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