[BACK]Return to win32_threads.c CVS log [TXT][DIR] Up to [local] / OpenXM_contrib2 / asir2000 / gc

Annotation of OpenXM_contrib2/asir2000/gc/win32_threads.c, Revision 1.2

1.1       noro        1: #ifdef WIN32_THREADS
                      2:
                      3: #include "gc_priv.h"
                      4:
1.2     ! noro        5: #if 0
1.1       noro        6: #define STRICT
                      7: #include <windows.h>
1.2     ! noro        8: #endif
1.1       noro        9:
                     10: #define MAX_THREADS 64
                     11:
                     12: struct thread_entry {
                     13:   LONG in_use;
                     14:   DWORD id;
                     15:   HANDLE handle;
                     16:   void *stack;         /* The cold end of the stack.   */
                     17:                        /* 0 ==> entry not valid.       */
                     18:                        /* !in_use ==> stack == 0       */
                     19:   CONTEXT context;
                     20:   GC_bool suspended;
                     21: };
                     22:
                     23: volatile GC_bool GC_please_stop = FALSE;
                     24:
                     25: volatile struct thread_entry thread_table[MAX_THREADS];
                     26:
                     27: void GC_stop_world()
                     28: {
                     29:   DWORD thread_id = GetCurrentThreadId();
                     30:   int i;
                     31:
                     32:   GC_please_stop = TRUE;
                     33:   for (i = 0; i < MAX_THREADS; i++)
                     34:     if (thread_table[i].stack != 0
                     35:        && thread_table[i].id != thread_id) {
1.2     ! noro       36:       /* Apparently the Windows 95 GetOpenFileName call creates        */
        !            37:       /* a thread that does not properly get cleaned up, and           */
        !            38:       /* SuspendThread on its descriptor may provoke a crash.          */
        !            39:       /* This reduces the probability of that event, though it still   */
        !            40:       /* appears there's a race here.                                  */
        !            41:       DWORD exitCode;
        !            42:       if (GetExitCodeThread(thread_table[i].handle,&exitCode) &&
        !            43:             exitCode != STILL_ACTIVE) {
        !            44:             thread_table[i].stack = 0;
        !            45:           thread_table[i].in_use = FALSE;
        !            46:           CloseHandle(thread_table[i].handle);
        !            47:           BZERO(&thread_table[i].context, sizeof(CONTEXT));
        !            48:           continue;
        !            49:       }
1.1       noro       50:       if (SuspendThread(thread_table[i].handle) == (DWORD)-1)
                     51:        ABORT("SuspendThread failed");
                     52:       thread_table[i].suspended = TRUE;
                     53:     }
                     54: }
                     55:
                     56: void GC_start_world()
                     57: {
                     58:   DWORD thread_id = GetCurrentThreadId();
                     59:   int i;
                     60:   for (i = 0; i < MAX_THREADS; i++)
                     61:     if (thread_table[i].stack != 0 && thread_table[i].suspended
                     62:        && thread_table[i].id != thread_id) {
                     63:       if (ResumeThread(thread_table[i].handle) == (DWORD)-1)
                     64:        ABORT("ResumeThread failed");
                     65:       thread_table[i].suspended = FALSE;
                     66:     }
                     67:   GC_please_stop = FALSE;
                     68: }
                     69:
                     70: ptr_t GC_current_stackbottom()
                     71: {
                     72:   DWORD thread_id = GetCurrentThreadId();
                     73:   int i;
                     74:   for (i = 0; i < MAX_THREADS; i++)
                     75:     if (thread_table[i].stack && thread_table[i].id == thread_id)
                     76:       return thread_table[i].stack;
                     77:   ABORT("no thread table entry for current thread");
                     78: }
                     79:
1.2     ! noro       80: static ptr_t GC_get_lo_stack_addr(ptr_t s)
1.1       noro       81: {
                     82:     ptr_t bottom;
                     83:     MEMORY_BASIC_INFORMATION info;
                     84:     VirtualQuery(s, &info, sizeof(info));
                     85:     do {
                     86:        bottom = info.BaseAddress;
                     87:        VirtualQuery(bottom - 1, &info, sizeof(info));
                     88:     } while ((info.Protect & PAGE_READWRITE) && !(info.Protect & PAGE_GUARD));
                     89:     return(bottom);
                     90: }
                     91:
                     92: void GC_push_all_stacks()
                     93: {
                     94:   DWORD thread_id = GetCurrentThreadId();
                     95:   int i;
                     96:   for (i = 0; i < MAX_THREADS; i++)
                     97:     if (thread_table[i].stack) {
                     98:       ptr_t bottom = GC_get_lo_stack_addr(thread_table[i].stack);
                     99:       if (thread_table[i].id == thread_id)
1.2     ! noro      100:        GC_push_all_stack(&i, thread_table[i].stack);
1.1       noro      101:       else {
                    102:        thread_table[i].context.ContextFlags
                    103:                        = (CONTEXT_INTEGER|CONTEXT_CONTROL);
                    104:        if (!GetThreadContext(thread_table[i].handle,
                    105:                              &thread_table[i].context))
                    106:          ABORT("GetThreadContext failed");
                    107:        if (thread_table[i].context.Esp >= (DWORD)thread_table[i].stack
                    108:            || thread_table[i].context.Esp < (DWORD)bottom)
                    109:            ABORT("Thread stack pointer out of range");
                    110:        GC_push_one ((word) thread_table[i].context.Edi);
                    111:        GC_push_one ((word) thread_table[i].context.Esi);
                    112:        GC_push_one ((word) thread_table[i].context.Ebx);
                    113:        GC_push_one ((word) thread_table[i].context.Edx);
                    114:        GC_push_one ((word) thread_table[i].context.Ecx);
                    115:        GC_push_one ((word) thread_table[i].context.Eax);
                    116:        GC_push_all_stack(thread_table[i].context.Esp, thread_table[i].stack);
                    117:       }
                    118:     }
                    119: }
                    120:
                    121: void GC_get_next_stack(char *start, char **lo, char **hi)
                    122: {
                    123:     int i;
                    124: #   define ADDR_LIMIT (char *)(-1L)
                    125:     char * current_min = ADDR_LIMIT;
                    126:
                    127:     for (i = 0; i < MAX_THREADS; i++) {
                    128:        char * s = (char *)thread_table[i].stack;
                    129:
                    130:        if (0 != s && s > start && s < current_min) {
                    131:            current_min = s;
                    132:        }
                    133:     }
                    134:     *hi = current_min;
                    135:     if (current_min == ADDR_LIMIT) {
                    136:        *lo = ADDR_LIMIT;
                    137:        return;
                    138:     }
                    139:     *lo = GC_get_lo_stack_addr(current_min);
                    140:     if (*lo < start) *lo = start;
                    141: }
                    142:
                    143: LONG WINAPI GC_write_fault_handler(struct _EXCEPTION_POINTERS *exc_info);
                    144:
                    145: /*
                    146:  * This isn't generally safe, since DllMain is not premptible.
                    147:  * If another thread holds the lock while this runs we're in trouble.
                    148:  * Pontus Rydin suggests wrapping the thread start routine instead.
                    149:  */
                    150: BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVOID reserved)
                    151: {
                    152:   switch (reason) {
                    153:   case DLL_PROCESS_ATTACH:
                    154:     InitializeCriticalSection(&GC_allocate_ml);
                    155:     GC_init(); /* Force initialization before thread attach.   */
                    156:     /* fall through */
                    157:   case DLL_THREAD_ATTACH:
                    158:     {
                    159:       int i;
                    160:       /* It appears to be unsafe to acquire a lock here, since this    */
                    161:       /* code is apparently not preeemptible on some systems.          */
                    162:       /* (This is based on complaints, not on Microsoft's official     */
                    163:       /* documentation, which says this should perform "only simple    */
                    164:       /* inititalization tasks".)                                      */
                    165:       /* Hence we make do with nonblocking synchronization.            */
                    166:
                    167:       /* The following should be a noop according to the win32 */
                    168:       /* documentation.  There is empirical evidence that it   */
                    169:       /* isn't.                - HB                                    */
                    170: #     ifndef SMALL_CONFIG
                    171:        if (GC_incremental) SetUnhandledExceptionFilter(GC_write_fault_handler);
                    172: #     endif
                    173:
                    174:       for (i = 0; InterlockedExchange(&thread_table[i].in_use,1) != 0; i++) {
                    175:        /* Compare-and-swap would make this cleaner, but that's not     */
                    176:        /* supported before Windows 98 and NT 4.0.  In Windows 2000,    */
                    177:        /* InterlockedExchange is supposed to be replaced by            */
                    178:        /* InterlockedExchangePointer, but that's not really what I     */
                    179:        /* want here.                                                   */
                    180:        if (i == MAX_THREADS - 1)
                    181:          ABORT("too many threads");
                    182:       }
                    183:       thread_table[i].id = GetCurrentThreadId();
                    184:       if (!DuplicateHandle(GetCurrentProcess(),
                    185:                           GetCurrentThread(),
                    186:                           GetCurrentProcess(),
                    187:                           &thread_table[i].handle,
                    188:                           0,
                    189:                           0,
                    190:                           DUPLICATE_SAME_ACCESS)) {
                    191:            DWORD last_error = GetLastError();
                    192:            GC_printf1("Last error code: %lx\n", last_error);
                    193:            ABORT("DuplicateHandle failed");
                    194:       }
                    195:       thread_table[i].stack = GC_get_stack_base();
                    196:       /* If this thread is being created while we are trying to stop   */
                    197:       /* the world, wait here.  Hopefully this can't happen on any     */
                    198:       /* systems that don't allow us to block here.                    */
                    199:       while (GC_please_stop) Sleep(20);
                    200:     }
                    201:     break;
                    202:   case DLL_PROCESS_DETACH:
                    203:   case DLL_THREAD_DETACH:
                    204:     {
                    205:       int i;
                    206:       DWORD thread_id = GetCurrentThreadId();
                    207:       LOCK();
                    208:       for (i = 0;
                    209:            thread_table[i].stack == 0 || thread_table[i].id != thread_id;
                    210:           i++) {
                    211:        if (i == MAX_THREADS - 1)
                    212:          ABORT("thread not found on detach");
                    213:       }
                    214:       thread_table[i].stack = 0;
                    215:       thread_table[i].in_use = FALSE;
                    216:       CloseHandle(thread_table[i].handle);
                    217:       BZERO(&thread_table[i].context, sizeof(CONTEXT));
                    218:       UNLOCK();
                    219:     }
                    220:     break;
                    221:   }
                    222:   return TRUE;
                    223: }
                    224:
                    225: #endif /* WIN32_THREADS */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>