2004-01-14 16:45:37 +01:00
|
|
|
/* cygtls.cc
|
2003-12-23 17:43:45 +01:00
|
|
|
|
* 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 03:57:38 +02:00
|
|
|
Copyright 2003, 2004, 2005 Red Hat, Inc.
|
2003-12-23 17:43:45 +01:00
|
|
|
|
|
|
|
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"
|
2005-07-03 04:40:30 +02:00
|
|
|
#include <sys/time.h>
|
|
|
|
#define USE_SYS_TYPES_FD_SET
|
|
|
|
#include <winsock.h>
|
2003-12-23 17:43:45 +01:00
|
|
|
#include "thread.h"
|
|
|
|
#include "cygtls.h"
|
|
|
|
#include "assert.h"
|
|
|
|
#include <syslog.h>
|
2004-01-14 16:45:37 +01:00
|
|
|
#include <signal.h>
|
2005-03-15 22:58:44 +01:00
|
|
|
#include <malloc.h>
|
2004-01-14 16:45:37 +01:00
|
|
|
#include "exceptions.h"
|
|
|
|
#include "sync.h"
|
|
|
|
#include "cygerrno.h"
|
|
|
|
#include "path.h"
|
|
|
|
#include "fhandler.h"
|
|
|
|
#include "dtable.h"
|
|
|
|
#include "cygheap.h"
|
2004-02-12 04:01:58 +01:00
|
|
|
#include "pinfo.h"
|
2004-01-19 06:46:54 +01:00
|
|
|
#include "sigproc.h"
|
2004-01-14 16:45:37 +01:00
|
|
|
|
|
|
|
class sentry
|
|
|
|
{
|
2005-04-05 06:31:00 +02:00
|
|
|
static muto lock;
|
2004-01-14 16:45:37 +01:00
|
|
|
int destroy;
|
|
|
|
public:
|
|
|
|
void init ();
|
2005-04-05 06:31:00 +02:00
|
|
|
bool acquired () {return lock.acquired ();}
|
2004-01-14 16:45:37 +01:00
|
|
|
sentry () {destroy = 0;}
|
2005-04-05 06:31:00 +02:00
|
|
|
sentry (DWORD wait) {destroy = lock.acquire (wait);}
|
|
|
|
~sentry () {if (destroy) lock.release ();}
|
2004-02-12 04:01:58 +01:00
|
|
|
friend void _cygtls::init ();
|
2004-01-14 16:45:37 +01:00
|
|
|
};
|
|
|
|
|
2005-04-05 06:31:00 +02:00
|
|
|
muto NO_COPY sentry::lock;
|
2003-12-23 17:43:45 +01:00
|
|
|
|
2004-01-14 16:45:37 +01:00
|
|
|
static size_t NO_COPY nthreads;
|
2003-12-23 17:43:45 +01:00
|
|
|
|
2004-01-14 16:45:37 +01:00
|
|
|
#define THREADLIST_CHUNK 256
|
|
|
|
|
|
|
|
void
|
2004-02-12 04:01:58 +01:00
|
|
|
_cygtls::init ()
|
2004-01-14 16:45:37 +01:00
|
|
|
{
|
|
|
|
if (cygheap->threadlist)
|
|
|
|
memset (cygheap->threadlist, 0, cygheap->sthreads * sizeof (cygheap->threadlist[0]));
|
|
|
|
else
|
|
|
|
{
|
|
|
|
cygheap->sthreads = THREADLIST_CHUNK;
|
2004-02-12 04:01:58 +01:00
|
|
|
cygheap->threadlist = (_cygtls **) ccalloc (HEAP_TLS, cygheap->sthreads,
|
2004-01-14 16:45:37 +01:00
|
|
|
sizeof (cygheap->threadlist[0]));
|
|
|
|
}
|
2005-04-05 06:31:00 +02:00
|
|
|
sentry::lock.init ("sentry_lock");
|
2004-01-14 16:45:37 +01:00
|
|
|
}
|
2003-12-23 17:43:45 +01:00
|
|
|
|
|
|
|
void
|
2004-02-12 04:01:58 +01:00
|
|
|
_cygtls::set_state (bool is_exception)
|
2003-12-23 17:43:45 +01:00
|
|
|
{
|
|
|
|
initialized = CYGTLS_INITIALIZED + is_exception;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2004-02-12 04:01:58 +01:00
|
|
|
_cygtls::reset_exception ()
|
2003-12-23 17:43:45 +01:00
|
|
|
{
|
|
|
|
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
|
2004-02-12 04:01:58 +01:00
|
|
|
_cygtls::call (DWORD (*func) (void *, void *), void *arg)
|
2003-12-23 17:43:45 +01:00
|
|
|
{
|
|
|
|
char buf[CYGTLS_PADSIZE];
|
|
|
|
call2 (func, arg, buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2004-02-12 04:01:58 +01:00
|
|
|
_cygtls::call2 (DWORD (*func) (void *, void *), void *arg, void *buf)
|
2003-12-23 17:43:45 +01:00
|
|
|
{
|
2004-01-14 16:45:37 +01:00
|
|
|
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);
|
2003-12-23 17:43:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2004-02-12 04:01:58 +01:00
|
|
|
_cygtls::init_thread (void *x, DWORD (*func) (void *, void *))
|
2003-12-23 17:43:45 +01:00
|
|
|
{
|
|
|
|
if (x)
|
|
|
|
{
|
2004-01-14 16:45:37 +01:00
|
|
|
memset (this, 0, CYGTLS_PADSIZE);
|
2003-12-23 17:43:45 +01:00
|
|
|
stackptr = stack;
|
|
|
|
if (_GLOBAL_REENT)
|
|
|
|
{
|
|
|
|
local_clib._stdin = _GLOBAL_REENT->_stdin;
|
|
|
|
local_clib._stdout = _GLOBAL_REENT->_stdout;
|
|
|
|
local_clib._stderr = _GLOBAL_REENT->_stderr;
|
2004-09-07 06:05:14 +02:00
|
|
|
local_clib.__sdidinit = _GLOBAL_REENT->__sdidinit ? -1 : 0;
|
2003-12-23 17:43:45 +01:00
|
|
|
local_clib.__cleanup = _GLOBAL_REENT->__cleanup;
|
2004-01-26 19:52:02 +01:00
|
|
|
local_clib.__sglue._niobs = 3;
|
|
|
|
local_clib.__sglue._iobs = &_GLOBAL_REENT->__sf[0];
|
2003-12-23 17:43:45 +01:00
|
|
|
}
|
|
|
|
local_clib._current_locale = "C";
|
|
|
|
locals.process_logmask = LOG_UPTO (LOG_DEBUG);
|
|
|
|
}
|
|
|
|
|
2005-03-03 01:32:57 +01:00
|
|
|
locals.exitsock = INVALID_SOCKET;
|
2003-12-23 17:43:45 +01:00
|
|
|
set_state (false);
|
|
|
|
errno_addr = &(local_clib._errno);
|
2004-01-14 16:45:37 +01:00
|
|
|
|
|
|
|
if ((void *) func == (void *) cygthread::stub
|
|
|
|
|| (void *) func == (void *) cygthread::simplestub)
|
|
|
|
return;
|
|
|
|
|
2005-04-03 15:06:43 +02:00
|
|
|
if (wincap.has_security ())
|
|
|
|
cygheap->user.reimpersonate ();
|
|
|
|
|
2004-01-14 16:45:37 +01:00
|
|
|
sentry here (INFINITE);
|
|
|
|
if (nthreads >= cygheap->sthreads)
|
|
|
|
{
|
2004-02-12 04:01:58 +01:00
|
|
|
cygheap->threadlist = (_cygtls **)
|
2004-01-14 16:45:37 +01:00
|
|
|
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;
|
2003-12-23 17:43:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2004-02-12 04:01:58 +01:00
|
|
|
_cygtls::fixup_after_fork ()
|
|
|
|
{
|
2004-03-16 05:39:38 +01:00
|
|
|
if (sig)
|
|
|
|
{
|
|
|
|
pop ();
|
|
|
|
sig = 0;
|
|
|
|
}
|
2005-10-24 01:47:45 +02:00
|
|
|
stacklock = spinning = 0;
|
2004-10-26 23:13:50 +02:00
|
|
|
locals.exitsock = INVALID_SOCKET;
|
2004-03-12 04:09:28 +01:00
|
|
|
wq.thread_ev = NULL;
|
2004-02-12 04:01:58 +01:00
|
|
|
}
|
|
|
|
|
2005-03-16 18:07:32 +01:00
|
|
|
#define free_local(x) \
|
|
|
|
if (locals.x) \
|
|
|
|
{ \
|
|
|
|
free (locals.x); \
|
|
|
|
locals.x = NULL; \
|
|
|
|
}
|
|
|
|
|
2004-02-12 04:01:58 +01:00
|
|
|
void
|
|
|
|
_cygtls::remove (DWORD wait)
|
2003-12-23 17:43:45 +01:00
|
|
|
{
|
2005-03-09 21:08:29 +01:00
|
|
|
debug_printf ("wait %p", wait);
|
2005-03-03 01:36:49 +01:00
|
|
|
if (!locals.exitsock)
|
|
|
|
return;
|
2005-04-05 19:13:35 +02:00
|
|
|
if (wait)
|
|
|
|
{
|
2005-05-11 05:33:38 +02:00
|
|
|
/* FIXME: Need some sort of atthreadexit function to allow things like
|
2005-08-12 04:39:13 +02:00
|
|
|
select to control this themselves. */
|
2005-04-05 19:13:35 +02:00
|
|
|
if (locals.exitsock != INVALID_SOCKET)
|
2005-05-11 05:33:38 +02:00
|
|
|
{
|
|
|
|
closesocket (locals.exitsock);
|
2005-05-13 05:21:39 +02:00
|
|
|
locals.exitsock = (SOCKET) NULL;
|
2005-05-11 05:33:38 +02:00
|
|
|
}
|
2005-04-05 19:13:35 +02:00
|
|
|
free_local (process_ident);
|
|
|
|
free_local (ntoa_buf);
|
|
|
|
free_local (protoent_buf);
|
|
|
|
free_local (servent_buf);
|
|
|
|
free_local (hostent_buf);
|
|
|
|
}
|
2005-03-16 18:07:32 +01:00
|
|
|
|
2004-03-15 03:47:35 +01:00
|
|
|
do
|
2003-12-23 17:43:45 +01:00
|
|
|
{
|
2004-03-15 03:47:35 +01:00
|
|
|
sentry here (wait);
|
|
|
|
if (here.acquired ())
|
|
|
|
{
|
|
|
|
for (size_t i = 0; i < nthreads; i++)
|
|
|
|
if (this == cygheap->threadlist[i])
|
|
|
|
{
|
|
|
|
if (i < --nthreads)
|
|
|
|
cygheap->threadlist[i] = cygheap->threadlist[nthreads];
|
|
|
|
debug_printf ("removed %p element %d", this, i);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} while (0);
|
|
|
|
remove_wq (wait);
|
2003-12-23 17:43:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2004-02-12 04:01:58 +01:00
|
|
|
_cygtls::push (__stack_t addr, bool exception)
|
2003-12-23 17:43:45 +01:00
|
|
|
{
|
2004-02-08 20:59:27 +01:00
|
|
|
if (exception)
|
2004-02-09 05:04:24 +01:00
|
|
|
lock ();
|
2003-12-23 17:43:45 +01:00
|
|
|
*stackptr++ = (__stack_t) addr;
|
2004-02-08 20:59:27 +01:00
|
|
|
if (exception)
|
|
|
|
unlock ();
|
2003-12-23 17:43:45 +01:00
|
|
|
set_state (exception);
|
|
|
|
}
|
|
|
|
|
2004-01-14 16:45:37 +01:00
|
|
|
#define BAD_IX ((size_t) -1)
|
|
|
|
static size_t NO_COPY threadlist_ix = BAD_IX;
|
|
|
|
|
2004-02-12 04:01:58 +01:00
|
|
|
_cygtls *
|
|
|
|
_cygtls::find_tls (int sig)
|
2004-01-14 16:45:37 +01:00
|
|
|
{
|
|
|
|
debug_printf ("sig %d\n", sig);
|
|
|
|
sentry here (INFINITE);
|
|
|
|
__asm__ volatile (".equ _threadlist_exception_return,.");
|
2004-02-12 04:01:58 +01:00
|
|
|
_cygtls *res = NULL;
|
2004-01-14 16:45:37 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2004-01-19 06:46:54 +01:00
|
|
|
void
|
2004-02-12 04:01:58 +01:00
|
|
|
_cygtls::set_siginfo (sigpacket *pack)
|
2004-01-19 06:46:54 +01:00
|
|
|
{
|
|
|
|
infodata = pack->si;
|
|
|
|
}
|
|
|
|
|
2004-01-14 16:45:37 +01:00
|
|
|
extern "C" DWORD __stdcall RtlUnwind (void *, void *, void *, DWORD);
|
|
|
|
static int
|
2005-10-19 02:22:08 +02:00
|
|
|
handle_threadlist_exception (EXCEPTION_RECORD *e, void *frame, CONTEXT *c, void *)
|
2004-01-14 16:45:37 +01:00
|
|
|
{
|
|
|
|
if (e->ExceptionCode != STATUS_ACCESS_VIOLATION)
|
2004-01-21 16:16:10 +01:00
|
|
|
{
|
2005-10-19 02:22:08 +02:00
|
|
|
system_printf ("unhandled exception %p at %p", e->ExceptionCode, c->Eip);
|
2004-01-21 16:16:10 +01:00
|
|
|
return 1;
|
|
|
|
}
|
2004-01-14 16:45:37 +01:00
|
|
|
|
|
|
|
sentry here;
|
2004-01-21 16:16:10 +01:00
|
|
|
if (threadlist_ix == BAD_IX)
|
|
|
|
{
|
2005-10-19 02:22:08 +02:00
|
|
|
system_printf ("called with threadlist_ix %d", BAD_IX);
|
2004-01-21 16:16:10 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!here.acquired ())
|
|
|
|
{
|
2005-10-19 02:22:08 +02:00
|
|
|
system_printf ("couldn't aquire muto");
|
2004-01-21 16:16:10 +01:00
|
|
|
return 1;
|
|
|
|
}
|
2004-01-14 16:45:37 +01:00
|
|
|
|
|
|
|
extern void *threadlist_exception_return;
|
|
|
|
cygheap->threadlist[threadlist_ix]->remove (INFINITE);
|
|
|
|
threadlist_ix = 0;
|
|
|
|
RtlUnwind (frame, threadlist_exception_return, e, 0);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2004-02-12 04:01:58 +01:00
|
|
|
_cygtls::init_threadlist_exceptions (exception_list *el)
|
2004-01-14 16:45:37 +01:00
|
|
|
{
|
|
|
|
extern void init_exception_handler (exception_list *, exception_handler *);
|
|
|
|
init_exception_handler (el, handle_threadlist_exception);
|
|
|
|
}
|