newlib-cygwin/winsup/cygwin/cygthread.cc

511 lines
11 KiB
C++
Raw Normal View History

/* cygthread.cc
2010-08-20 23:28:28 +08:00
Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2008,
2009, 2010, 2011 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 "miscfuncs.h"
#include <stdlib.h>
#include "sigproc.h"
#include "cygtls.h"
#include "ntdll.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;
void
cygthread::callfunc (bool issimplestub)
{
void *pass_arg;
if (arg == cygself)
pass_arg = this;
else if (!arglen)
pass_arg = arg;
else
{
if (issimplestub)
ev = CreateEvent (&sec_none_nih, TRUE, FALSE, NULL);
pass_arg = alloca (arglen);
memcpy (pass_arg, arg, arglen);
SetEvent (ev);
}
if (issimplestub)
{
/* Wait for main thread to assign 'h' */
while (!h)
yield ();
if (ev)
CloseHandle (ev);
ev = h;
}
/* Cygwin threads should not call ExitThread directly */
func (pass_arg);
/* ...so the above should always return */
}
/* Initial stub called by cygthread constructor. Performs initial
* wininfo.h (wininfo::timer_active): Delete. (wininfo::itv): Ditto. (wininfo::start_time): Ditto. (wininfo::window_started): Ditto. (wininfo::getitimer): Ditto. (wininfo::setitimer): Ditto. (wininfo::wininfo): Ditto. (wininfo::lock): New method. (wininfo::release): Ditto. * window.cc: Use new lock/acquire wininfo methods throughout. (wininfo::wininfo): Delete (wininfo::getitimer): Ditto. (wininfo::setitimer): Ditto. (getitimer): Ditto. (setitimer): Ditto. (ualarm): Ditto. (alarm): Ditto. (wininfo::lock): Define new function. (wininfo::release): Ditto. (wininfo::process): Delete WM_TIMER handling. * timer.cc (struct timetracker): Delete it, flags. Add it_interval, interval_us, sleepto_us, running, init_muto(), syncthread, and gettime(). (ttstart): Make NO_COPY. (lock_timer_tracker): New class. (timer_tracker::timer_tracker): Distinguish ttstart case. (timer_tracker::~timer_tracker): New destructor. Clean out events, and reset magic. (timer_tracker::init_muto): New method. (to_us): Round up as per POSIX. (timer_thread): Reorganize to match timer_tracker::settime and timer_tracker::gettime. Call sig_send without wait. Call auto_release. (timer_tracker::settime): Reorganize logic to avoid race. Call gettime to recover old value. (timer_tracker::gettime): New method. (timer_create): Properly set errno on invalid timerid. Use new lock_timer_tracker method. (timer_delete): Ditto. Simplify code slightly. (timer_gettime): New function. (fixup_timers_after_fork): Reinit ttstart. (getitimer): New implementation. (setitimer): Ditto. (ualarm): Ditto. (alarm): Ditto. * cygwin.din: Export timer_gettime. * winsup.h: Remove has has_visible_window_station declaration. * Makefile.in (DLL_OFILES): Add lsearch.o. * cygthread.h (cygthread::notify_detached): New element. (cygthread::cygthread): Take optional fourth argument signifying event to signal on thread completion. * cygthread.cc (cygthread::stub): Signal notify_detached event, if it exists. (cygthread::cygthread): Initialize notify_detached from fourth argument. (cygthread::detach): Wait for notify_detached field is present. * lsearch.cc: New file. * search.h: Ditto. * include/cygwin/version.h: Bump API minor number to 126. * cygwin.din: Export lsearch, lfind.
2005-03-27 09:57:38 +08:00
per-thread initialization and loops waiting for another thread function
to execute. */
DWORD WINAPI
cygthread::stub (VOID *arg)
{
cygthread *info = (cygthread *) arg;
* child_info.h (child_info_spawn::hexec_proc): Eliminate. * dcrt0.cc (dll_crt0_0): Remove hexec_proc stuff. * fork.cc (fork_child): Remove call to pinfo_fixup_after_fork. * pinfo.cc (set_myself): Close and zero pid_handle if set. (pinfo_fixup_after_fork): Delete. (proc_waiter): Don't close vchild.hProcess here. Do that when we are remove the vchild from procs. Save hProcess as pid_handle only on first reparent operation. (pinfo::wait): Don't set pid_handle here. (pinfo::alert_parent): Always try to send signal. If unsuccessful then close and zero wr_proc_pipe. * pinfo.h (pinfo::pinfo): Make sure that appropriate parts of the class are zeroed on construction. (pinfo::alert_parent): Take char argument. (pinfo_fixup_after_fork): Delete declaration. (hexec_proc): Ditto. * sigproc.cc (remove_proc): Close pid_handle and hProcess if appropriate. * spawn.cc (spawn_guts): Set cygheap->pid_handle on first exec. * cygheap.h (init_cygheap::pid_handle): New element. * pinfo.cc (set_myself): Clear previously existing cygheap->pid_handle when a new process has been started. (pinfo::wait): Make sure that a handle to the newly forked/spawned process is kept around so that the pid will not be reused. * pinfo.h (_pinfo::pid_handle): Move. (pinfo::pid_handle): to here. * spawn.cc (spawn_guts): Create a pid_handle in cygheap prior to spawning to ensure that the pid does not get reused during the lifetime of the "cygwin pid". * pinfo.h (pinfo::alert_parent): New function. * exceptions.cc (sig_handle_tty_stop): Use alert_parent to send "signals" to parent. * fork.cc (fork_parent): Don't close pi.hProcess. Let the waiter thread do that. * pinfo.cc (proc_waiter): Detect case where process exits without setting the exit code and use value from GetExitCodeProcess. Reluctantly implement __SIGREPARENT. (pinfo::alert_parent): Define. * sigproc.h (__SIGREPARENT): New enum. * spawn.cc (spawn_guts): Send reparent signal to parent on exec. Always create process in suspended state to avoid races. Remove cygthread.h in favor of cygtls.h throughout since cygtls now includes cygthread.h. Eliminate ppid_handle usage throughout. * child_info.h: Regenerate magic number (child_info): Remove pppid_handle. * cygthread.h (cygthread::release): New method. Frees thread without waiting. * cygthread.cc (cygthread::stub): Set _ctinfo in _mytls to point to information for executing thread. Don't call SetEvent if thread is no longer in use. (cygthread::simplestub): Ditto. * cygtls.h (_cygtls::_ctinfo): New element contains pointer to information about executing cygthread, if any. * dcrt0.cc: Remove last vestiges of per_thread stuff. (dll_crt0_0): Ditto. Remove accommodation for ppid_handle. (do_exit): Remove obsolete reparenting test. (_exit): Exit with a more SUSv3-like exit value. * dtable.cc (dtable::stdio_init): Check for myself->cygstarted rather than myself->ppid_handle to see if we were started by a cygwin process. * exceptions.cc (open_stackdumpfile): Ditto. (handle_exceptions): Ditto. (ctrl_c_handler): Ditto. (sig_handle_tty_stop): Ditto. Let parent send signal to itself on STOP. (sigpacket::process): Comment out vfork test. (signal_exit): Use more SUSv3-like exit value on signal. * external.cc (fillout_pinfo): Don't set hProcess. * fork.cc: Remove VFORK cruft. (per_thread::set): Delete. (fork_child): Remove perthread stuff. (fork_parent): Remove obsolete subproc_init. Accommodate new method for tracking subprocesses. * pinfo.cc (set_myself): Accommodate new pinfo/_pinfo layout. Set some things here that used to be set in wait_sig. (_pinfo::exit): Set exitcode here. Close process pipe. (_pinfo::commune_send): Accommodeate new pinfo/_pinfo layout. (proc_waiter): New function. Waits, in a thread for subprocess to go away. (pinfo::wait): New function. Initialization for proc_waiter. * pinfo.h (_pinfo::exitcode): New element. (_pinfo::cygstarted): Ditto. (_pinfo::wr_proc_pipe): Ditto. (_pinfo::ppid_handle): Delete. (_pinfo::hProcess): Delete. (_pinfo::lock): Delete. (pinfo::hProcess): New element. (pinfo::lock): Ditto. (pinfo::wait): Declare new function. (pinfo::preserve): Define new function. * sigproc.cc: Remove old stuff from wait_subproc thread based method. (zombies): Remove. (procs): New. (my_parent_is_alive): Just check that the parent pid exists. (mychild): Just use pinfo methods to determine if child is mine. (proc_subproc): Revamp PROC_ADDCHILD to use pinfo::wait. Remove PROC_CHILDTERMINATED logic. Use different method to remove processes from list when SIGCHLD == SIG_IGN. (proc_terminate): Gut. (subproc_init): Delete. (init_child_info): Remove setting of pppid_handle. (checkstate): Revamp to only scan procs array. (remove_proc): Rename from remove_zombie. Don't close hProcess or pid_handle. Don't release memory if it's myself. (stopped_or_terminated): Change logic to handle new consolidated proc/zombie array. (wait_subproc): Delete. * sigproc.h: Remove obsolete EXIT_* defines. (subproc_init): Remove declaration. * spawn.cc (spawn_guts): Remove reparenting stuff. Use standard wait logic to wait for child if started from a non-cygwin process. * tlsoffsets.h: Regenerate. * tty.cc (tty_init): Check for myself->cygstarted rather than myself->ppid_handle to see if we were started by a cygwin process. * include/sys/signal.h (external_pinfo::exitcode): Replace hProcess. * include/sys/wait.h (WCOREDUMP): Define. * fhandler_tty.cc (fhandler_tty_slave::read): Add debugging output for timeout case. * signal.cc (abort): Flag that we are exiting with the ABORT signal.
2004-11-26 12:15:10 +08:00
_my_tls._ctinfo = info;
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;
debug_printf ("thread '%s', id %p, stack_ptr %p", info->name (), info->id, info->stack_ptr);
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)
#ifdef DEBUGGING
system_printf ("erroneous thread activation, name is NULL prev thread name = '%s'", info->__oldname);
#else
system_printf ("erroneous thread activation, name is NULL");
#endif
else
{
if (exiting)
{
info->inuse = false; // FIXME: Do we need this?
return 0;
}
info->callfunc (false);
* wininfo.h (wininfo::timer_active): Delete. (wininfo::itv): Ditto. (wininfo::start_time): Ditto. (wininfo::window_started): Ditto. (wininfo::getitimer): Ditto. (wininfo::setitimer): Ditto. (wininfo::wininfo): Ditto. (wininfo::lock): New method. (wininfo::release): Ditto. * window.cc: Use new lock/acquire wininfo methods throughout. (wininfo::wininfo): Delete (wininfo::getitimer): Ditto. (wininfo::setitimer): Ditto. (getitimer): Ditto. (setitimer): Ditto. (ualarm): Ditto. (alarm): Ditto. (wininfo::lock): Define new function. (wininfo::release): Ditto. (wininfo::process): Delete WM_TIMER handling. * timer.cc (struct timetracker): Delete it, flags. Add it_interval, interval_us, sleepto_us, running, init_muto(), syncthread, and gettime(). (ttstart): Make NO_COPY. (lock_timer_tracker): New class. (timer_tracker::timer_tracker): Distinguish ttstart case. (timer_tracker::~timer_tracker): New destructor. Clean out events, and reset magic. (timer_tracker::init_muto): New method. (to_us): Round up as per POSIX. (timer_thread): Reorganize to match timer_tracker::settime and timer_tracker::gettime. Call sig_send without wait. Call auto_release. (timer_tracker::settime): Reorganize logic to avoid race. Call gettime to recover old value. (timer_tracker::gettime): New method. (timer_create): Properly set errno on invalid timerid. Use new lock_timer_tracker method. (timer_delete): Ditto. Simplify code slightly. (timer_gettime): New function. (fixup_timers_after_fork): Reinit ttstart. (getitimer): New implementation. (setitimer): Ditto. (ualarm): Ditto. (alarm): Ditto. * cygwin.din: Export timer_gettime. * winsup.h: Remove has has_visible_window_station declaration. * Makefile.in (DLL_OFILES): Add lsearch.o. * cygthread.h (cygthread::notify_detached): New element. (cygthread::cygthread): Take optional fourth argument signifying event to signal on thread completion. * cygthread.cc (cygthread::stub): Signal notify_detached event, if it exists. (cygthread::cygthread): Initialize notify_detached from fourth argument. (cygthread::detach): Wait for notify_detached field is present. * lsearch.cc: New file. * search.h: Ditto. * include/cygwin/version.h: Bump API minor number to 126. * cygwin.din: Export lsearch, lfind.
2005-03-27 09:57:38 +08:00
HANDLE notify = info->notify_detached;
/* If func is NULL, the above function has set that to indicate
that it doesn't want to alert anyone with a SetEvent and should
just be marked as no longer inuse. Hopefully the function knows
* wininfo.h (wininfo::timer_active): Delete. (wininfo::itv): Ditto. (wininfo::start_time): Ditto. (wininfo::window_started): Ditto. (wininfo::getitimer): Ditto. (wininfo::setitimer): Ditto. (wininfo::wininfo): Ditto. (wininfo::lock): New method. (wininfo::release): Ditto. * window.cc: Use new lock/acquire wininfo methods throughout. (wininfo::wininfo): Delete (wininfo::getitimer): Ditto. (wininfo::setitimer): Ditto. (getitimer): Ditto. (setitimer): Ditto. (ualarm): Ditto. (alarm): Ditto. (wininfo::lock): Define new function. (wininfo::release): Ditto. (wininfo::process): Delete WM_TIMER handling. * timer.cc (struct timetracker): Delete it, flags. Add it_interval, interval_us, sleepto_us, running, init_muto(), syncthread, and gettime(). (ttstart): Make NO_COPY. (lock_timer_tracker): New class. (timer_tracker::timer_tracker): Distinguish ttstart case. (timer_tracker::~timer_tracker): New destructor. Clean out events, and reset magic. (timer_tracker::init_muto): New method. (to_us): Round up as per POSIX. (timer_thread): Reorganize to match timer_tracker::settime and timer_tracker::gettime. Call sig_send without wait. Call auto_release. (timer_tracker::settime): Reorganize logic to avoid race. Call gettime to recover old value. (timer_tracker::gettime): New method. (timer_create): Properly set errno on invalid timerid. Use new lock_timer_tracker method. (timer_delete): Ditto. Simplify code slightly. (timer_gettime): New function. (fixup_timers_after_fork): Reinit ttstart. (getitimer): New implementation. (setitimer): Ditto. (ualarm): Ditto. (alarm): Ditto. * cygwin.din: Export timer_gettime. * winsup.h: Remove has has_visible_window_station declaration. * Makefile.in (DLL_OFILES): Add lsearch.o. * cygthread.h (cygthread::notify_detached): New element. (cygthread::cygthread): Take optional fourth argument signifying event to signal on thread completion. * cygthread.cc (cygthread::stub): Signal notify_detached event, if it exists. (cygthread::cygthread): Initialize notify_detached from fourth argument. (cygthread::detach): Wait for notify_detached field is present. * lsearch.cc: New file. * search.h: Ditto. * include/cygwin/version.h: Bump API minor number to 126. * cygwin.din: Export lsearch, lfind.
2005-03-27 09:57:38 +08:00
what it is doing. */
if (!info->func)
info->release (false);
else
{
#ifdef DEBUGGING
info->func = NULL; // catch erroneous activation
info->__oldname = info->__name;
#endif
info->__name = NULL;
SetEvent (info->ev);
}
* wininfo.h (wininfo::timer_active): Delete. (wininfo::itv): Ditto. (wininfo::start_time): Ditto. (wininfo::window_started): Ditto. (wininfo::getitimer): Ditto. (wininfo::setitimer): Ditto. (wininfo::wininfo): Ditto. (wininfo::lock): New method. (wininfo::release): Ditto. * window.cc: Use new lock/acquire wininfo methods throughout. (wininfo::wininfo): Delete (wininfo::getitimer): Ditto. (wininfo::setitimer): Ditto. (getitimer): Ditto. (setitimer): Ditto. (ualarm): Ditto. (alarm): Ditto. (wininfo::lock): Define new function. (wininfo::release): Ditto. (wininfo::process): Delete WM_TIMER handling. * timer.cc (struct timetracker): Delete it, flags. Add it_interval, interval_us, sleepto_us, running, init_muto(), syncthread, and gettime(). (ttstart): Make NO_COPY. (lock_timer_tracker): New class. (timer_tracker::timer_tracker): Distinguish ttstart case. (timer_tracker::~timer_tracker): New destructor. Clean out events, and reset magic. (timer_tracker::init_muto): New method. (to_us): Round up as per POSIX. (timer_thread): Reorganize to match timer_tracker::settime and timer_tracker::gettime. Call sig_send without wait. Call auto_release. (timer_tracker::settime): Reorganize logic to avoid race. Call gettime to recover old value. (timer_tracker::gettime): New method. (timer_create): Properly set errno on invalid timerid. Use new lock_timer_tracker method. (timer_delete): Ditto. Simplify code slightly. (timer_gettime): New function. (fixup_timers_after_fork): Reinit ttstart. (getitimer): New implementation. (setitimer): Ditto. (ualarm): Ditto. (alarm): Ditto. * cygwin.din: Export timer_gettime. * winsup.h: Remove has has_visible_window_station declaration. * Makefile.in (DLL_OFILES): Add lsearch.o. * cygthread.h (cygthread::notify_detached): New element. (cygthread::cygthread): Take optional fourth argument signifying event to signal on thread completion. * cygthread.cc (cygthread::stub): Signal notify_detached event, if it exists. (cygthread::cygthread): Initialize notify_detached from fourth argument. (cygthread::detach): Wait for notify_detached field is present. * lsearch.cc: New file. * search.h: Ditto. * include/cygwin/version.h: Bump API minor number to 126. * cygwin.din: Export lsearch, lfind.
2005-03-27 09:57:38 +08:00
if (notify)
SetEvent (notify);
}
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;
* child_info.h (child_info_spawn::hexec_proc): Eliminate. * dcrt0.cc (dll_crt0_0): Remove hexec_proc stuff. * fork.cc (fork_child): Remove call to pinfo_fixup_after_fork. * pinfo.cc (set_myself): Close and zero pid_handle if set. (pinfo_fixup_after_fork): Delete. (proc_waiter): Don't close vchild.hProcess here. Do that when we are remove the vchild from procs. Save hProcess as pid_handle only on first reparent operation. (pinfo::wait): Don't set pid_handle here. (pinfo::alert_parent): Always try to send signal. If unsuccessful then close and zero wr_proc_pipe. * pinfo.h (pinfo::pinfo): Make sure that appropriate parts of the class are zeroed on construction. (pinfo::alert_parent): Take char argument. (pinfo_fixup_after_fork): Delete declaration. (hexec_proc): Ditto. * sigproc.cc (remove_proc): Close pid_handle and hProcess if appropriate. * spawn.cc (spawn_guts): Set cygheap->pid_handle on first exec. * cygheap.h (init_cygheap::pid_handle): New element. * pinfo.cc (set_myself): Clear previously existing cygheap->pid_handle when a new process has been started. (pinfo::wait): Make sure that a handle to the newly forked/spawned process is kept around so that the pid will not be reused. * pinfo.h (_pinfo::pid_handle): Move. (pinfo::pid_handle): to here. * spawn.cc (spawn_guts): Create a pid_handle in cygheap prior to spawning to ensure that the pid does not get reused during the lifetime of the "cygwin pid". * pinfo.h (pinfo::alert_parent): New function. * exceptions.cc (sig_handle_tty_stop): Use alert_parent to send "signals" to parent. * fork.cc (fork_parent): Don't close pi.hProcess. Let the waiter thread do that. * pinfo.cc (proc_waiter): Detect case where process exits without setting the exit code and use value from GetExitCodeProcess. Reluctantly implement __SIGREPARENT. (pinfo::alert_parent): Define. * sigproc.h (__SIGREPARENT): New enum. * spawn.cc (spawn_guts): Send reparent signal to parent on exec. Always create process in suspended state to avoid races. Remove cygthread.h in favor of cygtls.h throughout since cygtls now includes cygthread.h. Eliminate ppid_handle usage throughout. * child_info.h: Regenerate magic number (child_info): Remove pppid_handle. * cygthread.h (cygthread::release): New method. Frees thread without waiting. * cygthread.cc (cygthread::stub): Set _ctinfo in _mytls to point to information for executing thread. Don't call SetEvent if thread is no longer in use. (cygthread::simplestub): Ditto. * cygtls.h (_cygtls::_ctinfo): New element contains pointer to information about executing cygthread, if any. * dcrt0.cc: Remove last vestiges of per_thread stuff. (dll_crt0_0): Ditto. Remove accommodation for ppid_handle. (do_exit): Remove obsolete reparenting test. (_exit): Exit with a more SUSv3-like exit value. * dtable.cc (dtable::stdio_init): Check for myself->cygstarted rather than myself->ppid_handle to see if we were started by a cygwin process. * exceptions.cc (open_stackdumpfile): Ditto. (handle_exceptions): Ditto. (ctrl_c_handler): Ditto. (sig_handle_tty_stop): Ditto. Let parent send signal to itself on STOP. (sigpacket::process): Comment out vfork test. (signal_exit): Use more SUSv3-like exit value on signal. * external.cc (fillout_pinfo): Don't set hProcess. * fork.cc: Remove VFORK cruft. (per_thread::set): Delete. (fork_child): Remove perthread stuff. (fork_parent): Remove obsolete subproc_init. Accommodate new method for tracking subprocesses. * pinfo.cc (set_myself): Accommodate new pinfo/_pinfo layout. Set some things here that used to be set in wait_sig. (_pinfo::exit): Set exitcode here. Close process pipe. (_pinfo::commune_send): Accommodeate new pinfo/_pinfo layout. (proc_waiter): New function. Waits, in a thread for subprocess to go away. (pinfo::wait): New function. Initialization for proc_waiter. * pinfo.h (_pinfo::exitcode): New element. (_pinfo::cygstarted): Ditto. (_pinfo::wr_proc_pipe): Ditto. (_pinfo::ppid_handle): Delete. (_pinfo::hProcess): Delete. (_pinfo::lock): Delete. (pinfo::hProcess): New element. (pinfo::lock): Ditto. (pinfo::wait): Declare new function. (pinfo::preserve): Define new function. * sigproc.cc: Remove old stuff from wait_subproc thread based method. (zombies): Remove. (procs): New. (my_parent_is_alive): Just check that the parent pid exists. (mychild): Just use pinfo methods to determine if child is mine. (proc_subproc): Revamp PROC_ADDCHILD to use pinfo::wait. Remove PROC_CHILDTERMINATED logic. Use different method to remove processes from list when SIGCHLD == SIG_IGN. (proc_terminate): Gut. (subproc_init): Delete. (init_child_info): Remove setting of pppid_handle. (checkstate): Revamp to only scan procs array. (remove_proc): Rename from remove_zombie. Don't close hProcess or pid_handle. Don't release memory if it's myself. (stopped_or_terminated): Change logic to handle new consolidated proc/zombie array. (wait_subproc): Delete. * sigproc.h: Remove obsolete EXIT_* defines. (subproc_init): Remove declaration. * spawn.cc (spawn_guts): Remove reparenting stuff. Use standard wait logic to wait for child if started from a non-cygwin process. * tlsoffsets.h: Regenerate. * tty.cc (tty_init): Check for myself->cygstarted rather than myself->ppid_handle to see if we were started by a cygwin process. * include/sys/signal.h (external_pinfo::exitcode): Replace hProcess. * include/sys/wait.h (WCOREDUMP): Define. * fhandler_tty.cc (fhandler_tty_slave::read): Add debugging output for timeout case. * signal.cc (abort): Flag that we are exiting with the ABORT signal.
2004-11-26 12:15:10 +08:00
_my_tls._ctinfo = info;
info->stack_ptr = &arg;
info->callfunc (true);
* 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 ();
}
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? %s, id %p, i %d", info->__name, info->id, info - threads);
#endif
goto out;
}
#ifdef DEBUGGING
if (!getenv ("CYGWIN_FREERANGE_NOCHECK"))
api_fatal ("overflowed cygwin thread pool");
else
thread_printf ("overflowed cygwin thread pool");
#endif
info = freerange (); /* exhausted thread pool */
out:
return info;
}
void
cygthread::create ()
{
thread_printf ("name %s, id %p, this %p", __name, id, this);
HANDLE htobe;
if (h)
{
if (ev)
ResetEvent (ev);
while (!thread_sync)
yield ();
SetEvent (thread_sync);
thread_printf ("activated name '%s', thread_sync %p for id %p", __name, thread_sync, id);
htobe = h;
}
else
{
stack_ptr = NULL;
htobe = CreateThread (&sec_none_nih, 0, is_freerange ? simplestub : stub,
this, 0, &id);
if (!htobe)
api_fatal ("CreateThread failed for %s - %p<%p>, %E", __name, h, id);
thread_printf ("created name '%s', thread %p, id %p", __name, h, id);
#ifdef DEBUGGING
terminated = false;
#endif
}
if (arglen)
{
while (!ev)
yield ();
WaitForSingleObject (ev, INFINITE);
ResetEvent (ev);
}
h = htobe;
}
/* 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)
{
__small_sprintf (_my_tls.locals.unknown_thread_name, "unknown (%p)", tid);
res = _my_tls.locals.unknown_thread_name;
}
return res;
}
cygthread::operator
HANDLE ()
{
while (!ev)
yield ();
return ev;
}
void
cygthread::release (bool nuke_h)
{
if (nuke_h)
h = NULL;
#ifdef DEBUGGING
__oldname = __name;
debug_printf ("released thread '%s'", __oldname);
#endif
__name = NULL;
func = NULL;
/* Must be last */
if (!InterlockedExchange (&inuse, 0))
#ifdef DEBUGGING
api_fatal ("released a thread that was not inuse");
#else
system_printf ("released a thread that was not inuse");
#endif
}
/* Forcibly terminate a thread. */
bool
cygthread::terminate_thread ()
{
bool terminated = true;
debug_printf ("thread '%s', id %p, inuse %d, stack_ptr %p", __name, id, inuse, stack_ptr);
while (inuse && !stack_ptr)
yield ();
if (!inuse)
goto force_notterminated;
2005-02-14 02:17:29 +08:00
TerminateThread (h, 0);
WaitForSingleObject (h, INFINITE);
CloseHandle (h);
if (!inuse || exiting)
goto force_notterminated;
if (ev && !(terminated = !IsEventSignalled (ev)))
ResetEvent (ev);
MEMORY_BASIC_INFORMATION m;
memset (&m, 0, sizeof (m));
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
{
#ifdef DEBUGGING
terminated = true;
#endif
release (true);
}
2005-02-14 02:17:29 +08:00
goto out;
force_notterminated:
terminated = false;
out:
return terminated;
}
/* 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;
bool thread_was_reset = false;
if (!inuse)
system_printf ("called detach but inuse %d, thread %p?", inuse, id);
else
{
DWORD res;
if (!sigwait)
* wininfo.h (wininfo::timer_active): Delete. (wininfo::itv): Ditto. (wininfo::start_time): Ditto. (wininfo::window_started): Ditto. (wininfo::getitimer): Ditto. (wininfo::setitimer): Ditto. (wininfo::wininfo): Ditto. (wininfo::lock): New method. (wininfo::release): Ditto. * window.cc: Use new lock/acquire wininfo methods throughout. (wininfo::wininfo): Delete (wininfo::getitimer): Ditto. (wininfo::setitimer): Ditto. (getitimer): Ditto. (setitimer): Ditto. (ualarm): Ditto. (alarm): Ditto. (wininfo::lock): Define new function. (wininfo::release): Ditto. (wininfo::process): Delete WM_TIMER handling. * timer.cc (struct timetracker): Delete it, flags. Add it_interval, interval_us, sleepto_us, running, init_muto(), syncthread, and gettime(). (ttstart): Make NO_COPY. (lock_timer_tracker): New class. (timer_tracker::timer_tracker): Distinguish ttstart case. (timer_tracker::~timer_tracker): New destructor. Clean out events, and reset magic. (timer_tracker::init_muto): New method. (to_us): Round up as per POSIX. (timer_thread): Reorganize to match timer_tracker::settime and timer_tracker::gettime. Call sig_send without wait. Call auto_release. (timer_tracker::settime): Reorganize logic to avoid race. Call gettime to recover old value. (timer_tracker::gettime): New method. (timer_create): Properly set errno on invalid timerid. Use new lock_timer_tracker method. (timer_delete): Ditto. Simplify code slightly. (timer_gettime): New function. (fixup_timers_after_fork): Reinit ttstart. (getitimer): New implementation. (setitimer): Ditto. (ualarm): Ditto. (alarm): Ditto. * cygwin.din: Export timer_gettime. * winsup.h: Remove has has_visible_window_station declaration. * Makefile.in (DLL_OFILES): Add lsearch.o. * cygthread.h (cygthread::notify_detached): New element. (cygthread::cygthread): Take optional fourth argument signifying event to signal on thread completion. * cygthread.cc (cygthread::stub): Signal notify_detached event, if it exists. (cygthread::cygthread): Initialize notify_detached from fourth argument. (cygthread::detach): Wait for notify_detached field is present. * lsearch.cc: New file. * search.h: Ditto. * include/cygwin/version.h: Bump API minor number to 126. * cygwin.din: Export lsearch, lfind.
2005-03-27 09:57:38 +08:00
/* If the caller specified a special handle for notification, wait for that.
This assumes that the thread in question is auto releasing. */
res = WaitForSingleObject (*this, INFINITE);
else
{
/* Lower our priority and give priority to the read thread */
HANDLE hth = GetCurrentThread ();
LONG prio = GetThreadPriority (hth);
::SetThreadPriority (hth, THREAD_PRIORITY_BELOW_NORMAL);
HANDLE w4[2];
unsigned n = 2;
DWORD howlong = INFINITE;
w4[0] = sigwait;
w4[1] = signal_arrived;
/* For a description of the below loop see the end of this file */
for (int i = 0; i < 2; i++)
switch (res = WaitForMultipleObjects (n, w4, FALSE, howlong))
{
case WAIT_OBJECT_0:
if (n == 1)
howlong = 50;
break;
case WAIT_OBJECT_0 + 1:
n = 1;
if (i--)
howlong = 50;
break;
case WAIT_TIMEOUT:
break;
default:
if (!exiting)
{
system_printf ("WFMO failed waiting for cygthread '%s', %E", __name);
for (unsigned j = 0; j < n; j++)
switch (WaitForSingleObject (w4[j], 0))
{
case WAIT_OBJECT_0:
case WAIT_TIMEOUT:
break;
default:
system_printf ("%s handle %p is bad", (j ? "signal_arrived" : "semaphore"), w4[j]);
break;
}
api_fatal ("exiting on fatal error");
}
break;
}
/* WAIT_OBJECT_0 means that the thread successfully read something,
so wait for the cygthread to "terminate". */
if (res == WAIT_OBJECT_0)
WaitForSingleObject (*this, INFINITE);
else
{
/* Thread didn't terminate on its own, so maybe we have to
do it. */
signalled = terminate_thread ();
/* Possibly the thread completed *just* before it was
terminated. Detect this. If this happened then the
read was not terminated on a signal. */
if (WaitForSingleObject (sigwait, 0) == WAIT_OBJECT_0)
signalled = false;
if (signalled)
set_sig_errno (EINTR);
thread_was_reset = true;
}
::SetThreadPriority (hth, prio);
}
thread_printf ("%s returns %d, id %p", sigwait ? "WFMO" : "WFSO",
res, id);
if (thread_was_reset)
/* already handled */;
else if (is_freerange)
{
CloseHandle (h);
free (this);
}
else
{
ResetEvent (*this);
/* Mark the thread as available by setting inuse to zero */
InterlockedExchange (&inuse, 0);
}
}
return signalled;
}
void
cygthread::terminate ()
{
exiting = 1;
}
/* The below is an explanation of synchronization loop in cygthread::detach.
The intent is that the loop will always try hard to wait for both
synchronization events from the reader thread but will exit with
res == WAIT_TIMEOUT if a signal occurred and the reader thread is
still blocked.
case 0 - no signal
i == 0 (howlong == INFINITE)
W0 activated
howlong not set because n != 1
just loop
i == 1 (howlong == INFINITE)
W0 activated
howlong not set because n != 1
just loop (to exit loop) - no signal
i == 2 (howlong == INFINITE)
exit loop
case 1 - signal before thread initialized
i == 0 (howlong == INFINITE)
WO + 1 activated
n set to 1
howlong untouched because i-- == 0
loop
i == 0 (howlong == INFINITE)
W0 must be activated
howlong set to 50 because n == 1
i == 1 (howlong == 50)
W0 activated
loop (to exit loop) - no signal
WAIT_TIMEOUT activated
signal potentially detected
loop (to exit loop)
i == 2 (howlong == 50)
exit loop
case 2 - signal after thread initialized
i == 0 (howlong == INFINITE)
W0 activated
howlong not set because n != 1
loop
i == 1 (howlong == INFINITE)
W0 + 1 activated
n set to 1
howlong set to 50 because i-- != 0
loop
i == 1 (howlong == 50)
W0 activated
loop (to exit loop) - no signal
WAIT_TIMEOUT activated
loop (to exit loop) - signal
i == 2 (howlong == 50)
exit loop
*/