|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 #include "cpr.h" |
|
6 #include "cpr_stdlib.h" |
|
7 #include "cpr_stdio.h" |
|
8 #include <pthread.h> |
|
9 #include <errno.h> |
|
10 #include <unistd.h> |
|
11 #include <sys/resource.h> |
|
12 #include "thread_monitor.h" |
|
13 #include "prtypes.h" |
|
14 #include "mozilla/Assertions.h" |
|
15 |
|
16 #define ANDROID_MIN_THREAD_PRIORITY (-20) /* tbd: check MV linux: current val from Larry port */ |
|
17 #define ANDROID_MAX_THREAD_PRIORITY (+19) /* tbd: check MV linux. current val from Larry port */ |
|
18 |
|
19 void CSFLogRegisterThread(const cprThread_t thread); |
|
20 |
|
21 /** |
|
22 * cprCreateThread |
|
23 * |
|
24 * @brief Create a thread |
|
25 * |
|
26 * The cprCreateThread function creates another execution thread within the |
|
27 * current process. If the input parameter "name" is present, then this is used |
|
28 * for debugging purposes. The startRoutine is the address of the function where |
|
29 * the thread execution begins. The start routine prototype is defined as |
|
30 * follows |
|
31 * @code |
|
32 * int32_t (*cprThreadStartRoutine)(void* data) |
|
33 * @endcode |
|
34 * |
|
35 * @param[in] name - name of the thread created (optional) |
|
36 * @param[in] startRoutine - function where thread execution begins |
|
37 * @param[in] stackSize - size of the thread's stack |
|
38 * @param[in] priority - thread's execution priority |
|
39 * @param[in] data - parameter to pass to startRoutine |
|
40 * |
|
41 * Return Value: Thread handle or NULL if creation failed. |
|
42 */ |
|
43 cprThread_t |
|
44 cprCreateThread (const char *name, |
|
45 cprThreadStartRoutine startRoutine, |
|
46 uint16_t stackSize, |
|
47 uint16_t priority, |
|
48 void *data) |
|
49 { |
|
50 static const char fname[] = "cprCreateThread"; |
|
51 static uint16_t id = 0; |
|
52 cpr_thread_t *threadPtr; |
|
53 pthread_t threadId; |
|
54 pthread_attr_t attr; |
|
55 |
|
56 CPR_INFO("%s: creating '%s' thread\n", fname, name); |
|
57 |
|
58 /* Malloc memory for a new thread */ |
|
59 threadPtr = (cpr_thread_t *)cpr_malloc(sizeof(cpr_thread_t)); |
|
60 if (threadPtr != NULL) { |
|
61 if (pthread_attr_init(&attr) != 0) { |
|
62 |
|
63 CPR_ERROR("%s - Failed to init attribute for thread %s\n", |
|
64 fname, name); |
|
65 cpr_free(threadPtr); |
|
66 return (cprThread_t)NULL; |
|
67 } |
|
68 |
|
69 if (pthread_attr_setstacksize(&attr, stackSize) != 0) { |
|
70 CPR_ERROR("%s - Invalid stacksize %d specified for thread %s\n", |
|
71 fname, stackSize, name); |
|
72 cpr_free(threadPtr); |
|
73 return (cprThread_t)NULL; |
|
74 } |
|
75 |
|
76 if (pthread_create(&threadId, &attr, startRoutine, data) != 0) { |
|
77 CPR_ERROR("%s - Creation of thread %s failed: %d\n", |
|
78 fname, name, errno); |
|
79 cpr_free(threadPtr); |
|
80 return (cprThread_t)NULL; |
|
81 } |
|
82 |
|
83 /* Assign name to CPR if one was passed in */ |
|
84 if (name != NULL) { |
|
85 threadPtr->name = name; |
|
86 } |
|
87 |
|
88 /* |
|
89 * TODO - It would be nice for CPR to keep a linked |
|
90 * list of running threads for debugging purposes |
|
91 * such as a show command or walking the list to ensure |
|
92 * that an application does not attempt to create |
|
93 * the same thread twice. |
|
94 */ |
|
95 threadPtr->u.handleInt = threadId; |
|
96 threadPtr->threadId = ++id; |
|
97 CSFLogRegisterThread(threadPtr); |
|
98 return (cprThread_t)threadPtr; |
|
99 } |
|
100 |
|
101 /* Malloc failed */ |
|
102 CPR_ERROR("%s - Malloc for thread %s failed.\n", fname, name); |
|
103 errno = ENOMEM; |
|
104 return (cprThread_t)NULL; |
|
105 } |
|
106 |
|
107 /* |
|
108 * cprJoinThread |
|
109 * |
|
110 * wait for thread termination |
|
111 */ |
|
112 void cprJoinThread(cprThread_t thread) |
|
113 { |
|
114 cpr_thread_t *cprThreadPtr; |
|
115 |
|
116 cprThreadPtr = (cpr_thread_t *) thread; |
|
117 MOZ_ASSERT(cprThreadPtr); |
|
118 pthread_join(cprThreadPtr->u.handleInt, NULL); |
|
119 } |
|
120 |
|
121 /** |
|
122 * cprDestroyThread |
|
123 * |
|
124 * @brief Destroys the thread passed in. |
|
125 * |
|
126 * The cprDestroyThread function is called to destroy a thread. The thread |
|
127 * parameter may be any valid thread including the calling thread itself. |
|
128 * |
|
129 * @param[in] thread - thread to destroy. |
|
130 * |
|
131 * @return CPR_SUCCESS or CPR_FAILURE. errno should be set for FAILURE case. |
|
132 * |
|
133 * @note In Linux there will never be a success indication as the |
|
134 * calling thread will have been terminated. |
|
135 */ |
|
136 cprRC_t |
|
137 cprDestroyThread (cprThread_t thread) |
|
138 { |
|
139 cpr_thread_t *cprThreadPtr; |
|
140 |
|
141 cprThreadPtr = (cpr_thread_t *) thread; |
|
142 if (cprThreadPtr) { |
|
143 /* |
|
144 * Make sure thread is trying to destroy itself. |
|
145 */ |
|
146 if ((pthread_t) cprThreadPtr->u.handleInt == pthread_self()) { |
|
147 CPR_INFO("%s: Destroying Thread %d", __FUNCTION__, cprThreadPtr->threadId); |
|
148 pthread_exit(NULL); |
|
149 return CPR_SUCCESS; |
|
150 } |
|
151 |
|
152 CPR_ERROR("%s: Thread attempted to destroy another thread, not itself.", |
|
153 __FUNCTION__); |
|
154 MOZ_ASSERT(PR_FALSE); |
|
155 errno = EINVAL; |
|
156 return CPR_FAILURE; |
|
157 } |
|
158 |
|
159 CPR_ERROR("%s - NULL pointer passed in.", __FUNCTION__); |
|
160 MOZ_ASSERT(PR_FALSE); |
|
161 errno = EINVAL; |
|
162 return CPR_FAILURE; |
|
163 } |
|
164 |
|
165 /** |
|
166 * cprAdjustRelativeThreadPriority |
|
167 * |
|
168 * @brief The function sets the relative thread priority up or down by the given value. |
|
169 * |
|
170 * This function is used pSIPCC to set up the thread priority. The values of the |
|
171 * priority range from -20 (Maximum priority) to +19 (Minimum priority). |
|
172 * |
|
173 * @param[in] relPri - nice value of the thread -20 is MAX and 19 is MIN |
|
174 * |
|
175 * @return CPR_SUCCESS or CPR_FAILURE |
|
176 */ |
|
177 cprRC_t |
|
178 cprAdjustRelativeThreadPriority (int relPri) |
|
179 { |
|
180 const char *fname = "cprAdjustRelativeThreadPriority"; |
|
181 |
|
182 if (setpriority(PRIO_PROCESS, 0, relPri) == -1) { |
|
183 CPR_ERROR("%s: could not set the nice..err=%d\n", |
|
184 fname, errno); |
|
185 return CPR_FAILURE; |
|
186 } |
|
187 return CPR_SUCCESS; |
|
188 } |
|
189 |
|
190 /** |
|
191 * @} |
|
192 * @addtogroup ThreadInternal Helper functions for implementing threads in CPR |
|
193 * @ingroup Threads |
|
194 * @brief Helper functions used by CPR for thread implementation |
|
195 * |
|
196 * @{ |
|
197 */ |
|
198 |
|
199 /** |
|
200 * cprGetThreadId |
|
201 * |
|
202 * @brief Return the pthread ID for the given CPR thread. |
|
203 * |
|
204 * @param[in] thread - thread to query |
|
205 * |
|
206 * @return Thread's Id or zero(0) |
|
207 * |
|
208 */ |
|
209 pthread_t |
|
210 cprGetThreadId (cprThread_t thread) |
|
211 { |
|
212 if (thread) { |
|
213 return ((cpr_thread_t *)thread)->u.handleInt; |
|
214 } |
|
215 return 0; |
|
216 } |
|
217 /** |
|
218 * @} |
|
219 */ |