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. */ |
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); |
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 |
} |
} |
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 |
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; |
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); |
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); |