[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.3

1.3     ! noro        1: #if defined(GC_WIN32_THREADS) || defined(WIN32_THREADS)
1.1       noro        2:
1.3     ! noro        3: #include "private/gc_priv.h"
1.1       noro        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:
1.3     ! noro       27: void GC_push_thread_structures GC_PROTO((void))
        !            28: {
        !            29:     /* Unlike the other threads implementations, the thread table here */
        !            30:     /* contains no pointers to the collectable heap.  Thus we have     */
        !            31:     /* no private structures we need to preserve.                      */
        !            32: }
        !            33:
1.1       noro       34: void GC_stop_world()
                     35: {
                     36:   DWORD thread_id = GetCurrentThreadId();
                     37:   int i;
                     38:
                     39:   GC_please_stop = TRUE;
                     40:   for (i = 0; i < MAX_THREADS; i++)
                     41:     if (thread_table[i].stack != 0
                     42:        && thread_table[i].id != thread_id) {
1.3     ! noro       43: #     ifdef MSWINCE
        !            44:         /* SuspendThread will fail if thread is running kernel code */
        !            45:        while (SuspendThread(thread_table[i].handle) == (DWORD)-1)
        !            46:          Sleep(10);
        !            47: #     else
        !            48:        /* Apparently the Windows 95 GetOpenFileName call creates       */
        !            49:        /* a thread that does not properly get cleaned up, and          */
        !            50:        /* SuspendThread on its descriptor may provoke a crash.         */
        !            51:        /* This reduces the probability of that event, though it still  */
        !            52:        /* appears there's a race here.                                 */
        !            53:        DWORD exitCode;
        !            54:        if (GetExitCodeThread(thread_table[i].handle,&exitCode) &&
1.2       noro       55:             exitCode != STILL_ACTIVE) {
                     56:             thread_table[i].stack = 0;
1.3     ! noro       57:            thread_table[i].in_use = FALSE;
        !            58:            CloseHandle(thread_table[i].handle);
        !            59:            BZERO((void *)(&thread_table[i].context), sizeof(CONTEXT));
        !            60:            continue;
        !            61:        }
        !            62:        if (SuspendThread(thread_table[i].handle) == (DWORD)-1)
        !            63:          ABORT("SuspendThread failed");
        !            64: #     endif
1.1       noro       65:       thread_table[i].suspended = TRUE;
                     66:     }
                     67: }
                     68:
                     69: void GC_start_world()
                     70: {
                     71:   DWORD thread_id = GetCurrentThreadId();
                     72:   int i;
                     73:   for (i = 0; i < MAX_THREADS; i++)
                     74:     if (thread_table[i].stack != 0 && thread_table[i].suspended
                     75:        && thread_table[i].id != thread_id) {
                     76:       if (ResumeThread(thread_table[i].handle) == (DWORD)-1)
                     77:        ABORT("ResumeThread failed");
                     78:       thread_table[i].suspended = FALSE;
                     79:     }
                     80:   GC_please_stop = FALSE;
                     81: }
                     82:
1.3     ! noro       83: # ifdef _MSC_VER
        !            84: #   pragma warning(disable:4715)
        !            85: # endif
1.1       noro       86: ptr_t GC_current_stackbottom()
                     87: {
                     88:   DWORD thread_id = GetCurrentThreadId();
                     89:   int i;
                     90:   for (i = 0; i < MAX_THREADS; i++)
                     91:     if (thread_table[i].stack && thread_table[i].id == thread_id)
                     92:       return thread_table[i].stack;
                     93:   ABORT("no thread table entry for current thread");
                     94: }
1.3     ! noro       95: # ifdef _MSC_VER
        !            96: #   pragma warning(default:4715)
        !            97: # endif
        !            98:
        !            99: # ifdef MSWINCE
        !           100:     /* The VirtualQuery calls below won't work properly on WinCE, but  */
        !           101:     /* since each stack is restricted to an aligned 64K region of      */
        !           102:     /* virtual memory we can just take the next lowest multiple of 64K.        */
        !           103: #   define GC_get_lo_stack_addr(s) \
        !           104:         ((ptr_t)(((DWORD)(s) - 1) & 0xFFFF0000))
        !           105: # else
        !           106:     static ptr_t GC_get_lo_stack_addr(ptr_t s)
        !           107:     {
        !           108:        ptr_t bottom;
        !           109:        MEMORY_BASIC_INFORMATION info;
        !           110:        VirtualQuery(s, &info, sizeof(info));
        !           111:        do {
        !           112:            bottom = info.BaseAddress;
        !           113:            VirtualQuery(bottom - 1, &info, sizeof(info));
        !           114:        } while ((info.Protect & PAGE_READWRITE)
        !           115:                 && !(info.Protect & PAGE_GUARD));
        !           116:        return(bottom);
        !           117:     }
        !           118: # endif
1.1       noro      119:
                    120: void GC_push_all_stacks()
                    121: {
                    122:   DWORD thread_id = GetCurrentThreadId();
                    123:   int i;
                    124:   for (i = 0; i < MAX_THREADS; i++)
                    125:     if (thread_table[i].stack) {
                    126:       ptr_t bottom = GC_get_lo_stack_addr(thread_table[i].stack);
                    127:       if (thread_table[i].id == thread_id)
1.3     ! noro      128:        GC_push_all_stack((ptr_t)&i, thread_table[i].stack);
1.1       noro      129:       else {
                    130:        thread_table[i].context.ContextFlags
                    131:                        = (CONTEXT_INTEGER|CONTEXT_CONTROL);
                    132:        if (!GetThreadContext(thread_table[i].handle,
1.3     ! noro      133:                                /* cast away volatile qualifier */
        !           134:                                (LPCONTEXT)&thread_table[i].context))
1.1       noro      135:          ABORT("GetThreadContext failed");
1.3     ! noro      136: #      ifdef I386
        !           137:          if (thread_table[i].context.Esp >= (DWORD)thread_table[i].stack
        !           138:              || thread_table[i].context.Esp < (DWORD)bottom)
        !           139:              ABORT("Thread stack pointer out of range");
        !           140:          GC_push_one ((word) thread_table[i].context.Edi);
        !           141:          GC_push_one ((word) thread_table[i].context.Esi);
        !           142:          GC_push_one ((word) thread_table[i].context.Ebp);
        !           143:          GC_push_one ((word) thread_table[i].context.Ebx);
        !           144:          GC_push_one ((word) thread_table[i].context.Edx);
        !           145:          GC_push_one ((word) thread_table[i].context.Ecx);
        !           146:          GC_push_one ((word) thread_table[i].context.Eax);
        !           147:          GC_push_all_stack((char *) thread_table[i].context.Esp,
        !           148:                            thread_table[i].stack);
        !           149: #       else
        !           150: #       ifdef ARM32
        !           151:          if (thread_table[i].context.Sp >= (DWORD)thread_table[i].stack
        !           152:              || thread_table[i].context.Sp < (DWORD)bottom)
        !           153:              ABORT("Thread stack pointer out of range");
        !           154:          GC_push_one ((word) thread_table[i].context.R0);
        !           155:          GC_push_one ((word) thread_table[i].context.R1);
        !           156:          GC_push_one ((word) thread_table[i].context.R2);
        !           157:          GC_push_one ((word) thread_table[i].context.R3);
        !           158:          GC_push_one ((word) thread_table[i].context.R4);
        !           159:          GC_push_one ((word) thread_table[i].context.R5);
        !           160:          GC_push_one ((word) thread_table[i].context.R6);
        !           161:          GC_push_one ((word) thread_table[i].context.R7);
        !           162:          GC_push_one ((word) thread_table[i].context.R8);
        !           163:          GC_push_one ((word) thread_table[i].context.R9);
        !           164:          GC_push_one ((word) thread_table[i].context.R10);
        !           165:          GC_push_one ((word) thread_table[i].context.R11);
        !           166:          GC_push_one ((word) thread_table[i].context.R12);
        !           167:          GC_push_all_stack((char *) thread_table[i].context.Sp,
        !           168:                            thread_table[i].stack);
        !           169: #       else
        !           170: #      ifdef SHx
        !           171:          if (thread_table[i].context.R15 >= (DWORD)thread_table[i].stack
        !           172:              || thread_table[i].context.R15 < (DWORD)bottom)
        !           173:              ABORT("Thread stack pointer out of range");
        !           174:          GC_push_one ((word) thread_table[i].context.R0);
        !           175:          GC_push_one ((word) thread_table[i].context.R1);
        !           176:          GC_push_one ((word) thread_table[i].context.R2);
        !           177:          GC_push_one ((word) thread_table[i].context.R3);
        !           178:          GC_push_one ((word) thread_table[i].context.R4);
        !           179:          GC_push_one ((word) thread_table[i].context.R5);
        !           180:          GC_push_one ((word) thread_table[i].context.R6);
        !           181:          GC_push_one ((word) thread_table[i].context.R7);
        !           182:          GC_push_one ((word) thread_table[i].context.R8);
        !           183:          GC_push_one ((word) thread_table[i].context.R9);
        !           184:          GC_push_one ((word) thread_table[i].context.R10);
        !           185:          GC_push_one ((word) thread_table[i].context.R11);
        !           186:          GC_push_one ((word) thread_table[i].context.R12);
        !           187:          GC_push_one ((word) thread_table[i].context.R13);
        !           188:          GC_push_one ((word) thread_table[i].context.R14);
        !           189:          GC_push_all_stack((char *) thread_table[i].context.R15,
        !           190:                            thread_table[i].stack);
        !           191: #       else
        !           192: #      ifdef MIPS
        !           193:          if (thread_table[i].context.IntSp >= (DWORD)thread_table[i].stack
        !           194:              || thread_table[i].context.IntSp < (DWORD)bottom)
        !           195:              ABORT("Thread stack pointer out of range");
        !           196:          GC_push_one ((word) thread_table[i].context.IntAt);
        !           197:          GC_push_one ((word) thread_table[i].context.IntV0);
        !           198:          GC_push_one ((word) thread_table[i].context.IntV1);
        !           199:          GC_push_one ((word) thread_table[i].context.IntA0);
        !           200:          GC_push_one ((word) thread_table[i].context.IntA1);
        !           201:          GC_push_one ((word) thread_table[i].context.IntA2);
        !           202:          GC_push_one ((word) thread_table[i].context.IntA3);
        !           203:          GC_push_one ((word) thread_table[i].context.IntT0);
        !           204:          GC_push_one ((word) thread_table[i].context.IntT1);
        !           205:          GC_push_one ((word) thread_table[i].context.IntT2);
        !           206:          GC_push_one ((word) thread_table[i].context.IntT3);
        !           207:          GC_push_one ((word) thread_table[i].context.IntT4);
        !           208:          GC_push_one ((word) thread_table[i].context.IntT5);
        !           209:          GC_push_one ((word) thread_table[i].context.IntT6);
        !           210:          GC_push_one ((word) thread_table[i].context.IntT7);
        !           211:          GC_push_one ((word) thread_table[i].context.IntS0);
        !           212:          GC_push_one ((word) thread_table[i].context.IntS1);
        !           213:          GC_push_one ((word) thread_table[i].context.IntS2);
        !           214:          GC_push_one ((word) thread_table[i].context.IntS3);
        !           215:          GC_push_one ((word) thread_table[i].context.IntS4);
        !           216:          GC_push_one ((word) thread_table[i].context.IntS5);
        !           217:          GC_push_one ((word) thread_table[i].context.IntS6);
        !           218:          GC_push_one ((word) thread_table[i].context.IntS7);
        !           219:          GC_push_one ((word) thread_table[i].context.IntT8);
        !           220:          GC_push_one ((word) thread_table[i].context.IntT9);
        !           221:          GC_push_one ((word) thread_table[i].context.IntK0);
        !           222:          GC_push_one ((word) thread_table[i].context.IntK1);
        !           223:          GC_push_one ((word) thread_table[i].context.IntS8);
        !           224:          GC_push_all_stack((char *) thread_table[i].context.IntSp,
        !           225:                            thread_table[i].stack);
        !           226: #      else
        !           227: #      ifdef PPC
        !           228:          if (thread_table[i].context.Gpr1 >= (DWORD)thread_table[i].stack
        !           229:              || thread_table[i].context.Gpr1 < (DWORD)bottom)
        !           230:              ABORT("Thread stack pointer out of range");
        !           231:          GC_push_one ((word) thread_table[i].context.Gpr0);
        !           232:          /* Gpr1 is stack pointer */
        !           233:          /* Gpr2 is global pointer */
        !           234:          GC_push_one ((word) thread_table[i].context.Gpr3);
        !           235:          GC_push_one ((word) thread_table[i].context.Gpr4);
        !           236:          GC_push_one ((word) thread_table[i].context.Gpr5);
        !           237:          GC_push_one ((word) thread_table[i].context.Gpr6);
        !           238:          GC_push_one ((word) thread_table[i].context.Gpr7);
        !           239:          GC_push_one ((word) thread_table[i].context.Gpr8);
        !           240:          GC_push_one ((word) thread_table[i].context.Gpr9);
        !           241:          GC_push_one ((word) thread_table[i].context.Gpr10);
        !           242:          GC_push_one ((word) thread_table[i].context.Gpr11);
        !           243:          GC_push_one ((word) thread_table[i].context.Gpr12);
        !           244:          /* Gpr13 is reserved for the kernel */
        !           245:          GC_push_one ((word) thread_table[i].context.Gpr14);
        !           246:          GC_push_one ((word) thread_table[i].context.Gpr15);
        !           247:          GC_push_one ((word) thread_table[i].context.Gpr16);
        !           248:          GC_push_one ((word) thread_table[i].context.Gpr17);
        !           249:          GC_push_one ((word) thread_table[i].context.Gpr18);
        !           250:          GC_push_one ((word) thread_table[i].context.Gpr19);
        !           251:          GC_push_one ((word) thread_table[i].context.Gpr20);
        !           252:          GC_push_one ((word) thread_table[i].context.Gpr21);
        !           253:          GC_push_one ((word) thread_table[i].context.Gpr22);
        !           254:          GC_push_one ((word) thread_table[i].context.Gpr23);
        !           255:          GC_push_one ((word) thread_table[i].context.Gpr24);
        !           256:          GC_push_one ((word) thread_table[i].context.Gpr25);
        !           257:          GC_push_one ((word) thread_table[i].context.Gpr26);
        !           258:          GC_push_one ((word) thread_table[i].context.Gpr27);
        !           259:          GC_push_one ((word) thread_table[i].context.Gpr28);
        !           260:          GC_push_one ((word) thread_table[i].context.Gpr29);
        !           261:          GC_push_one ((word) thread_table[i].context.Gpr30);
        !           262:          GC_push_one ((word) thread_table[i].context.Gpr31);
        !           263:          GC_push_all_stack((char *) thread_table[i].context.Gpr1,
        !           264:                            thread_table[i].stack);
        !           265: #      else
        !           266: #      ifdef ALPHA
        !           267:          if (thread_table[i].context.IntSp >= (DWORD)thread_table[i].stack
        !           268:              || thread_table[i].context.IntSp < (DWORD)bottom)
        !           269:              ABORT("Thread stack pointer out of range");
        !           270:          GC_push_one ((word) thread_table[i].context.IntV0);
        !           271:          GC_push_one ((word) thread_table[i].context.IntT0);
        !           272:          GC_push_one ((word) thread_table[i].context.IntT1);
        !           273:          GC_push_one ((word) thread_table[i].context.IntT2);
        !           274:          GC_push_one ((word) thread_table[i].context.IntT3);
        !           275:          GC_push_one ((word) thread_table[i].context.IntT4);
        !           276:          GC_push_one ((word) thread_table[i].context.IntT5);
        !           277:          GC_push_one ((word) thread_table[i].context.IntT6);
        !           278:          GC_push_one ((word) thread_table[i].context.IntT7);
        !           279:          GC_push_one ((word) thread_table[i].context.IntS0);
        !           280:          GC_push_one ((word) thread_table[i].context.IntS1);
        !           281:          GC_push_one ((word) thread_table[i].context.IntS2);
        !           282:          GC_push_one ((word) thread_table[i].context.IntS3);
        !           283:          GC_push_one ((word) thread_table[i].context.IntS4);
        !           284:          GC_push_one ((word) thread_table[i].context.IntS5);
        !           285:          GC_push_one ((word) thread_table[i].context.IntFp);
        !           286:          GC_push_one ((word) thread_table[i].context.IntA0);
        !           287:          GC_push_one ((word) thread_table[i].context.IntA1);
        !           288:          GC_push_one ((word) thread_table[i].context.IntA2);
        !           289:          GC_push_one ((word) thread_table[i].context.IntA3);
        !           290:          GC_push_one ((word) thread_table[i].context.IntA4);
        !           291:          GC_push_one ((word) thread_table[i].context.IntA5);
        !           292:          GC_push_one ((word) thread_table[i].context.IntT8);
        !           293:          GC_push_one ((word) thread_table[i].context.IntT9);
        !           294:          GC_push_one ((word) thread_table[i].context.IntT10);
        !           295:          GC_push_one ((word) thread_table[i].context.IntT11);
        !           296:          GC_push_one ((word) thread_table[i].context.IntT12);
        !           297:          GC_push_one ((word) thread_table[i].context.IntAt);
        !           298:          GC_push_all_stack((char *) thread_table[i].context.IntSp,
        !           299:                            thread_table[i].stack);
        !           300: #      else
        !           301:              --> architecture not supported
        !           302: #      endif /* !ALPHA */
        !           303: #      endif /* !PPC */
        !           304: #      endif /* !MIPS */
        !           305: #      endif /* !SHx */
        !           306: #      endif /* !ARM32 */
        !           307: #      endif /* !I386 */
1.1       noro      308:       }
                    309:     }
                    310: }
                    311:
                    312: void GC_get_next_stack(char *start, char **lo, char **hi)
                    313: {
                    314:     int i;
                    315: #   define ADDR_LIMIT (char *)(-1L)
                    316:     char * current_min = ADDR_LIMIT;
                    317:
                    318:     for (i = 0; i < MAX_THREADS; i++) {
                    319:        char * s = (char *)thread_table[i].stack;
                    320:
                    321:        if (0 != s && s > start && s < current_min) {
                    322:            current_min = s;
                    323:        }
                    324:     }
                    325:     *hi = current_min;
                    326:     if (current_min == ADDR_LIMIT) {
                    327:        *lo = ADDR_LIMIT;
                    328:        return;
                    329:     }
                    330:     *lo = GC_get_lo_stack_addr(current_min);
                    331:     if (*lo < start) *lo = start;
                    332: }
                    333:
1.3     ! noro      334:
        !           335: # ifdef MSWINCE
        !           336:
        !           337: typedef struct {
        !           338:     HANDLE child_ready_h, parent_ready_h;
        !           339:     volatile struct thread_entry * entry;
        !           340:     LPTHREAD_START_ROUTINE start;
        !           341:     LPVOID param;
        !           342: } thread_args;
        !           343:
        !           344: DWORD WINAPI thread_start(LPVOID arg);
        !           345:
        !           346: HANDLE WINAPI GC_CreateThread(
        !           347:     LPSECURITY_ATTRIBUTES lpThreadAttributes,
        !           348:     DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress,
        !           349:     LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId )
        !           350: {
        !           351:     HANDLE thread_h = NULL;
        !           352:     HANDLE child_ready_h, parent_ready_h;
        !           353:
        !           354:     int i;
        !           355:     thread_args args;
        !           356:
        !           357:     /* allocate thread slot */
        !           358:     LOCK();
        !           359:     for (i = 0; i != MAX_THREADS && thread_table[i].in_use; i++)
        !           360:        ;
        !           361:     if (i != MAX_THREADS) {
        !           362:        thread_table[i].in_use = TRUE;
        !           363:     }
        !           364:     UNLOCK();
        !           365:
        !           366:     if (i != MAX_THREADS) {
        !           367:
        !           368:        /* create unnamed unsignalled events */
        !           369:        if (child_ready_h = CreateEvent(NULL, FALSE, FALSE, NULL)) {
        !           370:            if (parent_ready_h = CreateEvent(NULL, FALSE, FALSE, NULL)) {
        !           371:
        !           372:                /* set up thread arguments */
        !           373:                args.child_ready_h = child_ready_h;
        !           374:                args.parent_ready_h = parent_ready_h;
        !           375:                args.entry = &thread_table[i];
        !           376:                args.start = lpStartAddress;
        !           377:                args.param = lpParameter;
        !           378:
        !           379:                thread_h = CreateThread(lpThreadAttributes,
        !           380:                                        dwStackSize, thread_start,
        !           381:                                        &args,
        !           382:                                        dwCreationFlags & ~CREATE_SUSPENDED,
        !           383:                                        lpThreadId);
        !           384:
        !           385:                if (thread_h) {
        !           386:
        !           387:                    /* fill in ID and handle; tell child this is done */
        !           388:                    thread_table[i].id = *lpThreadId;
        !           389:                    thread_table[i].handle = thread_h;
        !           390:                    SetEvent (parent_ready_h);
        !           391:
        !           392:                    /* wait for child to fill in stack and copy args */
        !           393:                    WaitForSingleObject (child_ready_h, INFINITE);
        !           394:
        !           395:                    /* suspend the child if requested */
        !           396:                    if (dwCreationFlags & CREATE_SUSPENDED)
        !           397:                        SuspendThread (thread_h);
        !           398:
        !           399:                    /* let child call given function now (or when resumed) */
        !           400:                    SetEvent (parent_ready_h);
        !           401:
        !           402:                } else {
        !           403:                    CloseHandle (parent_ready_h);
        !           404:                }
        !           405:            }
        !           406:        }
        !           407:
        !           408:        CloseHandle (child_ready_h);
        !           409:
        !           410:        if (thread_h == NULL)
        !           411:            thread_table[i].in_use = FALSE;
        !           412:
        !           413:     } else { /* no thread slot found */
        !           414:        SetLastError (ERROR_TOO_MANY_TCBS);
        !           415:     }
        !           416:
        !           417:     return thread_h;
        !           418: }
        !           419:
        !           420: static DWORD WINAPI thread_start(LPVOID arg)
        !           421: {
        !           422:     DWORD ret = 0;
        !           423:     thread_args args = *(thread_args *)arg;
        !           424:
        !           425:     /* wait for parent to fill in ID and handle */
        !           426:     WaitForSingleObject (args.parent_ready_h, INFINITE);
        !           427:     ResetEvent (args.parent_ready_h);
        !           428:
        !           429:     /* fill in stack; tell parent this is done */
        !           430:     args.entry->stack = GC_get_stack_base();
        !           431:     SetEvent (args.child_ready_h);
        !           432:
        !           433:     /* wait for parent to tell us to go (in case it needs to suspend us) */
        !           434:     WaitForSingleObject (args.parent_ready_h, INFINITE);
        !           435:     CloseHandle (args.parent_ready_h);
        !           436:
        !           437:     /* Clear the thread entry even if we exit with an exception.       */
        !           438:     /* This is probably pointless, since an uncaught exception is      */
        !           439:     /* supposed to result in the process being killed.                 */
        !           440:     __try {
        !           441:        ret = args.start (args.param);
        !           442:     } __finally {
        !           443:        LOCK();
        !           444:        args.entry->stack = 0;
        !           445:        args.entry->in_use = FALSE;
        !           446:              /* cast away volatile qualifier */
        !           447:        BZERO((void *) &args.entry->context, sizeof(CONTEXT));
        !           448:        UNLOCK();
        !           449:     }
        !           450:
        !           451:     return ret;
        !           452: }
        !           453:
        !           454: typedef struct {
        !           455:     HINSTANCE hInstance;
        !           456:     HINSTANCE hPrevInstance;
        !           457:     LPWSTR lpCmdLine;
        !           458:     int nShowCmd;
        !           459: } main_thread_args;
        !           460:
        !           461: DWORD WINAPI main_thread_start(LPVOID arg);
        !           462:
        !           463: int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
        !           464:                   LPWSTR lpCmdLine, int nShowCmd)
        !           465: {
        !           466:     DWORD exit_code = 1;
        !           467:
        !           468:     main_thread_args args = {
        !           469:        hInstance, hPrevInstance, lpCmdLine, nShowCmd
        !           470:     };
        !           471:     HANDLE thread_h;
        !           472:     DWORD thread_id;
        !           473:
        !           474:     /* initialize everything */
        !           475:     InitializeCriticalSection(&GC_allocate_ml);
        !           476:     GC_init();
        !           477:
        !           478:     /* start the main thread */
        !           479:     thread_h = GC_CreateThread(
        !           480:        NULL, 0, main_thread_start, &args, 0, &thread_id);
        !           481:
        !           482:     if (thread_h != NULL)
        !           483:     {
        !           484:        WaitForSingleObject (thread_h, INFINITE);
        !           485:        GetExitCodeThread (thread_h, &exit_code);
        !           486:        CloseHandle (thread_h);
        !           487:     }
        !           488:
        !           489:     GC_deinit();
        !           490:     DeleteCriticalSection(&GC_allocate_ml);
        !           491:
        !           492:     return (int) exit_code;
        !           493: }
        !           494:
        !           495: DWORD WINAPI main_thread_start(LPVOID arg)
        !           496: {
        !           497:     main_thread_args * args = (main_thread_args *) arg;
        !           498:
        !           499:     return (DWORD) GC_WinMain (args->hInstance, args->hPrevInstance,
        !           500:                               args->lpCmdLine, args->nShowCmd);
        !           501: }
        !           502:
        !           503: # else /* !MSWINCE */
        !           504:
1.1       noro      505: LONG WINAPI GC_write_fault_handler(struct _EXCEPTION_POINTERS *exc_info);
                    506:
                    507: /*
                    508:  * This isn't generally safe, since DllMain is not premptible.
                    509:  * If another thread holds the lock while this runs we're in trouble.
                    510:  * Pontus Rydin suggests wrapping the thread start routine instead.
                    511:  */
                    512: BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVOID reserved)
                    513: {
                    514:   switch (reason) {
                    515:   case DLL_PROCESS_ATTACH:
                    516:     InitializeCriticalSection(&GC_allocate_ml);
                    517:     GC_init(); /* Force initialization before thread attach.   */
                    518:     /* fall through */
                    519:   case DLL_THREAD_ATTACH:
                    520:     {
                    521:       int i;
                    522:       /* It appears to be unsafe to acquire a lock here, since this    */
                    523:       /* code is apparently not preeemptible on some systems.          */
                    524:       /* (This is based on complaints, not on Microsoft's official     */
                    525:       /* documentation, which says this should perform "only simple    */
                    526:       /* inititalization tasks".)                                      */
                    527:       /* Hence we make do with nonblocking synchronization.            */
                    528:
                    529:       /* The following should be a noop according to the win32 */
                    530:       /* documentation.  There is empirical evidence that it   */
                    531:       /* isn't.                - HB                                    */
1.3     ! noro      532: #     ifdef MPROTECT_VDB
1.1       noro      533:        if (GC_incremental) SetUnhandledExceptionFilter(GC_write_fault_handler);
                    534: #     endif
                    535:
1.3     ! noro      536:       for (i = 0;
        !           537:                               /* cast away volatile qualifier */
        !           538:           InterlockedExchange((LPLONG) &thread_table[i].in_use, 1) != 0;
        !           539:           i++) {
1.1       noro      540:        /* Compare-and-swap would make this cleaner, but that's not     */
                    541:        /* supported before Windows 98 and NT 4.0.  In Windows 2000,    */
                    542:        /* InterlockedExchange is supposed to be replaced by            */
                    543:        /* InterlockedExchangePointer, but that's not really what I     */
                    544:        /* want here.                                                   */
                    545:        if (i == MAX_THREADS - 1)
                    546:          ABORT("too many threads");
                    547:       }
                    548:       thread_table[i].id = GetCurrentThreadId();
                    549:       if (!DuplicateHandle(GetCurrentProcess(),
1.3     ! noro      550:                           GetCurrentThread(),
1.1       noro      551:                           GetCurrentProcess(),
1.3     ! noro      552:                           /* cast away volatile qualifier */
        !           553:                           (HANDLE *) &thread_table[i].handle,
1.1       noro      554:                           0,
                    555:                           0,
                    556:                           DUPLICATE_SAME_ACCESS)) {
1.3     ! noro      557:        DWORD last_error = GetLastError();
        !           558:        GC_printf1("Last error code: %lx\n", last_error);
        !           559:        ABORT("DuplicateHandle failed");
1.1       noro      560:       }
                    561:       thread_table[i].stack = GC_get_stack_base();
                    562:       /* If this thread is being created while we are trying to stop   */
                    563:       /* the world, wait here.  Hopefully this can't happen on any     */
                    564:       /* systems that don't allow us to block here.                    */
                    565:       while (GC_please_stop) Sleep(20);
                    566:     }
                    567:     break;
                    568:   case DLL_THREAD_DETACH:
                    569:     {
                    570:       int i;
                    571:       DWORD thread_id = GetCurrentThreadId();
                    572:       LOCK();
                    573:       for (i = 0;
1.3     ! noro      574:            i < MAX_THREADS &&
        !           575:           (thread_table[i].stack == 0 || thread_table[i].id != thread_id);
        !           576:           i++) {}
        !           577:       if (i >= MAX_THREADS) {
        !           578:          WARN("thread %ld not found on detach", (GC_word)thread_id);
        !           579:       } else {
        !           580:           thread_table[i].stack = 0;
        !           581:           thread_table[i].in_use = FALSE;
        !           582:           CloseHandle(thread_table[i].handle);
        !           583:            /* cast away volatile qualifier */
        !           584:           BZERO((void *) &thread_table[i].context, sizeof(CONTEXT));
        !           585:       }
        !           586:       UNLOCK();
        !           587:     }
        !           588:     break;
        !           589:   case DLL_PROCESS_DETACH:
        !           590:     {
        !           591:       int i;
        !           592:
        !           593:       LOCK();
        !           594:       for (i = 0; i < MAX_THREADS; ++i)
        !           595:       {
        !           596:           if (thread_table[i].in_use)
        !           597:           {
        !           598:               thread_table[i].stack = 0;
        !           599:               thread_table[i].in_use = FALSE;
        !           600:               CloseHandle(thread_table[i].handle);
        !           601:               BZERO((void *) &thread_table[i].context, sizeof(CONTEXT));
        !           602:           }
1.1       noro      603:       }
                    604:       UNLOCK();
1.3     ! noro      605:
        !           606:       GC_deinit();
        !           607:       DeleteCriticalSection(&GC_allocate_ml);
1.1       noro      608:     }
                    609:     break;
1.3     ! noro      610:
1.1       noro      611:   }
                    612:   return TRUE;
                    613: }
1.3     ! noro      614:
        !           615: # endif /* !MSWINCE */
1.1       noro      616:
                    617: #endif /* WIN32_THREADS */

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