newlib-cygwin/winsup/cygwin/cygthread.cc

326 lines
7.0 KiB
C++
Raw Normal View History

/* cygthread.cc
Copyright 1998, 1999, 2000, 2001, 2002, 2003 Red Hat, Inc.
This software is a copyrighted work licensed under the terms of the
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */
#include "winsup.h"
#include <windows.h>
#include <stdlib.h>
#include "exceptions.h"
#include "security.h"
#include "cygthread.h"
#include "sync.h"
#include "cygerrno.h"
#include "sigproc.h"
#include "thread.h"
#include "cygtls.h"
#undef CloseHandle
* cygwin/include/signal.h: Add copyright notice. * cygwin.din: Make clock SIGFE. Add clock_gettime, sigwaitinfo, timer_create, timer_delete, timer_settime. * include/cygwin/version.h: Reflect above additions. * fork.cc (fork_child): Call fixup_timers_after_fork. * signal.cc (sigwait): Remove unused variable. * timer.cc: New file. (clock_gettime): Define new function. (timer_tracker): Define new struct used by timer functions. (timer_tracker::timer_tracker): New function. (to_us): New function. (timer_thread): New function. (timer_tracker::settime): New function. (timer_create): New function. (timer_settime): New function. (timer_delete): New function. (fixup_timers_after_fork): New function. * cygthread.cc: Bump thread count. * signal.cc (sigwaitinfo): Define new function. (sigwait): Redefine based on sigwaitinfo. * include/cygwin/signal.h (sigwaitinfo): Declare. (sigwait): Ditto. * dtable.cc (dtable::vfork_parent_restore): Avoid double close of ctty when ctty == ctty_on_hold. * cygtls.h (_threadinfo::threadkill): New element. (_threadinfo::set_threadkill): Declare new function. (_threadinfo::reset_threadkill): Declare new function. * dcrt0.cc (dcrt0_1): Call here so that it will be possible to attach to running process with #(*& Windows Me/9x. (initial_env): Try to initialize strace if uninitialized. * gendef: Don't zero signal if threadkill is set since that will happen in the called function. * signal.cc (sigwait): Ensure cleanup in error conditions. * sigproc.cc (sig_send): Clear packet mask storage. (wait_subproc): Fill in child exit code in siginfo_t structure. * thread.cc (pthread_kill): Set threadkill flag. * tlsoffsets.h: Regenerate. Throughout, use siginfo_t to fill out all signal information for "kernel" signals. * cygtls.h (_threadinfo::set_siginfo): Declare new function. * cygtls.cc (_threadinfo::set_siginfo): Define new function. * dcrt0.cc (do_exit): Accommodate siginfo_t considerations. * exceptions.cc (handle_exceptions): Ditto. (sig_handle_tty_stop): Ditto. (ctrl_c_handler): Use killsys() to send signal. (sigpacket::process): Rename from sig_handle. Use siginfo_t field from sigpacket for everything. (tty_min::kill_pgrp): Accommodate siginfo_t considerations. (fhandler_termios::bg_check): Ditto. * fhandler_tty.cc (fhandler_tty_slave::ioctl): Use killsys() to send signal. * signal.cc (kill_worker): Rewrite to use siginfo_t second argument. (kill_pgrp): Ditto. (kill0): Define new function pulled from kill(). (kill): Rewrite as frontend to kill0. (killsys): Define new function. * sigproc.cc (sigelem): Eliminate. (sigpacket): Move to sigproc.h. Subsume sigelem. (pending_signals): Use sigpacket rather than sigelem for everything. (sig_clear): Ditto. (wait_sig): Ditto. (sig_send): Rewrite to use siginfo_t argument. (sig_send): New function wratpper to sig_send with siginfo_t argument. (wait_subproc): Accommodate siginfo_t considerations. * thread.cc (pthread_kill): Ditto. * sigproc.h (sigpacket): Move here. (sigpacket::process): Declare "new" function. (sig_handle): Eliminate declaration. (sig_send): Declare with new paramaters. (killsys): Declare new function. (kill_pgrp): Declare. * winsup.h: Move some signal-specific stuff to sigproc.h. * include/cygwin/signal.h: Tweak some siginfo_t stuff.
2004-01-19 13:46:54 +08:00
static cygthread NO_COPY threads[32];
#define NTHREADS (sizeof (threads) / sizeof (threads[0]))
DWORD NO_COPY cygthread::main_thread_id;
bool NO_COPY cygthread::exiting;
/* Initial stub called by cygthread constructor. Performs initial
per-thread initialization and loops waiting for new thread functions
to execute. */
DWORD WINAPI
cygthread::stub (VOID *arg)
{
cygthread *info = (cygthread *) arg;
if (info->arg == cygself)
{
if (info->ev)
{
CloseHandle (info->ev);
CloseHandle (info->thread_sync);
}
* cygtls.h (_threadinfo::call): Remove regparm declaration to work around compiler bug. * autoload.cc (TryEnterCriticalSection): Remove. * dcrt0.cc (dll_crt0_0): Delete inappropriate setting of _my_tls.stackptr to NULL since it has really bad consequences. Make 'si' an automatic variable. * cygtls.cc (_threadinfo::init_thread): Correct thinko which caused thread list to be allocated every time. * cygtls.h (CYGTLS_PADSIZE): Define as const int. * sync.h: Make multiple inclusion safe. (muto::next): Eliminate. (muto::exiting_thread): New variable. (muto::set_exiting_thread): New function. (new_muto): Change to use different section for mutos since c++ give inexplicable warning in some cases otherwise. (new_muto1): Ditto. * dcrt0.cc (do_exit): Call muto::set_exiting_thread here. * sync.cc (muto_start): Eliminate. (muto::acquire): Always give exiting thread a lock. Never give thread a lock if exiting. (muto::release): Ditto for releasing. * dtable.cc (dtable::init_lock): Unline function and define here. * dtable.h (lock_cs): Define as a muto since critical sections seem to work oddly on Windows Me. (lock): Accommodate switch to muto. (unlock): Ditto. * exceptions.cc (setup_handler): Don't worry about acquiring mutos since that hasn't mattered for a long time. (signal_exit): Ditto: muto stuff will be handled automatically on exit now. * Makefile.in (DLL_IMPORTS): Link advapi32 to ensure proper DLL initialization. * autoload.cc (RegCloseKey): Arbitrarily choose this function as a "seed" to pull the advapi32 link library in. So, comment out the autoloading. * cygtls.cc (_threadinfo::init_thread): Just clear CYGTLS_PADSIZE. (_threadinfo::remove): Add debugging. (_threadinfo::find_tls): Ditto. * cygtls.h (_threadinfo::padding): Make zero length (for now?). * dcrt0.cc (dll_crt0_0): Move more initialization here from dll_crt0_1. (dll_crt0_1): See above. * dtable.h (dtable::lock): Remove commented out critical section locking. * dtable.h (dtable::init_lock): Remove commented out critical section locking. * dtable.h (dtable::unlock): Remove commented out critical section locking. * exceptions.cc (interruptible): bool'ize. * init.cc (threadfunc_fe): Revert to storing threadfunc at stack bottom. (munge_threadfunc): Ditto. Avoid adding overhead to calibration_thread. (prime_threads): Don't initialize tls stuff. (dll_entry): Make minor change to initialization order. * tlsoffsets.h: Regenerate. * sigproc.cc (wait_sig): Add sanity check for end of process thread exit. * select.h: Make minor formatting change. * Makefile.in: Add still more -fomit-frame-pointer functions. * dtable.h (dtable::lock): New function. (dtable::unlock): New function. (dtable::init_lock): New function. * cygheap.h (HEAP_TLS): Declare new enum value. (init_cygheap::threadlist): Declare new array. (init_cygheap::sthreads): Declare new variable. (cygheap_fdmanip::~cygheap_fdmanip): Use new dtable lock/unlock functions. (cygheap_fdnew::cygheap_fdnew): Ditto. (cygheap_fdget::cygheap_fdget): Ditto. * dtable.cc (dtable_init): Initialize fdtab critical section. (dtable::fixup_after_fork): Ditto. (dtable::fixup_after_exec): Ditto. (dtable::dup2): Use lock/unlock calls to protect access to fdtab. (dtable::find_fifo): Ditto. (dtable::fixup_before_fork): Ditto. (dtable::fixup_before_exec): Ditto. (dtable::set_file_pointers_for_exec): Ditto. (dtable::vfork_child_dup): Ditto. (dtable::vfork_parent_restore): Ditto. * syscalls.cc (close_all_files): Ditto. * sync.h (muto::acquired): Declare new function. (new_muto1): Declare new macro used to specify name of muto storage. * sync.cc (muto::acquired): Define new function. * cygthread.cc (cygthread::stub): Remove signal chain removal call since it is handled during initialization now. * cygthread.cc (cygthread::simplestub): Remove signal chain removal call since it is handled during initialization now. * cygtls.cc (sentry): New class used for locking. Use throughout. (_threadinfo::reset_exception): Don't pop stack. (_threadinfo::find_tls): Move from exceptions.cc. (_threadinfo::init_thread): Initialize array of threads rather than linked list. Take second argument indicating thread function for this thread. (_threadinfo::remove): Search thread array rather than linked list. Use sentry to lock. Only unlock if we got the lock. (_threadinfo::find_tls): Ditto for first two. (handle_threadlist_exception): Handle exceptions when manipulating the thread list in case of premature thread termination. (_threadinfo::init_threadlist_exceptions): Ditto. * cygtls.h (TLS_STACK_SIZE): Decrease size. (_threadinfo::padding): Add element to avoid overwriting lower part of stack. (_threadinfo::remove): Add a "wait" argument to control how long we wait for a lock before removing. * exceptions.cc (init_exception_handler): Make global. Take argument to control exception handler being set. (ctrl_c_handler): Wait forever when removing self from signal chain. (_threadinfo::find_tls): Move to cygtls.cc. (sig_handle): Reorganize detection for thread-specific signals. * heap.cc (heap_init): Rework slightly. Make fatal error more verbose. Remove malloc initialization since it can't happen during dll attach. * init.cc (search_for): Move address to search for on stack here. (threadfunc_ix): Ditto for stack offset. Make shared so that stack walk potentially only has to be done once when cygwin processes are running. (threadfunc_fe): Use standard tls to store thread function (may change back later). (calibration_thread): New function. Potentially called to find threadfunc_ix. (munge_threadfunc): Search for "search_for" value on stack. Output warning when thread func not found on stack. Use standard tls to store thread function. (prime_threads): New function. Called to prime thread front end. (dll_entry): Call dll_crt0_0 here when DLL_PROCESS_ATTACH. Call prime_threads here. Try to remove thread from signal list here. * sigproc.cc (wait_sig): Initialize threadlist exception stuff here. * thread.cc (pthread::exit): Pass argument to signal list remove function. * thread.h: Remove obsolete *ResourceLock defines. * tlsoffsets.h: Regenerate. * winsup.h (spf): Define temporary debug macro to be deleted later. * dcrt0.cc (dll_crt0_0): New function, called during DLL initialization. Mainly consists of code pulled from dll_crt0_1. (dll_crt0_1): See above. (_dll_crt0): Wait for initial calibration thread to complete, if appropriate. Move some stuff to dll_crt0_0. (initialize_main_tls): Accommodate argument change to _thread_info::init_thread. * fork.cc (fork_child): Ditto. (sync_with_child): Fix debug message. * external.cc (cygwin_internal): Remove special considerations for uninitialized dll since initialization happens during dll attach now. * dlfcn.cc (dlopen): Remove obsolete *ResourceLock calls. (dlclose): Ditto. * cygheap.h (init_cygheap::close_ctty): Declare new function. * cygheap.cc (init_cygheap::close_ctty): Define new function. * syscalls.cc (close_all_files): Use close_ctty. (setsid): Ditto. * cygthread.cc (cygthread::stub): Remove exception initialization. * cygthread.cc (cygthread::stub): Remove exception initialization. (cygthread::simplestub): Ditto. * thread.cc (pthread::thread_init_wrapper): Ditto. * cygtls.cc (_last_thread): Make static. (_threadinfo::call2): Initialize exception handler here. (_threadinfo::find_tls): Move here. * exceptions.cc (_threadinfo::find_tls): Move. * dcrt0.cc (__api_fatal): Add prefix info to message here rather than including it in every call to function. * winsup.h (api_fatal): Accommodate above change. * debug.cc (add_handle): Don't do anything if cygheap not around. (mark_closed): Ditto. * dll_init.cc (dll_list::detach): Fix debug output. * fork.cc (sync_with_child): Ditto. (vfork): Improve debug output. * heap.cc (heap_init): Ditto. * exceptions.cc (try_to_debug): Clarify message when debugger attaches.
2004-01-14 23:45:37 +08:00
info->ev = info->thread_sync = info->stack_ptr = NULL;
}
else
{
info->stack_ptr = &arg;
if (!info->ev)
{
info->ev = CreateEvent (&sec_none_nih, TRUE, FALSE, NULL);
info->thread_sync = CreateEvent (&sec_none_nih, FALSE, FALSE, NULL);
}
}
* cygtls.h (_threadinfo::call): Remove regparm declaration to work around compiler bug. * autoload.cc (TryEnterCriticalSection): Remove. * dcrt0.cc (dll_crt0_0): Delete inappropriate setting of _my_tls.stackptr to NULL since it has really bad consequences. Make 'si' an automatic variable. * cygtls.cc (_threadinfo::init_thread): Correct thinko which caused thread list to be allocated every time. * cygtls.h (CYGTLS_PADSIZE): Define as const int. * sync.h: Make multiple inclusion safe. (muto::next): Eliminate. (muto::exiting_thread): New variable. (muto::set_exiting_thread): New function. (new_muto): Change to use different section for mutos since c++ give inexplicable warning in some cases otherwise. (new_muto1): Ditto. * dcrt0.cc (do_exit): Call muto::set_exiting_thread here. * sync.cc (muto_start): Eliminate. (muto::acquire): Always give exiting thread a lock. Never give thread a lock if exiting. (muto::release): Ditto for releasing. * dtable.cc (dtable::init_lock): Unline function and define here. * dtable.h (lock_cs): Define as a muto since critical sections seem to work oddly on Windows Me. (lock): Accommodate switch to muto. (unlock): Ditto. * exceptions.cc (setup_handler): Don't worry about acquiring mutos since that hasn't mattered for a long time. (signal_exit): Ditto: muto stuff will be handled automatically on exit now. * Makefile.in (DLL_IMPORTS): Link advapi32 to ensure proper DLL initialization. * autoload.cc (RegCloseKey): Arbitrarily choose this function as a "seed" to pull the advapi32 link library in. So, comment out the autoloading. * cygtls.cc (_threadinfo::init_thread): Just clear CYGTLS_PADSIZE. (_threadinfo::remove): Add debugging. (_threadinfo::find_tls): Ditto. * cygtls.h (_threadinfo::padding): Make zero length (for now?). * dcrt0.cc (dll_crt0_0): Move more initialization here from dll_crt0_1. (dll_crt0_1): See above. * dtable.h (dtable::lock): Remove commented out critical section locking. * dtable.h (dtable::init_lock): Remove commented out critical section locking. * dtable.h (dtable::unlock): Remove commented out critical section locking. * exceptions.cc (interruptible): bool'ize. * init.cc (threadfunc_fe): Revert to storing threadfunc at stack bottom. (munge_threadfunc): Ditto. Avoid adding overhead to calibration_thread. (prime_threads): Don't initialize tls stuff. (dll_entry): Make minor change to initialization order. * tlsoffsets.h: Regenerate. * sigproc.cc (wait_sig): Add sanity check for end of process thread exit. * select.h: Make minor formatting change. * Makefile.in: Add still more -fomit-frame-pointer functions. * dtable.h (dtable::lock): New function. (dtable::unlock): New function. (dtable::init_lock): New function. * cygheap.h (HEAP_TLS): Declare new enum value. (init_cygheap::threadlist): Declare new array. (init_cygheap::sthreads): Declare new variable. (cygheap_fdmanip::~cygheap_fdmanip): Use new dtable lock/unlock functions. (cygheap_fdnew::cygheap_fdnew): Ditto. (cygheap_fdget::cygheap_fdget): Ditto. * dtable.cc (dtable_init): Initialize fdtab critical section. (dtable::fixup_after_fork): Ditto. (dtable::fixup_after_exec): Ditto. (dtable::dup2): Use lock/unlock calls to protect access to fdtab. (dtable::find_fifo): Ditto. (dtable::fixup_before_fork): Ditto. (dtable::fixup_before_exec): Ditto. (dtable::set_file_pointers_for_exec): Ditto. (dtable::vfork_child_dup): Ditto. (dtable::vfork_parent_restore): Ditto. * syscalls.cc (close_all_files): Ditto. * sync.h (muto::acquired): Declare new function. (new_muto1): Declare new macro used to specify name of muto storage. * sync.cc (muto::acquired): Define new function. * cygthread.cc (cygthread::stub): Remove signal chain removal call since it is handled during initialization now. * cygthread.cc (cygthread::simplestub): Remove signal chain removal call since it is handled during initialization now. * cygtls.cc (sentry): New class used for locking. Use throughout. (_threadinfo::reset_exception): Don't pop stack. (_threadinfo::find_tls): Move from exceptions.cc. (_threadinfo::init_thread): Initialize array of threads rather than linked list. Take second argument indicating thread function for this thread. (_threadinfo::remove): Search thread array rather than linked list. Use sentry to lock. Only unlock if we got the lock. (_threadinfo::find_tls): Ditto for first two. (handle_threadlist_exception): Handle exceptions when manipulating the thread list in case of premature thread termination. (_threadinfo::init_threadlist_exceptions): Ditto. * cygtls.h (TLS_STACK_SIZE): Decrease size. (_threadinfo::padding): Add element to avoid overwriting lower part of stack. (_threadinfo::remove): Add a "wait" argument to control how long we wait for a lock before removing. * exceptions.cc (init_exception_handler): Make global. Take argument to control exception handler being set. (ctrl_c_handler): Wait forever when removing self from signal chain. (_threadinfo::find_tls): Move to cygtls.cc. (sig_handle): Reorganize detection for thread-specific signals. * heap.cc (heap_init): Rework slightly. Make fatal error more verbose. Remove malloc initialization since it can't happen during dll attach. * init.cc (search_for): Move address to search for on stack here. (threadfunc_ix): Ditto for stack offset. Make shared so that stack walk potentially only has to be done once when cygwin processes are running. (threadfunc_fe): Use standard tls to store thread function (may change back later). (calibration_thread): New function. Potentially called to find threadfunc_ix. (munge_threadfunc): Search for "search_for" value on stack. Output warning when thread func not found on stack. Use standard tls to store thread function. (prime_threads): New function. Called to prime thread front end. (dll_entry): Call dll_crt0_0 here when DLL_PROCESS_ATTACH. Call prime_threads here. Try to remove thread from signal list here. * sigproc.cc (wait_sig): Initialize threadlist exception stuff here. * thread.cc (pthread::exit): Pass argument to signal list remove function. * thread.h: Remove obsolete *ResourceLock defines. * tlsoffsets.h: Regenerate. * winsup.h (spf): Define temporary debug macro to be deleted later. * dcrt0.cc (dll_crt0_0): New function, called during DLL initialization. Mainly consists of code pulled from dll_crt0_1. (dll_crt0_1): See above. (_dll_crt0): Wait for initial calibration thread to complete, if appropriate. Move some stuff to dll_crt0_0. (initialize_main_tls): Accommodate argument change to _thread_info::init_thread. * fork.cc (fork_child): Ditto. (sync_with_child): Fix debug message. * external.cc (cygwin_internal): Remove special considerations for uninitialized dll since initialization happens during dll attach now. * dlfcn.cc (dlopen): Remove obsolete *ResourceLock calls. (dlclose): Ditto. * cygheap.h (init_cygheap::close_ctty): Declare new function. * cygheap.cc (init_cygheap::close_ctty): Define new function. * syscalls.cc (close_all_files): Use close_ctty. (setsid): Ditto. * cygthread.cc (cygthread::stub): Remove exception initialization. * cygthread.cc (cygthread::stub): Remove exception initialization. (cygthread::simplestub): Ditto. * thread.cc (pthread::thread_init_wrapper): Ditto. * cygtls.cc (_last_thread): Make static. (_threadinfo::call2): Initialize exception handler here. (_threadinfo::find_tls): Move here. * exceptions.cc (_threadinfo::find_tls): Move. * dcrt0.cc (__api_fatal): Add prefix info to message here rather than including it in every call to function. * winsup.h (api_fatal): Accommodate above change. * debug.cc (add_handle): Don't do anything if cygheap not around. (mark_closed): Ditto. * dll_init.cc (dll_list::detach): Fix debug output. * fork.cc (sync_with_child): Ditto. (vfork): Improve debug output. * heap.cc (heap_init): Ditto. * exceptions.cc (try_to_debug): Clarify message when debugger attaches.
2004-01-14 23:45:37 +08:00
while (1)
{
if (!info->__name)
system_printf ("erroneous thread activation");
else
{
if (!info->func || exiting)
* cygthread.cc (cygthread::stub): Revert previous change and again subsume cygthread::stub2. Just return from function now since ExitThread is guaranteed by automatic _threadinfo wrapper. Define as per ThreadProc convention. (cygthread::stub2): Remove. (cygthread::simplestub): Perform similar operations to cygthread::stub. (cygthread::simplestub2): Remove. * cygthread.h (cygthread::stub): Declare as per ThreadProc convention. (cygthread::stub2): Remove declaration. (cygthread::simplestub): Declare as per ThreadProc convention. (cygthread::simplestub2): Remove declaration. * cygtls.h (_threadinfo::call): Define first argument as per ThreadProc convention. (_threadinfo::call2): Ditto. (_tlsbase): Define as char * pointer. (_tlstop): New definition. (_main_tls): Define here. * dcrt0.cc (alloc_stack): Revert previous change which called init_thread since information would be overwritten by fork later anyway. (dll_crt0_1): Use _tlsbase and _tlstop for setting stack bottom, top. * exceptions.cc: Move _main_tls declaration to cygtls.h. (_threadinfo::call): Define first argument as per ThreadProc convention. (_threadinfo::call2): Call ExitThread with thread function return value. (_threadinfo::init_thread): Don't initialize cygtls to zero if input arg is NULL. * fork.cc (fork_child): Reset _main_tls here. Reinitialize parts of _my_tls after copying data from parent. * init.cc (threadfunc_fe): New function. Front-end for all threads created in cygwin processes. (munge_threadfunc): New function. (dll_entry): Call munge_threadfunc to force the call of a thread wrapper. * thread.cc (pthread::thread_init_wrapper): Perform similar operations to cygthread::stub. (pthread::thread_init_wrapper2): Remove. * thread.h (pthread::thread_init_wrapper): Declare as per ThreadProc convention. (pthread::thread_init_wrapper2): Remove declaration. * window.cc (Winmain): Just return from function now since ExitThread is guaranteed by automatic _threadinfo wrapper.
2003-12-14 15:09:22 +08:00
return 0;
/* Cygwin threads should not call ExitThread directly */
info->func (info->arg == cygself ? info : info->arg);
/* ...so the above should always return */
#ifdef DEBUGGING
info->func = NULL; // catch erroneous activation
#endif
info->__name = NULL;
SetEvent (info->ev);
}
switch (WaitForSingleObject (info->thread_sync, INFINITE))
{
case WAIT_OBJECT_0:
continue;
default:
api_fatal ("WFSO failed, %E");
break;
}
}
}
/* Overflow stub called by cygthread constructor. Calls specified function
and then exits the thread. */
DWORD WINAPI
cygthread::simplestub (VOID *arg)
{
cygthread *info = (cygthread *) arg;
info->stack_ptr = &arg;
info->ev = info->h;
info->func (info->arg == cygself ? info : info->arg);
* cygthread.cc (cygthread::stub): Revert previous change and again subsume cygthread::stub2. Just return from function now since ExitThread is guaranteed by automatic _threadinfo wrapper. Define as per ThreadProc convention. (cygthread::stub2): Remove. (cygthread::simplestub): Perform similar operations to cygthread::stub. (cygthread::simplestub2): Remove. * cygthread.h (cygthread::stub): Declare as per ThreadProc convention. (cygthread::stub2): Remove declaration. (cygthread::simplestub): Declare as per ThreadProc convention. (cygthread::simplestub2): Remove declaration. * cygtls.h (_threadinfo::call): Define first argument as per ThreadProc convention. (_threadinfo::call2): Ditto. (_tlsbase): Define as char * pointer. (_tlstop): New definition. (_main_tls): Define here. * dcrt0.cc (alloc_stack): Revert previous change which called init_thread since information would be overwritten by fork later anyway. (dll_crt0_1): Use _tlsbase and _tlstop for setting stack bottom, top. * exceptions.cc: Move _main_tls declaration to cygtls.h. (_threadinfo::call): Define first argument as per ThreadProc convention. (_threadinfo::call2): Call ExitThread with thread function return value. (_threadinfo::init_thread): Don't initialize cygtls to zero if input arg is NULL. * fork.cc (fork_child): Reset _main_tls here. Reinitialize parts of _my_tls after copying data from parent. * init.cc (threadfunc_fe): New function. Front-end for all threads created in cygwin processes. (munge_threadfunc): New function. (dll_entry): Call munge_threadfunc to force the call of a thread wrapper. * thread.cc (pthread::thread_init_wrapper): Perform similar operations to cygthread::stub. (pthread::thread_init_wrapper2): Remove. * thread.h (pthread::thread_init_wrapper): Declare as per ThreadProc convention. (pthread::thread_init_wrapper2): Remove declaration. * window.cc (Winmain): Just return from function now since ExitThread is guaranteed by automatic _threadinfo wrapper.
2003-12-14 15:09:22 +08:00
return 0;
}
/* Start things going. Called from dll_crt0_1. */
void
cygthread::init ()
{
main_thread_id = GetCurrentThreadId ();
}
bool
cygthread::is ()
{
DWORD tid = GetCurrentThreadId ();
for (DWORD i = 0; i < NTHREADS; i++)
if (threads[i].id == tid)
return 1;
return 0;
}
cygthread *
cygthread::freerange ()
{
cygthread *self = (cygthread *) calloc (1, sizeof (*self));
self->is_freerange = true;
self->inuse = 1;
return self;
}
void * cygthread::operator
new (size_t)
{
cygthread *info;
/* Search the threads array for an empty slot to use */
for (info = threads; info < threads + NTHREADS; info++)
if (!InterlockedExchange (&info->inuse, 1))
{
/* available */
#ifdef DEBUGGING
if (info->__name)
api_fatal ("name not NULL? id %p, i %d", info->id, info - threads);
#endif
goto out;
}
#ifdef DEBUGGING
char buf[1024];
if (!GetEnvironmentVariable ("CYGWIN_FREERANGE_NOCHECK", buf, sizeof (buf)))
api_fatal ("Overflowed cygwin thread pool");
else
thread_printf ("Overflowed cygwin thread pool");
#endif
info = freerange (); /* exhausted thread pool */
out:
return info;
}
cygthread::cygthread (LPTHREAD_START_ROUTINE start, LPVOID param,
const char *name): __name (name),
func (start), arg (param)
{
thread_printf ("name %s, id %p", name, id);
if (h)
{
while (!thread_sync)
low_priority_sleep (0);
SetEvent (thread_sync);
thread_printf ("activated thread_sync %p", thread_sync);
}
else
{
stack_ptr = NULL;
h = CreateThread (&sec_none_nih, 0, is_freerange ? simplestub : stub,
this, 0, &id);
if (!h)
api_fatal ("thread handle not set - %p<%p>, %E", h, id);
thread_printf ("created thread %p", h);
}
}
/* Return the symbolic name of the current thread for debugging.
*/
const char *
cygthread::name (DWORD tid)
{
const char *res = NULL;
if (!tid)
tid = GetCurrentThreadId ();
if (tid == main_thread_id)
return "main";
for (DWORD i = 0; i < NTHREADS; i++)
if (threads[i].id == tid)
{
res = threads[i].__name ?: "exiting thread";
break;
}
if (!res)
{
static char buf[30] NO_COPY = {0};
__small_sprintf (buf, "unknown (%p)", tid);
res = buf;
}
return res;
}
cygthread::operator
HANDLE ()
{
while (!ev)
low_priority_sleep (0);
return ev;
}
/* Should only be called when the process is exiting since it
leaves an open thread slot. */
void
cygthread::exit_thread ()
{
if (!is_freerange)
SetEvent (*this);
ExitThread (0);
}
/* Forcibly terminate a thread. */
void
cygthread::terminate_thread ()
{
if (!is_freerange)
{
ResetEvent (*this);
ResetEvent (thread_sync);
}
(void) TerminateThread (h, 0);
(void) WaitForSingleObject (h, INFINITE);
CloseHandle (h);
while (!stack_ptr)
low_priority_sleep (0);
MEMORY_BASIC_INFORMATION m;
memset (&m, 0, sizeof (m));
(void) VirtualQuery (stack_ptr, &m, sizeof m);
if (!m.RegionSize)
system_printf ("m.RegionSize 0? stack_ptr %p", stack_ptr);
else if (!VirtualFree (m.AllocationBase, 0, MEM_RELEASE))
debug_printf ("VirtualFree of allocation base %p<%p> failed, %E",
stack_ptr, m.AllocationBase);
if (is_freerange)
free (this);
else
{
h = NULL;
__name = NULL;
stack_ptr = NULL;
(void) InterlockedExchange (&inuse, 0); /* No longer in use */
}
}
/* Detach the cygthread from the current thread. Note that the
theory is that cygthreads are only associated with one thread.
So, there should be never be multiple threads doing waits
on the same cygthread. */
bool
cygthread::detach (HANDLE sigwait)
{
bool signalled = false;
if (!inuse)
system_printf ("called detach but inuse %d, thread %p?", inuse, id);
else
{
DWORD res;
if (!sigwait)
res = WaitForSingleObject (*this, INFINITE);
else
{
HANDLE w4[2];
w4[0] = *this;
w4[1] = signal_arrived;
res = WaitForSingleObject (sigwait, INFINITE);
if (res != WAIT_OBJECT_0)
system_printf ("WFSO sigwait %p failed, res %u, %E", sigwait, res);
res = WaitForMultipleObjects (2, w4, FALSE, INFINITE);
if (res == WAIT_OBJECT_0)
/* nothing */;
else if (WaitForSingleObject (sigwait, 0) == WAIT_OBJECT_0)
res = WaitForSingleObject (*this, INFINITE);
else if ((res = WaitForSingleObject (*this, 0)) != WAIT_OBJECT_0)
{
signalled = true;
terminate_thread ();
set_sig_errno (EINTR); /* caller should be dealing with return
values. */
}
}
thread_printf ("%s returns %d, id %p", sigwait ? "WFMO" : "WFSO",
res, id);
if (signalled)
/* already handled */;
else if (is_freerange)
{
CloseHandle (h);
free (this);
}
else
{
ResetEvent (*this);
/* Mark the thread as available by setting inuse to zero */
(void) InterlockedExchange (&inuse, 0);
}
}
return signalled;
}
void
cygthread::terminate ()
{
exiting = 1;
}