newlib/winsup/cygwin/cygtls.cc
Christopher Faylor f6936c48f3 * 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 05:46:54 +00:00

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);
}