Changeset 1400
- Timestamp:
- Apr 29, 2004, 5:35:22 AM (21 years ago)
- Location:
- trunk/src/emx
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
TabularUnified trunk/src/emx/include/InnoTekLIBC/thread.h ¶
-
Property cvs2svn:cvs-rev
changed from
1.2
to1.3
r1399 r1400 141 141 142 142 143 /** 144 * Thread Termination Callback Registration Record. (cool name, right) 145 * For use with __libc_ThreadRegisterTermCallback(). 146 */ 147 typedef struct __libc_ThreadTermCbRegRec 148 { 149 /** This member must be initialized to NULL. */ 150 struct __libc_ThreadTermCbRegRec *pNext; 151 /** Flags field reserved for future use. 152 * Must be initalized to ZERO. */ 153 unsigned fFlags; 154 /** 155 * The callback function. 156 * 157 * @param pRegRec Registration record which the callback was registered with. 158 * @param fFlags Reserved for future use. Will always be zero when fFlags 159 * in the RegRec is zero. 160 */ 161 void (*pfnCallback)(struct __libc_ThreadTermCbRegRec *pRegRec, unsigned fFlags); 162 } __LIBC_THREADTERMCBREGREC, *__LIBC_PTHREADTERMCBREGREC; 163 164 143 165 /******************************************************************************* 144 166 * Global Variables * … … 223 245 224 246 247 /** 248 * Register a thread destruction callback. 249 * 250 * This will be called when one thread is terminating normally, i.e. calling 251 * _endthread() or returning from it's thread function. 252 * When LIBC implements pthreads basics any new non-abnormal thread exit will 253 * cause a callback too. 254 * 255 * @param pRegRec Pointer to thread registration record. 256 * This must be initialized as described in the documation of 257 * the structure. After calling this API the memory must not 258 * be touched or freed by the application. It is not possible 259 * to unregister a callback at present. 260 * 261 * @remark We might wanna extend the API at a later point for calling back 262 * at abnormal termination and such. Such extensions will be done 263 * using the fFlags member of __LIBC_THREADTERMCBREGREC and the fFlags 264 * parameter to the callback. 265 */ 266 int __libc_ThreadRegisterTermCallback(__LIBC_PTHREADTERMCBREGREC pRegRec); 267 268 /** 269 * Internal API which is called by a thread exit to work the registered callbacks. 270 * 271 * Not called for thread 1. 272 * 273 * @param fFlags Reserved for termination reasons. 274 * Zero means normal exit, no other codes have been defined. 275 */ 276 void __libc_threadTermination(unsigned fFlags); 277 278 225 279 /** @group InnoTek LIBC Thread Local Storage 226 280 * @{ … … 263 317 int __libc_TLSSet(int iIndex, void *pvValue); 264 318 319 /** 320 * Register a thread termination destructor for an TLS entry. 321 * 322 * The destructor function will be called when a thread terminates 323 * in a normal fashion and the TLS entry iTLSIndex of that thread is 324 * not NULL. 325 * 326 * There will be no callbacks in thread 1. 327 * 328 * @returns 0 on succces. 329 * @returns -1 on failure. errno set. 330 * @param iTLSIndex Value returned by __libc_TLSAlloc(). 331 * @param pfnDestructor Callback function. Use NULL to unregister a previously 332 * registered destructor. 333 * 334 * It's pvValue argument is the non-zero value in the 335 * TLS entry for the thread it's called on. 336 * 337 * It's fFlags argument is reserved for future use, it will 338 * always be zero when the fFlags parameter to this API is zero. 339 * 340 * @param fFlags Flags reserved for future use. At the moment 341 * only ZERO is allowed. 342 * 343 * @remark The application is not allowed to call __libc_TLSFree() for iIndex when calling 344 * this function. The result from doing that is undefined. 345 */ 346 int __libc_TLSDestructor(int iIndex, void (*pfnDestructor)(void *pvValue, unsigned fFlags), unsigned fFlags); 347 265 348 /** @} */ 349 266 350 __END_DECLS 267 351 -
Property cvs2svn:cvs-rev
changed from
-
TabularUnified trunk/src/emx/src/lib/libc.def ¶
-
Property cvs2svn:cvs-rev
changed from
1.54
to1.55
r1399 r1400 1095 1095 "_catopen" @1117 1096 1096 "___libc_PathRewrite" @1118 1097 "___libc_TLSDestructor" @1119 1098 "___libc_ThreadRegisterTermCallback" @1120 -
Property cvs2svn:cvs-rev
changed from
-
TabularUnified trunk/src/emx/src/lib/process/beginthr.c ¶
-
Property cvs2svn:cvs-rev
changed from
1.8
to1.9
r1399 r1400 33 33 LIBCLOG_MSG("thread function returned\n"); 34 34 35 FS_SAVE_LOAD();35 __libc_threadTermination(0); 36 36 tid = _gettid(); 37 37 __libc_threadFree(pThrd); 38 38 __libc_Back_threadEnd(®); 39 FS_SAVE_LOAD(); 39 40 LIBCLOG_MSG("calling DosExit(%s, 0)\n", tid == 1 ? "EXIT_PROCESS" : "EXIT_THREAD"); 40 41 for (;;) … … 98 99 FS_VAR(); 99 100 100 FS_SAVE_LOAD();101 __libc_threadTermination(0); 101 102 tid = _gettid(); 102 103 __libc_threadFree(pThrd); 104 FS_SAVE_LOAD(); 103 105 LIBCLOG_MSG("calling DosExit(%s, 0)\n", tid == 1 ? "EXIT_PROCESS" : "EXIT_THREAD"); 104 106 for (;;) -
Property cvs2svn:cvs-rev
changed from
-
TabularUnified trunk/src/emx/src/lib/process/thread_internals.c ¶
-
Property cvs2svn:cvs-rev
changed from
1.2
to1.3
r1399 r1400 30 30 #include "libc-alias.h" 31 31 #undef NDEBUG 32 #include <386/builtin.h> 32 33 #include <assert.h> 33 34 #include <string.h> 35 #include <errno.h> 36 #include <sys/smutex.h> 34 37 #include <emx/umalloc.h> 35 38 #include <emx/syscalls.h> … … 47 50 /** Flags whether or not gPreAllocThrd is used. */ 48 51 static int gfPreAllocThrd; 52 53 /** Head of the thread termination callback list. */ 54 static __LIBC_PTHREADTERMCBREGREC gpTermHead; 55 /** Tail of the thread termination callback list. */ 56 static __LIBC_PTHREADTERMCBREGREC gpTermTail; 57 /** List protection semaphore (spinlock sort). */ 58 static _smutex gsmtxTerm; 59 49 60 50 61 … … 109 120 void __libc_threadFree(__LIBC_PTHREAD pThrd) 110 121 { 111 LIBCLOG_ENTER("pThrd=%p\n", pThrd);122 LIBCLOG_ENTER("pThrd=%p\n", (void *)pThrd); 112 123 /* 113 124 * Clean up members. … … 125 136 } 126 137 138 139 int __libc_ThreadRegisterTermCallback(__LIBC_PTHREADTERMCBREGREC pRegRec) 140 { 141 LIBCLOG_ENTER("pRegRec=%p {%p, %u, %p}\n", (void *)pRegRec, 142 pRegRec ? (void *)pRegRec->pNext : NULL, 143 pRegRec ? pRegRec->fFlags : 0, 144 pRegRec ? (void *)pRegRec->pfnCallback : NULL); 145 146 /* 147 * Validate input. 148 */ 149 if ( pRegRec->pNext 150 || !pRegRec->pfnCallback 151 || pRegRec->fFlags) 152 { 153 LIBC_ASSERTM(!pRegRec->pNext, "pNext must be NULL not %p\n", pRegRec->pNext); 154 LIBC_ASSERTM(pRegRec->pfnCallback, "pfnCallback not be NULL\n"); 155 LIBC_ASSERTM(!pRegRec->fFlags, "fFlags must be ZERO not %u\n", pRegRec->fFlags); 156 errno = EINVAL; 157 LIBCLOG_RETURN_INT(-1); 158 } 159 160 /* 161 * Insert into the LIFO. 162 */ 163 _smutex_request(&gsmtxTerm); 164 if ( !pRegRec->pNext 165 && pRegRec != gpTermTail) 166 { 167 pRegRec->pNext = gpTermTail; 168 gpTermTail = pRegRec; 169 if (!gpTermHead) 170 gpTermHead = pRegRec; 171 _smutex_release(&gsmtxTerm); 172 LIBCLOG_RETURN_INT(0); 173 } 174 else 175 { 176 _smutex_release(&gsmtxTerm); 177 LIBC_ASSERTM_FAILED("Double registration of %p\n", pRegRec); 178 LIBCLOG_RETURN_INT(-1); 179 } 180 } 181 182 183 void __libc_threadTermination(unsigned fFlags) 184 { 185 LIBCLOG_ENTER("fFlags=%u\n", fFlags); 186 __LIBC_PTHREADTERMCBREGREC pCur; 187 __LIBC_PTHREADTERMCBREGREC pTail; 188 189 /* 190 * We'll need to do this in a safe manner. 191 * 192 * ASSUME no removal of records. 193 * Thus we just pick the head and tail record and walk them. 194 */ 195 _smutex_request(&gsmtxTerm); 196 pTail = gpTermTail; 197 pCur = gpTermHead; 198 _smutex_release(&gsmtxTerm); 199 200 while (pCur) 201 { 202 /* call it */ 203 LIBCLOG_MSG("calling %p with %p\n", pCur->pfnCallback, pCur); 204 pCur->pfnCallback(pCur, fFlags); 205 206 /* next */ 207 if (pCur == pTail) 208 break; 209 pCur = pCur->pNext; 210 } 211 212 LIBCLOG_RETURN_VOID(); 213 } -
Property cvs2svn:cvs-rev
changed from
-
TabularUnified trunk/src/emx/src/lib/process/tls.c ¶
-
Property cvs2svn:cvs-rev
changed from
1.2
to1.3
r1399 r1400 31 31 #include <errno.h> 32 32 #include <sys/limits.h> 33 #include <sys/smutex.h> 33 34 #include <InnoTekLIBC/thread.h> 34 35 #define __LIBC_LOG_GROUP __LIBC_LOG_GRP_THREAD … … 50 51 #endif 51 52 53 /******************************************************************************* 54 * Internal Functions * 55 *******************************************************************************/ 56 static void __libc_tlsThreadDestructor(__LIBC_PTHREADTERMCBREGREC pRegRec, unsigned fFlags); 57 52 58 53 59 /******************************************************************************* 54 60 * Global Variables * 55 61 *******************************************************************************/ 62 /** Number of allocated TLS items. 63 * Updated atomically. Update before allocation and after free. */ 64 static unsigned gcTLSAllocated; 65 56 66 /** TLS allocation bitmap map. 57 67 * Set means allocated, clear means free. Updated atomically. */ 58 static unsigned auBitmap[(__LIBC_TLS_MAX + ENTRY_BITS - 1) / ENTRY_BITS]; 59 60 /** Number of allocated TLS items. 61 * Updated atomically. Update before allocation and after free. */ 62 static unsigned cTLSAllocated; 68 static unsigned gauBitmap[(__LIBC_TLS_MAX + ENTRY_BITS - 1) / ENTRY_BITS]; 69 70 /** TLS Per Thread Destructors. */ 71 static void (*gapfnDestructors[__LIBC_TLS_MAX])(void *, unsigned); 72 73 /** Thread Termination Registration Record. */ 74 static __LIBC_THREADTERMCBREGREC gThrdTermRegRec = 75 { 76 NULL, 0, __libc_tlsThreadDestructor 77 }; 63 78 64 79 … … 71 86 * Space left? 72 87 */ 73 if (__atomic_increment_max(& cTLSAllocated, __LIBC_TLS_MAX))74 { 75 LIBC_ASSERTM_FAILED("Out of TLS entries! cur=%d max=%d\n", cTLSAllocated, __LIBC_TLS_MAX);88 if (__atomic_increment_max(&gcTLSAllocated, __LIBC_TLS_MAX)) 89 { 90 LIBC_ASSERTM_FAILED("Out of TLS entries! cur=%d max=%d\n", gcTLSAllocated, __LIBC_TLS_MAX); 76 91 LIBCLOG_RETURN_INT(-1); 77 92 } … … 86 101 * Scan the bitmap int by int. 87 102 */ 88 unsigned *pu = & auBitmap[0];89 while (pu < & auBitmap[sizeof(auBitmap) / sizeof(auBitmap[0])])103 unsigned *pu = &gauBitmap[0]; 104 while (pu < &gauBitmap[sizeof(gauBitmap) / sizeof(gauBitmap[0])]) 90 105 { 91 106 if (*pu != ~0) … … 101 116 if (!__atomic_set_bit(pu, uBit)) 102 117 { 103 int iBitRet = (pu - & auBitmap[0]) * ENTRY_BITS + uBit;118 int iBitRet = (pu - &gauBitmap[0]) * ENTRY_BITS + uBit; 104 119 if (iBitRet < __LIBC_TLS_MAX) 120 { 121 gapfnDestructors[iIndex] = NULL; 105 122 LIBCLOG_RETURN_INT(iBitRet); 123 } 106 124 } 107 125 } … … 114 132 } 115 133 116 LIBC_ASSERTM_FAILED("We're giving up finding a free enter!!! cur=%d max=%d\n", cTLSAllocated, __LIBC_TLS_MAX);134 LIBC_ASSERTM_FAILED("We're giving up finding a free enter!!! cur=%d max=%d\n", gcTLSAllocated, __LIBC_TLS_MAX); 117 135 LIBCLOG_RETURN_INT(-1); 118 136 } … … 127 145 if ( iIndex < 0 128 146 || iIndex >= __LIBC_TLS_MAX 129 || !__atomic_test_bit(& auBitmap[0], iIndex)147 || !__atomic_test_bit(&gauBitmap[0], iIndex) 130 148 ) 131 149 { … … 138 156 * Clear the bitmap bit. 139 157 */ 140 __atomic_clear_bit(&auBitmap[0], iIndex); 158 gapfnDestructors[iIndex] = NULL; 159 __atomic_clear_bit(&gauBitmap[0], iIndex); 141 160 142 161 /* 143 162 * Decrement the allocation count. 144 163 */ 145 LIBC_ASSERT( cTLSAllocated > 0);146 __atomic_decrement(& cTLSAllocated);164 LIBC_ASSERT(gcTLSAllocated > 0); 165 __atomic_decrement(&gcTLSAllocated); 147 166 LIBCLOG_RETURN_INT(0); 148 167 } … … 157 176 if ( iIndex < 0 158 177 || iIndex >= __LIBC_TLS_MAX 159 || !__atomic_test_bit(& auBitmap[0], iIndex)178 || !__atomic_test_bit(&gauBitmap[0], iIndex) 160 179 ) 161 180 { … … 180 199 if ( iIndex < 0 181 200 || iIndex >= __LIBC_TLS_MAX 182 || !__atomic_test_bit(& auBitmap[0], iIndex)201 || !__atomic_test_bit(&gauBitmap[0], iIndex) 183 202 ) 184 203 { … … 195 214 } 196 215 216 217 218 int __libc_TLSDestructor(int iIndex, void (*pfnDestructor)(void *pvValue, unsigned fFlags), unsigned fFlags) 219 { 220 LIBCLOG_ENTER("iIndex=%d pfnDestructor=%p\n", iIndex, pfnDestructor); 221 static _smutex smtxInit; 222 static volatile int fInited; 223 224 /* 225 * Validate index 226 */ 227 if ( iIndex < 0 228 || iIndex >= __LIBC_TLS_MAX 229 || !__atomic_test_bit(&gauBitmap[0], iIndex) 230 ) 231 { 232 LIBC_ASSERTM_FAILED("Bad index %d. (max=%d)\n", iIndex, __LIBC_TLS_MAX); 233 errno = EINVAL; 234 LIBCLOG_RETURN_INT(-1); 235 } 236 if (fFlags) 237 { 238 LIBC_ASSERTM_FAILED("fFlags must be zero not %x!\n", fFlags); 239 errno = EINVAL; 240 LIBCLOG_RETURN_INT(-1); 241 } 242 243 /* 244 * Init the destructor if needed. 245 */ 246 if (!fInited) 247 { 248 _smutex_request(&smtxInit); 249 if (!fInited) 250 { 251 __libc_ThreadRegisterTermCallback(&gThrdTermRegRec); 252 fInited = 1; 253 } 254 _smutex_release(&smtxInit); 255 } 256 257 /* 258 * Update destructor index. 259 */ 260 LIBCLOG_MSG("old=%p new=%p\n", gapfnDestructors[iIndex], pfnDestructor); 261 gapfnDestructors[iIndex] = pfnDestructor; 262 LIBCLOG_RETURN_INT(0); 263 } 264 265 266 /** 267 * Callback function for thread termination. 268 * See __LIBC_THREADTERMCBREGREC::pfnCallback for parameter details. 269 * 270 * This is registered by the first call to __libc_TLSDestructor() and will 271 * be called back on normal thread terminations. It's function is to iterate 272 * the registered TLS destructors and calling back the registered TLS 273 * destructors so they can perform proper per thread cleanups. 274 */ 275 static void __libc_tlsThreadDestructor(__LIBC_PTHREADTERMCBREGREC pRegRec, unsigned fFlags) 276 { 277 LIBCLOG_ENTER("pRegRec=%p, fFlags=%d\n", (void *)pRegRec, fFlags); 278 279 /* get thread structure. */ 280 __LIBC_PTHREAD pThrd = __libc_threadCurrentNoAuto(); 281 if (!pThrd) 282 LIBCLOG_RETURN_MSG_VOID("ret void (thread struct not initialized)\n"); 283 284 285 /* iterate it word by word. */ 286 int i; 287 unsigned *pu = (unsigned *)&gauBitmap[0]; 288 for (i = 0; i < sizeof(gauBitmap) / sizeof(unsigned); i++, pu++) 289 { 290 if (*pu) 291 { 292 /* iterate the word byte by byte. */ 293 int j; 294 unsigned char *puch = (unsigned char *)&gauBitmap[0]; 295 for (j = 0; j < sizeof(unsigned char); j++, puch++) 296 { 297 if (*puch) 298 { 299 /* iterate byte entry by entry. */ 300 int k = i * sizeof(unsigned) * 8 + j * 8; 301 int kEnd = k + 8; 302 while (k < kEnd) 303 { 304 void (*pfnDestructor)(void *, unsigned); 305 if ( __atomic_test_bit(&gauBitmap[0], k) 306 && k < __LIBC_TLS_MAX 307 && pThrd->apvTLS[k] 308 && (pfnDestructor = gapfnDestructors[k]) != NULL) 309 { 310 LIBCLOG_MSG("tls %d: calling %p with %p\n", k, (void *)pfnDestructor, pThrd->apvTLS[k]); 311 pfnDestructor(pThrd->apvTLS[k], fFlags); 312 } 313 314 /* next */ 315 k++; 316 } 317 } 318 } 319 } 320 } 321 LIBCLOG_RETURN_VOID(); 322 } -
Property cvs2svn:cvs-rev
changed from
Note:
See TracChangeset
for help on using the changeset viewer.