1 /*******************************************************************************
2 * The confidential and proprietary information contained in this file may      *
3 * only be used by a person authorised under and to the extent permitted        *
4 * by a subsisting licensing agreement from ARM Limited or its affiliates.      *
5 *   (C) COPYRIGHT [2001-2017] ARM Limited or its affiliates.                   *
6 *       ALL RIGHTS RESERVED                                                    *
7 * This entire notice must be reproduced on all copies of this file             *
8 * and copies of this file may only be made by a person if such person is       *
9 * permitted to do so under the terms of a subsisting license agreement         *
10 * from ARM Limited or its affiliates.                                          *
11 *******************************************************************************/
12 
13 #include <stdlib.h>
14 #include <stdio.h>
15 #include <stdbool.h>
16 #include <string.h>
17 #include <pthread.h>
18 #include <unistd.h>
19 
20 #include "test_pal_thread.h"
21 #include "test_pal_mem.h"
22 #include "test_pal_log.h"
23 
24 
25 struct ThreadStr {
26     pthread_t   threadId;   /* Thread ID */
27 
28     void        *(*threadFunc)(void *); /* thread function pointer */
29 
30     void        *arg;       /* Arguments received by thread
31                      * function. */
32 
33     void        *stackAddrToFree; /* Stack Address that needs to be
34                        * freed. If NULL, stack is not
35                        * dma-able and was allocated by
36                        * the OS. */
37 
38     uint8_t     isJoined;   /* Indicates whether pthread_join
39                      * was called or not. This function is
40                      * necessary for cleaning up any
41                      * resources associated with the thread.
42                      * Can be called only once. */
43 
44     uint8_t     isCompleted;    /* Indicates whether the thread finished
45                      * to run. */
46 };
47 
48 /* minimum stack size is 1MB */
49 #define LINUX_MINIMAL_STACK_SIZE_BYTES  0x100000
50 /* stack alignment to page size */
51 #define STACK_ALIGN         (sysconf(_SC_PAGESIZE))
52 
53 /******************************************************************************/
Test_PalThreadFunc(void * ctx)54 void *Test_PalThreadFunc(void *ctx)
55 {
56     struct ThreadStr *threadStr = ctx;
57     void *ret = NULL;
58 
59     /* The thread is cancelable */
60     if (pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL)) {
61         TEST_PRINTF_ERROR("pthread_setcancelstate failed\n");
62         goto exit;
63     }
64 
65     /* The thread can be cancelled at any time. */
66     if (pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL)) {
67         TEST_PRINTF_ERROR("pthread_setcanceltype failed\n");
68         goto exit;
69     }
70 
71     ret = threadStr->threadFunc(threadStr->arg);
72     threadStr->isCompleted = true;
73 
74 exit:
75     pthread_exit(ret);
76     /*Should not reach here. The line below prevents a compilation warning*/
77     return ret;
78 }
79 
80 /******************************************************************************/
Test_PalGetMinimalStackSize(void)81 size_t Test_PalGetMinimalStackSize(void)
82 {
83     return LINUX_MINIMAL_STACK_SIZE_BYTES;
84 }
85 
86 /******************************************************************************/
Test_PalGetHighestPriority(void)87 uint32_t Test_PalGetHighestPriority(void)
88 {
89     return 0;
90 }
91 
92 /******************************************************************************/
Test_PalGetLowestPriority(void)93 uint32_t Test_PalGetLowestPriority(void)
94 {
95     return 0;
96 }
97 
98 /******************************************************************************/
Test_PalGetDefaultPriority(void)99 uint32_t Test_PalGetDefaultPriority(void)
100 {
101     return 0;
102 }
103 
104 /******************************************************************************/
Test_PalThreadCreate(size_t stackSize,void * (* threadFunc)(void *),int priority,void * arg,const char * threadName,uint8_t nameLen,uint8_t dmaAble)105 ThreadHandle Test_PalThreadCreate(size_t stackSize,
106                   void *(*threadFunc)(void *),
107                   int priority, void *arg,
108                   const char *threadName,
109                   uint8_t nameLen, uint8_t dmaAble)
110 {
111     (void)threadName;
112     (void)nameLen;
113     (void)priority;
114     struct ThreadStr *threadStr = NULL;
115     void *stackAddr = NULL;
116     pthread_attr_t attr;
117 
118     /* Checks argument validity */
119     if (stackSize < LINUX_MINIMAL_STACK_SIZE_BYTES) {
120         TEST_PRINTF_ERROR("Stack size is too small. Changed to "
121                 "minimal stack size in bytes: 0x%08lx\n",
122                 LINUX_MINIMAL_STACK_SIZE_BYTES);
123         stackSize = LINUX_MINIMAL_STACK_SIZE_BYTES;
124     }
125 
126     /* Allocates ThreadStr */
127     threadStr = Test_PalMalloc(sizeof(struct ThreadStr));
128     if (threadStr == NULL) {
129         TEST_PRINTF_ERROR("threadStr allocation failed\n");
130         goto error;
131     }
132 
133     /* Initializes thread attribute */
134     if (pthread_attr_init(&attr) != 0) {
135         TEST_PRINTF_ERROR("pthread_attr_init failed\n");
136         goto error_freeStr;
137     }
138 
139     /* Initializes ThreadStr */
140     threadStr->threadFunc = threadFunc;
141     threadStr->arg = arg;
142     threadStr->stackAddrToFree = NULL;
143     threadStr->isJoined = false;
144     threadStr->isCompleted = false;
145 
146     /* Allocates thread stack */
147     if (dmaAble) {
148         /* Allocate the stack + extra for page alignment */
149         threadStr->stackAddrToFree = Test_PalDMAContigBufferAlloc(
150                 stackSize + LINUX_MINIMAL_STACK_SIZE_BYTES);
151         if (threadStr->stackAddrToFree == NULL) {
152             TEST_PRINTF_ERROR("thread stack allocation failed\n");
153             goto error_freeStr;
154         }
155         /* Align stack size to be multiple of page size. */
156         stackAddr = (void *)(threadStr->stackAddrToFree +
157                     STACK_ALIGN - 1);
158         stackAddr = (void *)((size_t)stackAddr & (-STACK_ALIGN));
159 
160         if (pthread_attr_setstack(&attr, stackAddr, stackSize) != 0) {
161             TEST_PRINTF_ERROR("pthread_attr_setstack failed\n");
162             goto error_freeAll;
163         }
164     }
165     else {
166         if (pthread_attr_setstacksize(&attr, stackSize) != 0) {
167             TEST_PRINTF_ERROR("pthread_attr_setstacksize failed\n");
168             goto error_freeStr;
169         }
170     }
171 
172     /* Creates thread */
173     if (pthread_create(&threadStr->threadId, &attr,
174                Test_PalThreadFunc, threadStr)) {
175         TEST_PRINTF_ERROR("pthread_create failed\n");
176         goto error_freeAll;
177     }
178 
179     /* Cannot free thread stack and context in case destroy attribute
180      * fails as the thread is already running */
181     if (pthread_attr_destroy(&attr))
182         TEST_PRINTF_ERROR("pthread_attr_destroy failed\n");
183 
184     return threadStr;
185 
186 error_freeAll:
187     if (dmaAble)
188         Test_PalDMAContigBufferFree(threadStr->stackAddrToFree);
189 error_freeStr:
190     Test_PalFree(threadStr);
191 error:
192     return NULL;
193 }
194 
195 /******************************************************************************/
Test_PalThreadJoin(ThreadHandle threadHandle,void ** threadRet)196 uint32_t Test_PalThreadJoin(ThreadHandle threadHandle, void **threadRet)
197 {
198     struct ThreadStr *threadStr = (struct ThreadStr *)threadHandle;
199 
200     /* Calling to pthread_join. threadRet is not changed. *threadRet is
201        Changed and can be set to NULL */
202     if (pthread_join(threadStr->threadId, threadRet)) {
203         TEST_PRINTF_ERROR("pthread_join failed\n");
204         return 1;
205     }
206 
207     threadStr->isJoined = true;
208     return 0;
209 }
210 
211 /******************************************************************************/
Test_PalThreadDestroy(ThreadHandle threadHandle)212 uint32_t Test_PalThreadDestroy(ThreadHandle threadHandle)
213 {
214     struct ThreadStr *threadStr = (struct ThreadStr *)threadHandle;
215 
216     if (threadStr->isCompleted == false) {
217         if (pthread_cancel(threadStr->threadId)) {
218             TEST_PRINTF_ERROR("pthread_cancel failed\n");
219             return 1;
220         }
221         threadStr->isCompleted = true;
222     }
223 
224     /* pthread_join is necessary for cleaning up any resources associated
225      * with the thread. Can be called only once */
226     if (threadStr->isJoined == false) {
227         /* Cannot return because thread is already cancelled.
228          * Must continue freeing resources */
229         if (pthread_join(threadStr->threadId, NULL)) {
230             TEST_PRINTF_ERROR("pthread_join failed\n");
231         }
232         threadStr->isJoined = true;
233     }
234 
235     /* Frees stack only in case its Dma-able */
236     if (threadStr->stackAddrToFree != NULL)
237         Test_PalDMAContigBufferFree(threadStr->stackAddrToFree);
238 
239     Test_PalFree(threadStr);
240     return 0;
241 }
242