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

Annotation of OpenXM_contrib2/asir2000/gc5.3/win32_threads.c, Revision 1.1

1.1     ! noro        1: #ifdef WIN32_THREADS
        !             2:
        !             3: #include "gc_priv.h"
        !             4:
        !             5: #if 0
        !             6: #define STRICT
        !             7: #include <windows.h>
        !             8: #endif
        !             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) {
        !            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:       }
        !            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:
        !            80: static ptr_t GC_get_lo_stack_addr(ptr_t s)
        !            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)
        !           100:        GC_push_all_stack(&i, thread_table[i].stack);
        !           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>