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

Annotation of OpenXM_contrib/gc/win32_threads.c, Revision 1.1.1.1

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

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