/[dotgnu-pnet]/pnet/libgc/win32_threads.c
ViewVC logotype

Diff of /pnet/libgc/win32_threads.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.12 by ktreichel, Sat Jul 23 12:52:58 2005 UTC revision 1.13 by ktreichel, Sat Jul 23 14:59:34 2005 UTC
# Line 27  Line 27 
27  typedef LONG * IE_t;  typedef LONG * IE_t;
28    
29  #ifndef MAX_THREADS  #ifndef MAX_THREADS
30  # define MAX_THREADS 256  # define MAX_THREADS 1024
31      /* FIXME:                                                   */      /* FIXME:                                                   */
32      /* Things may get quite slow for large numbers of threads,  */      /* Things may get quite slow for large numbers of threads,  */
33      /* since we look them up with sequential search.            */      /* since we look them up with sequential search.            */
# Line 465  GC_API HANDLE WINAPI GC_CreateThread( Line 465  GC_API HANDLE WINAPI GC_CreateThread(
465      if (!GC_is_initialized) GC_init();      if (!GC_is_initialized) GC_init();
466                  /* make sure GC is initialized (i.e. main thread is attached) */                  /* make sure GC is initialized (i.e. main thread is attached) */
467            
468      args = GC_malloc_uncollectable(sizeof(thread_args));          /* It appears to be unsafe to use the GC's allocator here */
469        args = malloc(sizeof(thread_args)); */
470    
471          /* Handed off to and deallocated by child thread.       */          /* Handed off to and deallocated by child thread.       */
472      if (0 == args) {      if (0 == args) {
473          SetLastError(ERROR_NOT_ENOUGH_MEMORY);          SetLastError(ERROR_NOT_ENOUGH_MEMORY);
# Line 501  static DWORD WINAPI thread_start(LPVOID Line 503  static DWORD WINAPI thread_start(LPVOID
503  #ifndef __GNUC__  #ifndef __GNUC__
504      } __finally {      } __finally {
505  #endif /* __GNUC__ */  #endif /* __GNUC__ */
506          GC_free(args);          free(args);
507          GC_delete_thread(GetCurrentThreadId());          GC_delete_thread(GetCurrentThreadId());
508  #ifndef __GNUC__  #ifndef __GNUC__
509      }      }
# Line 612  int GC_pthread_join(pthread_t pthread_id Line 614  int GC_pthread_join(pthread_t pthread_id
614      return result;      return result;
615  }  }
616    
617    /*
618     * Some CYGWIN applications (like portable.net) use CreateThread.
619     * The wrappers for CreateThread for non-cgywin systems don't seem to
620     * be stable in so calls to CreateThread are redirected to through
621     * GC_pthread_create.
622     */
623    
624    /*
625     * Start information for CreateThread.
626     */
627    struct createthread_startinfo
628    {
629            HANDLE *handle_ptr;
630            DWORD *threadid_ptr;    
631            HANDLE waitHandle;
632            LPVOID parameter;
633            DWORD creationFlags;
634            LPTHREAD_START_ROUTINE startFunc;
635    };
636    
637    /*
638     * pthread start function for redirected CreateThread calls.
639     */
640    static void *main_thread_start(void *arg)
641    {
642            struct createthread_startinfo startinfo;
643            struct createthread_startinfo *startinfo_ptr;
644    
645            startinfo_ptr = (struct createthread_startinfo *)arg;
646            
647            /* Get and duplicate the handle to this thread and
648               return it through the startinfo_ptr */
649            if (!DuplicateHandle(GetCurrentProcess(),
650                            GetCurrentThread(),
651                            GetCurrentProcess(),
652                            startinfo_ptr->handle_ptr,
653                            0,
654                            0,
655                            DUPLICATE_SAME_ACCESS))
656            {
657                    DWORD last_error = GetLastError();
658                    GC_printf1("Last error code: %lx\n", last_error);
659                    
660                    ABORT("DuplicateHandle failed");
661            }
662    
663            /* Return the ThreadID through the startinfo_ptr */
664            if (startinfo_ptr->threadid_ptr)
665            {
666                    *startinfo_ptr->threadid_ptr = GetCurrentThreadId();
667            }
668            
669            /* Make a copy of the startinfo because it could be invalid
670               any time after we signal startinfo.waitHandle */
671            startinfo = *startinfo_ptr;
672    
673            /* Let the creater thread  know we have set the handle/threadid */
674            SetEvent(startinfo.waitHandle);
675    
676            /* If CREATE_SUSPENDED is requested then suspend the thread */
677            if (startinfo.creationFlags & CREATE_SUSPENDED)
678            {
679                    SuspendThread(GetCurrentThread());
680            }
681    
682            /* Start the actual thread function */
683            return (void *)startinfo.startFunc(startinfo.parameter);
684    }
685    
686    /*
687     * Wrapper for CreateThread.  This function is for CYGWIN systems and
688     * redirects CreateThread calls to GC_pthread_create.
689     */
690    GC_API HANDLE GC_CreateThread(
691        LPSECURITY_ATTRIBUTES lpThreadAttributes,
692        DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress,
693        LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId )
694    {
695            HANDLE handle;
696            pthread_t new_thread;
697            pthread_attr_t attr;
698            struct createthread_startinfo startinfo;
699    
700            /* Make sure GC is initialized (i.e. main thread is attached) */
701            if (!GC_is_initialized)
702            {
703                    GC_init();
704            }
705            
706            /* This WaitHandle will be signalled once the new thread has filled in
707               its handle/threadid information */
708            startinfo.waitHandle = CreateEvent(0, 1, 0, 0);
709    
710            if (startinfo.waitHandle == NULL)
711            {
712                    SetLastError(ERROR_NOT_ENOUGH_MEMORY);
713            
714                    return 0;
715            }
716    
717            handle = 0;
718    
719            /* Setup the CreateThread start information */
720            startinfo.handle_ptr = &handle;
721            startinfo.threadid_ptr = lpThreadId;
722            startinfo.parameter = lpParameter;
723            startinfo.startFunc = lpStartAddress;
724            startinfo.creationFlags = dwCreationFlags;
725    
726            /* Initialize the pthread_attr_t with defaults */
727            if (pthread_attr_init(&attr) != 0)
728            {
729                    SetLastError(ERROR_NOT_ENOUGH_MEMORY);
730                    CloseHandle(startinfo.waitHandle);
731                    
732                    return 0;
733            }
734            
735            if (dwStackSize != 0)
736            {
737                    /* Set the stack size if specified */
738                    pthread_attr_setstacksize(&attr, (size_t)dwStackSize);
739            }
740    
741            /* Create a CYGWIN pthread */
742            if (GC_pthread_create(&new_thread, &attr, main_thread_start, &startinfo) == 0)
743            {
744                    /* Wait for the handle/threadid to be filled in */
745                    WaitForSingleObject(startinfo.waitHandle, INFINITE);
746            }
747            else
748            {
749                    handle = 0;
750    
751                    if (lpThreadId)
752                    {
753                            *lpThreadId = 0;
754                    }
755            }
756    
757            /* Free the pthread_attr_t structure */
758            pthread_attr_destroy(&attr);
759            /* Free the wait event */
760            CloseHandle(startinfo.waitHandle);
761            
762            return handle;
763    }
764    
765  /* Cygwin-pthreads calls CreateThread internally, but it's not  /* Cygwin-pthreads calls CreateThread internally, but it's not
766   * easily interceptible by us..   * easily interceptible by us..
767   *   so intercept pthread_create instead   *   so intercept pthread_create instead
# Line 628  GC_pthread_create(pthread_t *new_thread, Line 778  GC_pthread_create(pthread_t *new_thread,
778            
779      /* This is otherwise saved only in an area mmapped by the thread */      /* This is otherwise saved only in an area mmapped by the thread */
780      /* library, which isn't visible to the collector.            */      /* library, which isn't visible to the collector.            */
781      si = GC_malloc_uncollectable(sizeof(struct start_info));          /* It appears to be unsafe to use the GC's allocator here */
782        si = malloc(sizeof(struct start_info));
783      if (0 == si) return(EAGAIN);      if (0 == si) return(EAGAIN);
784    
785      si -> start_routine = start_routine;      si -> start_routine = start_routine;
# Line 646  GC_pthread_create(pthread_t *new_thread, Line 797  GC_pthread_create(pthread_t *new_thread,
797      result = pthread_create(new_thread, attr, GC_start_routine, si);      result = pthread_create(new_thread, attr, GC_start_routine, si);
798    
799      if (result) { /* failure */      if (result) { /* failure */
800          GC_free(si);                  free(si);
801      }      }
802    
803      return(result);      return(result);
# Line 683  void * GC_start_routine(void * arg) Line 834  void * GC_start_routine(void * arg)
834      if (si-> detached) me -> flags |= DETACHED;      if (si-> detached) me -> flags |= DETACHED;
835      me -> pthread_id = pthread_id = pthread_self();      me -> pthread_id = pthread_id = pthread_self();
836    
837      GC_free(si); /* was allocated uncollectable */      free(si); /* was allocated uncollectable */
838    
839      pthread_cleanup_push(GC_thread_exit_proc, (void *)me);      pthread_cleanup_push(GC_thread_exit_proc, (void *)me);
840      result = (*start)(start_arg);      result = (*start)(start_arg);

Legend:
Removed from v.1.12  
changed lines
  Added in v.1.13

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26