f6936c48f3
* 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.
224 lines
5.2 KiB
C++
224 lines
5.2 KiB
C++
/* cygtls.cc
|
|
|
|
Copyright 2003, 2004 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 "thread.h"
|
|
#include "cygtls.h"
|
|
#include "assert.h"
|
|
#include <syslog.h>
|
|
#include <signal.h>
|
|
#include "exceptions.h"
|
|
#include "sync.h"
|
|
#include "cygerrno.h"
|
|
#include "path.h"
|
|
#include "fhandler.h"
|
|
#include "dtable.h"
|
|
#include "cygheap.h"
|
|
#include "cygthread.h"
|
|
#include "sigproc.h"
|
|
|
|
class sentry
|
|
{
|
|
static muto *lock;
|
|
int destroy;
|
|
public:
|
|
void init ();
|
|
bool acquired () {return lock->acquired ();}
|
|
sentry () {destroy = 0;}
|
|
sentry (DWORD wait) {destroy = lock->acquire (wait);}
|
|
~sentry () {if (destroy) lock->release ();}
|
|
friend void _threadinfo::init ();
|
|
};
|
|
|
|
muto NO_COPY *sentry::lock;
|
|
|
|
static size_t NO_COPY nthreads;
|
|
|
|
#define THREADLIST_CHUNK 256
|
|
|
|
void
|
|
_threadinfo::init ()
|
|
{
|
|
if (cygheap->threadlist)
|
|
memset (cygheap->threadlist, 0, cygheap->sthreads * sizeof (cygheap->threadlist[0]));
|
|
else
|
|
{
|
|
cygheap->sthreads = THREADLIST_CHUNK;
|
|
cygheap->threadlist = (_threadinfo **) ccalloc (HEAP_TLS, cygheap->sthreads,
|
|
sizeof (cygheap->threadlist[0]));
|
|
}
|
|
new_muto1 (sentry::lock, sentry_lock);
|
|
}
|
|
|
|
void
|
|
_threadinfo::set_state (bool is_exception)
|
|
{
|
|
initialized = CYGTLS_INITIALIZED + is_exception;
|
|
}
|
|
|
|
void
|
|
_threadinfo::reset_exception ()
|
|
{
|
|
if (initialized == CYGTLS_EXCEPTION)
|
|
{
|
|
#ifdef DEBUGGING
|
|
debug_printf ("resetting stack after an exception stack %p, stackptr %p", stack, stackptr);
|
|
#endif
|
|
set_state (false);
|
|
}
|
|
}
|
|
|
|
/* Two calls to get the stack right... */
|
|
void
|
|
_threadinfo::call (DWORD (*func) (void *, void *), void *arg)
|
|
{
|
|
char buf[CYGTLS_PADSIZE];
|
|
call2 (func, arg, buf);
|
|
}
|
|
|
|
void
|
|
_threadinfo::call2 (DWORD (*func) (void *, void *), void *arg, void *buf)
|
|
{
|
|
exception_list except_entry;
|
|
/* Initialize this thread's ability to respond to things like
|
|
SIGSEGV or SIGFPE. */
|
|
init_exceptions (&except_entry);
|
|
_my_tls.init_thread (buf, func);
|
|
DWORD res = func (arg, buf);
|
|
_my_tls.remove (INFINITE);
|
|
ExitThread (res);
|
|
}
|
|
|
|
void
|
|
_threadinfo::init_thread (void *x, DWORD (*func) (void *, void *))
|
|
{
|
|
if (x)
|
|
{
|
|
memset (this, 0, CYGTLS_PADSIZE);
|
|
stackptr = stack;
|
|
if (_GLOBAL_REENT)
|
|
{
|
|
local_clib._stdin = _GLOBAL_REENT->_stdin;
|
|
local_clib._stdout = _GLOBAL_REENT->_stdout;
|
|
local_clib._stderr = _GLOBAL_REENT->_stderr;
|
|
local_clib.__sdidinit = _GLOBAL_REENT->__sdidinit;
|
|
local_clib.__cleanup = _GLOBAL_REENT->__cleanup;
|
|
}
|
|
local_clib._current_locale = "C";
|
|
locals.process_logmask = LOG_UPTO (LOG_DEBUG);
|
|
}
|
|
|
|
set_state (false);
|
|
errno_addr = &(local_clib._errno);
|
|
|
|
if ((void *) func == (void *) cygthread::stub
|
|
|| (void *) func == (void *) cygthread::simplestub)
|
|
return;
|
|
|
|
sentry here (INFINITE);
|
|
if (nthreads >= cygheap->sthreads)
|
|
{
|
|
cygheap->threadlist = (_threadinfo **)
|
|
crealloc (cygheap->threadlist, (cygheap->sthreads += THREADLIST_CHUNK)
|
|
* sizeof (cygheap->threadlist[0]));
|
|
memset (cygheap->threadlist + nthreads, 0, THREADLIST_CHUNK * sizeof (cygheap->threadlist[0]));
|
|
}
|
|
|
|
cygheap->threadlist[nthreads++] = this;
|
|
}
|
|
|
|
void
|
|
_threadinfo::remove (DWORD wait)
|
|
{
|
|
debug_printf ("wait %p\n", wait);
|
|
sentry here (wait);
|
|
if (here.acquired ())
|
|
{
|
|
for (size_t i = 0; i < nthreads; i++)
|
|
if (&_my_tls == cygheap->threadlist[i])
|
|
{
|
|
if (i < --nthreads)
|
|
cygheap->threadlist[i] = cygheap->threadlist[nthreads];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
_threadinfo::push (__stack_t addr, bool exception)
|
|
{
|
|
*stackptr++ = (__stack_t) addr;
|
|
set_state (exception);
|
|
}
|
|
|
|
__stack_t
|
|
_threadinfo::pop ()
|
|
{
|
|
#ifdef DEBUGGING
|
|
assert (stackptr > stack);
|
|
#endif
|
|
__stack_t res = *--stackptr;
|
|
#ifdef DEBUGGING
|
|
*stackptr = 0;
|
|
debug_printf ("popped %p, stack %p, stackptr %p", res, stack, stackptr);
|
|
#endif
|
|
return res;
|
|
}
|
|
|
|
#define BAD_IX ((size_t) -1)
|
|
static size_t NO_COPY threadlist_ix = BAD_IX;
|
|
|
|
_threadinfo *
|
|
_threadinfo::find_tls (int sig)
|
|
{
|
|
debug_printf ("sig %d\n", sig);
|
|
sentry here (INFINITE);
|
|
__asm__ volatile (".equ _threadlist_exception_return,.");
|
|
_threadinfo *res = NULL;
|
|
for (threadlist_ix = 0; threadlist_ix < nthreads; threadlist_ix++)
|
|
if (sigismember (&(cygheap->threadlist[threadlist_ix]->sigwait_mask), sig))
|
|
{
|
|
res = cygheap->threadlist[threadlist_ix];
|
|
break;
|
|
}
|
|
threadlist_ix = BAD_IX;
|
|
return res;
|
|
}
|
|
|
|
void
|
|
_threadinfo::set_siginfo (sigpacket *pack)
|
|
{
|
|
infodata = pack->si;
|
|
}
|
|
|
|
extern "C" DWORD __stdcall RtlUnwind (void *, void *, void *, DWORD);
|
|
static int
|
|
handle_threadlist_exception (EXCEPTION_RECORD *e, void *frame, CONTEXT *, void *)
|
|
{
|
|
small_printf ("in handle_threadlist_exception!\n");
|
|
if (e->ExceptionCode != STATUS_ACCESS_VIOLATION)
|
|
return 1;
|
|
|
|
sentry here;
|
|
if (threadlist_ix != BAD_IX || !here.acquired ())
|
|
return 1;
|
|
|
|
extern void *threadlist_exception_return;
|
|
cygheap->threadlist[threadlist_ix]->remove (INFINITE);
|
|
threadlist_ix = 0;
|
|
RtlUnwind (frame, threadlist_exception_return, e, 0);
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
_threadinfo::init_threadlist_exceptions (exception_list *el)
|
|
{
|
|
extern void init_exception_handler (exception_list *, exception_handler *);
|
|
init_exception_handler (el, handle_threadlist_exception);
|
|
}
|