diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index a33ff3337..cd890ec6c 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,70 @@ +2005-03-26 Pierre Humblet + Christopher Faylor + + * 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. + +2005-03-26 Christopher Faylor + + * 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-23 Corinna Vinschen * fhandler.h (fhandler_socket::secret_event): Remove. diff --git a/winsup/cygwin/Makefile.in b/winsup/cygwin/Makefile.in index dc6096bdf..cd6f46df1 100644 --- a/winsup/cygwin/Makefile.in +++ b/winsup/cygwin/Makefile.in @@ -117,7 +117,7 @@ MALLOC_OFILES=@MALLOC_OFILES@ DLL_IMPORTS:=$(w32api_lib)/libkernel32.a $(w32api_lib)/libadvapi32.a MT_SAFE_OBJECTS:= -# Please maintain this list in sorted order, with maximum files per 85 col line +# Please maintain this list in sorted order, with maximum files per 86 col line # DLL_OFILES:=assert.o autoload.o bsdlib.o ctype.o cxx.o cygheap.o cygthread.o \ cygtls.o dcrt0.o debug.o delqueue.o devices.o dir.o dlfcn.o dll_init.o \ @@ -129,8 +129,8 @@ DLL_OFILES:=assert.o autoload.o bsdlib.o ctype.o cxx.o cygheap.o cygthread.o \ fhandler_socket.o fhandler_tape.o fhandler_termios.o \ fhandler_tty.o fhandler_virtual.o fhandler_windows.o fhandler_zero.o \ flock.o fnmatch.o fork.o getopt.o glob.o grp.o heap.o hookapi.o \ - init.o ioctl.o ipc.o iruserok.o localtime.o malloc_wrapper.o miscfuncs.o \ - mmap.o msg.o net.o netdb.o ntea.o passwd.o path.o pinfo.o pipe.o \ + init.o ioctl.o ipc.o iruserok.o localtime.o lsearch.o malloc_wrapper.o \ + miscfuncs.o mmap.o msg.o net.o netdb.o ntea.o passwd.o path.o pinfo.o pipe.o \ poll.o pthread.o regcomp.o regerror.o regexec.o regfree.o \ registry.o resource.o scandir.o sched.o sec_acl.o sec_helper.o security.o \ select.o sem.o shared.o shm.o sigfe.o signal.o sigproc.o smallprint.o \ diff --git a/winsup/cygwin/cygthread.cc b/winsup/cygwin/cygthread.cc index 9cdeac84b..11fb047dd 100644 --- a/winsup/cygwin/cygthread.cc +++ b/winsup/cygwin/cygthread.cc @@ -26,7 +26,7 @@ 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 + per-thread initialization and loops waiting for another thread function to execute. */ DWORD WINAPI cygthread::stub (VOID *arg) @@ -73,10 +73,11 @@ cygthread::stub (VOID *arg) info->func (info->arg == cygself ? info : info->arg); /* ...so the above should always return */ + 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 - that it is doing. */ + what it is doing. */ if (!info->func) info->release (false); else @@ -88,6 +89,8 @@ cygthread::stub (VOID *arg) info->__name = NULL; SetEvent (info->ev); } + if (notify) + SetEvent (notify); } switch (WaitForSingleObject (info->thread_sync, INFINITE)) { @@ -161,8 +164,8 @@ out: } cygthread::cygthread (LPTHREAD_START_ROUTINE start, LPVOID param, - const char *name): __name (name), - func (start), arg (param) + const char *name, HANDLE notify) + : __name (name), func (start), arg (param), notify_detached (notify) { thread_printf ("name %s, id %p", name, id); if (h) @@ -310,7 +313,9 @@ cygthread::detach (HANDLE sigwait) DWORD res; if (!sigwait) - res = WaitForSingleObject (*this, INFINITE); + /* If the caller specified a special handle for notification, wait for that. + This assumes that the thread in question is auto releasing. */ + res = WaitForSingleObject (notify_detached ?: *this, INFINITE); else { /* Lower our priority and give priority to the read thread */ diff --git a/winsup/cygwin/cygthread.h b/winsup/cygwin/cygthread.h index e1c2e495f..6d504f1e4 100644 --- a/winsup/cygwin/cygthread.h +++ b/winsup/cygwin/cygthread.h @@ -26,6 +26,7 @@ class cygthread VOID *arg; bool is_freerange; static bool exiting; + HANDLE notify_detached; public: bool terminate_thread (); static DWORD WINAPI stub (VOID *); @@ -34,7 +35,7 @@ class cygthread static const char * name (DWORD = 0); void auto_release () {func = NULL;} void release (bool); - cygthread (LPTHREAD_START_ROUTINE, LPVOID, const char *); + cygthread (LPTHREAD_START_ROUTINE, LPVOID, const char *, HANDLE = NULL); cygthread () {}; static void init (); bool detach (HANDLE = NULL); diff --git a/winsup/cygwin/cygtls.cc b/winsup/cygwin/cygtls.cc index 5b8167f2e..e14f248cf 100644 --- a/winsup/cygwin/cygtls.cc +++ b/winsup/cygwin/cygtls.cc @@ -1,6 +1,6 @@ /* cygtls.cc - Copyright 2003, 2004 Red Hat, Inc. + Copyright 2003, 2004, 2005 Red Hat, Inc. This software is a copyrighted work licensed under the terms of the Cygwin license. Please consult the file "CYGWIN_LICENSE" for diff --git a/winsup/cygwin/cygwin.din b/winsup/cygwin/cygwin.din index 8a0585de6..5d593270e 100644 --- a/winsup/cygwin/cygwin.din +++ b/winsup/cygwin/cygwin.din @@ -821,6 +821,7 @@ ldexpf NOSIGFE _ldexpf = ldexpf NOSIGFE ldiv NOSIGFE _ldiv = ldiv NOSIGFE +lfind NOSIGFE lgamma NOSIGFE _lgamma = lgamma NOSIGFE lgamma_r NOSIGFE @@ -866,6 +867,7 @@ lrint NOSIGFE lrintf NOSIGFE lround NOSIGFE lroundf NOSIGFE +lsearch NOSIGFE lseek SIGFE _lseek = lseek SIGFE _lseek64 = lseek64 SIGFE @@ -1436,6 +1438,7 @@ time SIGFE _time = time SIGFE timer_create SIGFE timer_delete SIGFE +timer_gettime SIGFE timer_settime SIGFE times SIGFE _times = times SIGFE diff --git a/winsup/cygwin/debug.cc b/winsup/cygwin/debug.cc index 075830f97..b885a9fc4 100644 --- a/winsup/cygwin/debug.cc +++ b/winsup/cygwin/debug.cc @@ -1,6 +1,6 @@ /* debug.cc - Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004 Red Hat, Inc. + Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Red Hat, Inc. This software is a copyrighted work licensed under the terms of the Cygwin license. Please consult the file "CYGWIN_LICENSE" for diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc index 277bd713a..1de0bf976 100644 --- a/winsup/cygwin/exceptions.cc +++ b/winsup/cygwin/exceptions.cc @@ -10,6 +10,8 @@ Cygwin license. Please consult the file "CYGWIN_LICENSE" for details. */ #include "winsup.h" +#include +#include #include #include #include @@ -782,6 +784,27 @@ out: return interrupted; } +static inline bool +has_visible_window_station () +{ + HWINSTA station_hdl; + USEROBJECTFLAGS uof; + DWORD len; + + /* Check if the process is associated with a visible window station. + These are processes running on the local desktop as well as processes + running in terminal server sessions. + Processes running in a service session not explicitely associated + with the desktop (using the "Allow service to interact with desktop" + property) are running in an invisible window station. */ + if ((station_hdl = GetProcessWindowStation ()) + && GetUserObjectInformationA (station_hdl, UOI_FLAGS, &uof, + sizeof uof, &len) + && (uof.dwFlags & WSF_VISIBLE)) + return true; + return false; +} + /* Keyboard interrupt handler. */ static BOOL WINAPI ctrl_c_handler (DWORD type) diff --git a/winsup/cygwin/external.cc b/winsup/cygwin/external.cc index c28039cc0..5ab476f44 100644 --- a/winsup/cygwin/external.cc +++ b/winsup/cygwin/external.cc @@ -1,6 +1,6 @@ /* external.cc: Interface to Cygwin internals from external programs. - Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 Red Hat, Inc. + Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Red Hat, Inc. Written by Christopher Faylor diff --git a/winsup/cygwin/fhandler_clipboard.cc b/winsup/cygwin/fhandler_clipboard.cc index fab1424be..dc9276c92 100644 --- a/winsup/cygwin/fhandler_clipboard.cc +++ b/winsup/cygwin/fhandler_clipboard.cc @@ -1,6 +1,6 @@ /* fhandler_dev_clipboard: code to access /dev/clipboard - Copyright 2000, 2001, 2002, 2003, 2004 Red Hat, Inc + Copyright 2000, 2001, 2002, 2003, 2004, 2005 Red Hat, Inc Written by Charles Wilson (cwilson@ece.gatech.edu) diff --git a/winsup/cygwin/fhandler_mem.cc b/winsup/cygwin/fhandler_mem.cc index 296ef8693..431ecb85d 100644 --- a/winsup/cygwin/fhandler_mem.cc +++ b/winsup/cygwin/fhandler_mem.cc @@ -1,6 +1,6 @@ /* fhandler_mem.cc. See fhandler.h for a description of the fhandler classes. - Copyright 2000, 2001, 2002, 2003, 2004 Red Hat, Inc. + Copyright 2000, 2001, 2002, 2003, 2004, 2005 Red Hat, Inc. This file is part of Cygwin. diff --git a/winsup/cygwin/fhandler_raw.cc b/winsup/cygwin/fhandler_raw.cc index e1ab19a07..0a80cc40f 100644 --- a/winsup/cygwin/fhandler_raw.cc +++ b/winsup/cygwin/fhandler_raw.cc @@ -1,6 +1,6 @@ /* fhandler_raw.cc. See fhandler.h for a description of the fhandler classes. - Copyright 1999, 2000, 2001, 2002, 2003, 2004 Red Hat, Inc. + Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005 Red Hat, Inc. This file is part of Cygwin. diff --git a/winsup/cygwin/fhandler_serial.cc b/winsup/cygwin/fhandler_serial.cc index d0b225f66..b91adc9de 100644 --- a/winsup/cygwin/fhandler_serial.cc +++ b/winsup/cygwin/fhandler_serial.cc @@ -1,6 +1,6 @@ /* fhandler_serial.cc - Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 Red Hat, Inc. + Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Red Hat, Inc. This file is part of Cygwin. diff --git a/winsup/cygwin/fhandler_tape.cc b/winsup/cygwin/fhandler_tape.cc index 33850e329..a3c74dd71 100644 --- a/winsup/cygwin/fhandler_tape.cc +++ b/winsup/cygwin/fhandler_tape.cc @@ -1,7 +1,7 @@ /* fhandler_tape.cc. See fhandler.h for a description of the fhandler classes. - Copyright 1999, 2000, 2001, 2002, 2003, 2004 Red Hat, Inc. + Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005 Red Hat, Inc. This file is part of Cygwin. diff --git a/winsup/cygwin/fhandler_termios.cc b/winsup/cygwin/fhandler_termios.cc index d1d65dd22..f54a08c0e 100644 --- a/winsup/cygwin/fhandler_termios.cc +++ b/winsup/cygwin/fhandler_termios.cc @@ -1,6 +1,6 @@ /* fhandler_termios.cc - Copyright 1999, 2000, 2001, 2002, 2003, 2004 Red Hat, Inc. + Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005 Red Hat, Inc. This file is part of Cygwin. diff --git a/winsup/cygwin/fhandler_windows.cc b/winsup/cygwin/fhandler_windows.cc index a7848bc07..1e6bf3db5 100644 --- a/winsup/cygwin/fhandler_windows.cc +++ b/winsup/cygwin/fhandler_windows.cc @@ -1,6 +1,6 @@ /* fhandler_windows.cc: code to access windows message queues. - Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004 Red Hat, Inc. + Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Red Hat, Inc. Written by Sergey S. Okhapkin (sos@prospect.com.ru). Feedback and testing by Andy Piper (andyp@parallax.co.uk). diff --git a/winsup/cygwin/include/cygwin/version.h b/winsup/cygwin/include/cygwin/version.h index f421e9cf6..a18bd8f71 100644 --- a/winsup/cygwin/include/cygwin/version.h +++ b/winsup/cygwin/include/cygwin/version.h @@ -252,12 +252,13 @@ details. */ 123: Export utmpxname. 124: Add MAP_AUTOGROW flag to mmap. 125: LD_PRELOAD/CW_HOOK available. + 126: Add lsearch, lfind, timer_gettime. */ /* Note that we forgot to bump the api for ualarm, strtoll, strtoull */ #define CYGWIN_VERSION_API_MAJOR 0 -#define CYGWIN_VERSION_API_MINOR 125 +#define CYGWIN_VERSION_API_MINOR 126 /* There is also a compatibity version number associated with the shared memory regions. It is incremented when incompatible diff --git a/winsup/cygwin/include/search.h b/winsup/cygwin/include/search.h new file mode 100644 index 000000000..fedfc8cf6 --- /dev/null +++ b/winsup/cygwin/include/search.h @@ -0,0 +1,64 @@ +/*- + * Written by J.T. Conklin + * Public domain. + * + * $NetBSD: search.h,v 1.12 1999/02/22 10:34:28 christos Exp $ + * $FreeBSD: src/include/search.h,v 1.10 2002/10/16 14:29:23 robert Exp $ + */ + +#ifndef _SEARCH_H_ +#define _SEARCH_H_ + +#include +#include + +typedef struct entry +{ + char *key; + void *data; +} ENTRY; + +typedef enum +{ + FIND, ENTER +} ACTION; + +typedef enum +{ + preorder, + postorder, + endorder, + leaf +} VISIT; + +#ifdef _SEARCH_PRIVATE +typedef struct node +{ + char *key; + struct node *llink, *rlink; +} node_t; + +struct que_elem +{ + struct que_elem *next; + struct que_elem *prev; +}; +#endif + +__BEGIN_DECLS +int hcreate (size_t); +void hdestroy (void); +ENTRY *hsearch (ENTRY, ACTION); +void *lfind (const void *, const void *, size_t *, size_t, + int (*) (const void *, const void *)); +void *lsearch (const void *, void *, size_t *, size_t, + int (*) (const void *, const void *)); +void *tdelete (const void * __restrict, void ** __restrict, + int (*) (const void *, const void *)); +void *tfind (const void *, void * const *, + int (*) (const void *, const void *)); +void *tsearch (const void *, void **, int (*) (const void *, const void *)); +void twalk (const void *, void (*) (const void *, VISIT, int)); +__END_DECLS + +#endif /* !_SEARCH_H_ */ diff --git a/winsup/cygwin/lsearch.cc b/winsup/cygwin/lsearch.cc new file mode 100644 index 000000000..68fcf735f --- /dev/null +++ b/winsup/cygwin/lsearch.cc @@ -0,0 +1,56 @@ +/* Initial implementation: + Copyright (c) 2002 Robert Drehmel + All rights reserved. + + As long as the above copyright statement and this notice remain + unchanged, you can do what ever you want with this file. */ + +#include +#include +#define _SEARCH_PRIVATE +#include +#include /* for uint8_t */ +#include /* for NULL */ +#include /* for memcpy () prototype */ + +static void *lwork (const void *, const void *, size_t *, size_t, + int (*) (const void *, const void *), int); + +extern "C" void * +lsearch (const void *key, void *base, size_t *nelp, size_t width, + int (*compar) (const void *, const void *)) +{ + return lwork (key, base, nelp, width, compar, 1); +} + +extern "C" void * +lfind (const void *key, const void *base, size_t *nelp, size_t width, + int (*compar) (const void *, const void *)) +{ + return lwork (key, base, nelp, width, compar, 0); +} + +static void * +lwork (const void *key, const void *base, size_t *nelp, size_t width, + int (*compar) (const void *, const void *), int addelem) +{ + uint8_t *ep, *endp; + + /* Cast to an integer value first to avoid the warning for removing + 'const' via a cast. */ + ep = (uint8_t *) (uintptr_t)base; + for (endp = (uint8_t *) (ep + width * *nelp); ep < endp; ep += width) + if (compar (key, ep) == 0) + return ep; + + /* lfind () shall return when the key was not found. */ + if (!addelem) + return NULL; + + /* lsearch () adds the key to the end of the table and increments + the number of elements. */ + memcpy (endp, key, width); + ++*nelp; + + return endp; +} diff --git a/winsup/cygwin/security.cc b/winsup/cygwin/security.cc index 40914ff4a..5fd401908 100644 --- a/winsup/cygwin/security.cc +++ b/winsup/cygwin/security.cc @@ -1,6 +1,6 @@ /* security.cc: NT security functions - Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 Red Hat, Inc. + Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Red Hat, Inc. Originaly written by Gunther Ebert, gunther.ebert@ixos-leipzig.de Completely rewritten by Corinna Vinschen diff --git a/winsup/cygwin/sync.cc b/winsup/cygwin/sync.cc index e8eb2ac76..68539a236 100644 --- a/winsup/cygwin/sync.cc +++ b/winsup/cygwin/sync.cc @@ -4,7 +4,7 @@ which is intended to operate similarly to a mutex but attempts to avoid making expensive calls to the kernel. - Copyright 2000, 2001, 2002, 2003, 2004 Red Hat, Inc. + Copyright 2000, 2001, 2002, 2003, 2004, 2005 Red Hat, Inc. Written by Christopher Faylor diff --git a/winsup/cygwin/timer.cc b/winsup/cygwin/timer.cc index 6a53a572f..1ab6616d3 100644 --- a/winsup/cygwin/timer.cc +++ b/winsup/cygwin/timer.cc @@ -22,27 +22,61 @@ details. */ #define TT_MAGIC 0x513e4a1c struct timer_tracker { - static muto *protect; unsigned magic; clockid_t clock_id; sigevent evp; - itimerspec it; + timespec it_interval; HANDLE cancel; - int flags; + HANDLE syncthread; + long long interval_us; + long long sleepto_us; cygthread *th; struct timer_tracker *next; int settime (int, const itimerspec *, itimerspec *); + void gettime (itimerspec *); timer_tracker (clockid_t, const sigevent *); - timer_tracker (); + timer_tracker () {}; + ~timer_tracker (); + friend void fixup_timers_after_fork (); }; -timer_tracker ttstart; +timer_tracker NO_COPY ttstart; -muto *timer_tracker::protect; - -timer_tracker::timer_tracker () +class lock_timer_tracker { - new_muto (protect); + static muto *protect; +public: + lock_timer_tracker (); + ~lock_timer_tracker (); +}; + +muto NO_COPY *lock_timer_tracker::protect; + +lock_timer_tracker::lock_timer_tracker () +{ + new_muto (protect)->acquire (); +} + +lock_timer_tracker::~lock_timer_tracker () +{ + protect->release (); +} + +timer_tracker::~timer_tracker () +{ + if (cancel) + { + SetEvent (cancel); + th->detach (); + CloseHandle (cancel); +#ifdef DEBUGGING + th = NULL; + cancel = NULL; +#endif + } + if (syncthread) + CloseHandle (syncthread); + magic = 0; } timer_tracker::timer_tracker (clockid_t c, const sigevent *e) @@ -56,84 +90,83 @@ timer_tracker::timer_tracker (clockid_t c, const sigevent *e) evp.sigev_value.sival_ptr = this; } clock_id = c; - cancel = NULL; - flags = 0; - memset (&it, 0, sizeof (it)); - protect->acquire (); - next = ttstart.next; - ttstart.next = this; - protect->release (); magic = TT_MAGIC; + if (this != &ttstart) + { + cancel = NULL; + lock_timer_tracker here; + next = ttstart.next; + ttstart.next = this; + } } static long long -to_us (timespec& ts) +to_us (const timespec& ts) { long long res = ts.tv_sec; res *= 1000000; - res += ts.tv_nsec / 1000 + ((ts.tv_nsec % 1000) >= 500 ? 1 : 0); + res += ts.tv_nsec / 1000 + ((ts.tv_nsec % 1000) ? 1 : 0); return res; } -static NO_COPY itimerspec itzero; -static NO_COPY timespec tzero; - static DWORD WINAPI timer_thread (VOID *x) { - timer_tracker *tp = ((timer_tracker *) x); - timer_tracker tt = *tp; - for (bool first = true; ; first = false) + timer_tracker *tt = ((timer_tracker *) x); + long long now; + long long sleepto_us = tt->sleepto_us; + while (1) { - long long sleep_us = to_us (first ? tt.it.it_value : tt.it.it_interval); - long long sleep_to = sleep_us; - long long now = gtod.usecs (false); - if (tt.flags & TIMER_ABSTIME) - sleep_us -= now; + long long sleep_us; + long sleep_ms; + /* Account for delays in starting thread + and sending the signal */ + now = gtod.usecs (false); + sleep_us = sleepto_us - now; + if (sleep_us > 0) + { + tt->sleepto_us = sleepto_us; + sleep_ms = (sleep_us + 999) / 1000; + } else - sleep_to += now; + { + tt->sleepto_us = now; + sleep_ms = 0; + } - DWORD sleep_ms = (sleep_us < 0) ? 0 : (sleep_us / 1000); - debug_printf ("%p waiting for %u ms, first %d", x, sleep_ms, first); - tp->it.it_value = tzero; - switch (WaitForSingleObject (tt.cancel, sleep_ms)) + debug_printf ("%p waiting for %u ms", x, sleep_ms); + switch (WaitForSingleObject (tt->cancel, sleep_ms)) { case WAIT_TIMEOUT: debug_printf ("timed out"); break; case WAIT_OBJECT_0: - now = gtod.usecs (false); - sleep_us = sleep_to - now; - if (sleep_us < 0) - sleep_us = 0; - tp->it.it_value.tv_sec = sleep_us / 1000000; - tp->it.it_value.tv_nsec = (sleep_us % 1000000) * 1000; - debug_printf ("%p cancelled, elapsed %D", x, sleep_us); + debug_printf ("%p cancelled", x); goto out; default: - debug_printf ("%p timer wait failed, %E", x); + debug_printf ("%p wait failed, %E", x); goto out; } - switch (tt.evp.sigev_notify) + switch (tt->evp.sigev_notify) { case SIGEV_SIGNAL: { siginfo_t si; memset (&si, 0, sizeof (si)); - si.si_signo = tt.evp.sigev_signo; - si.si_sigval.sival_ptr = tt.evp.sigev_value.sival_ptr; - debug_printf ("%p sending sig %d", x, tt.evp.sigev_signo); - sig_send (NULL, si); + si.si_signo = tt->evp.sigev_signo; + si.si_sigval.sival_ptr = tt->evp.sigev_value.sival_ptr; + debug_printf ("%p sending sig %d", x, tt->evp.sigev_signo); + sig_send (myself_nowait, si); break; } case SIGEV_THREAD: { pthread_t notify_thread; debug_printf ("%p starting thread", x); - int rc = pthread_create (¬ify_thread, tt.evp.sigev_notify_attributes, - (void * (*) (void *)) tt.evp.sigev_notify_function, - tt.evp.sigev_value.sival_ptr); + int rc = pthread_create (¬ify_thread, tt->evp.sigev_notify_attributes, + (void * (*) (void *)) tt->evp.sigev_notify_function, + tt->evp.sigev_value.sival_ptr); if (rc) { debug_printf ("thread creation failed, %E"); @@ -143,17 +176,15 @@ timer_thread (VOID *x) break; } } - if (!tt.it.it_interval.tv_sec && !tt.it.it_interval.tv_nsec) + if (!tt->interval_us) break; - tt.flags = 0; + + sleepto_us = tt->sleepto_us + tt->interval_us; debug_printf ("looping"); } out: - CloseHandle (tt.cancel); - // FIXME: race here but is it inevitable? - if (tt.cancel == tp->cancel) - tp->cancel = NULL; + _my_tls._ctinfo->auto_release (); /* automatically return the cygthread to the cygthread pool */ return 0; } @@ -177,48 +208,83 @@ timer_tracker::settime (int in_flags, const itimerspec *value, itimerspec *ovalu return -1; } - if (__check_invalid_read_ptr_errno (value, sizeof (*value))) + if (__check_invalid_read_ptr_errno (value, sizeof (*value)) + || it_bad (value->it_value) + || it_bad (value->it_interval) + || (ovalue && check_null_invalid_struct_errno (ovalue))) return -1; - if (ovalue && check_null_invalid_struct_errno (ovalue)) - return -1; + long long now = in_flags & TIMER_ABSTIME ? 0 : gtod.usecs (false); - itimerspec *elapsed; - if (!cancel) - elapsed = &itzero; - else + lock_timer_tracker here; + if (cancel) { SetEvent (cancel); // should be closed when the thread exits th->detach (); - elapsed = ⁢ } if (ovalue) - *ovalue = *elapsed; + gettime (ovalue); if (value->it_value.tv_sec || value->it_value.tv_nsec) { - if (it_bad (value->it_value)) - return -1; - if (it_bad (value->it_interval)) - return -1; - flags = in_flags; - cancel = CreateEvent (&sec_none_nih, TRUE, FALSE, NULL); - it = *value; - th = new cygthread (timer_thread, this, "itimer"); + sleepto_us = now + to_us (value->it_value); + interval_us = to_us (value->it_interval); + it_interval = value->it_interval; + if (!cancel) + cancel = CreateEvent (&sec_none_nih, TRUE, FALSE, NULL); + else + ResetEvent (cancel); + if (!syncthread) + syncthread = CreateEvent (&sec_none_nih, TRUE, FALSE, NULL); + else + ResetEvent (syncthread); + th = new cygthread (timer_thread, this, "itimer", syncthread); } return 0; } +void +timer_tracker::gettime (itimerspec *ovalue) +{ + if (!cancel) + memset (ovalue, 0, sizeof (*ovalue)); + else + { + ovalue->it_interval = it_interval; + long long now = gtod.usecs (false); + long long left_us = sleepto_us - now; + if (left_us < 0) + left_us = 0; + ovalue->it_value.tv_sec = left_us / 1000000; + ovalue->it_value.tv_nsec = (left_us % 1000000) * 1000; + } +} + +extern "C" int +timer_gettime (timer_t timerid, struct itimerspec *ovalue) +{ + if (check_null_invalid_struct_errno (ovalue)) + return -1; + + timer_tracker *tt = (timer_tracker *) timerid; + if (check_null_invalid_struct (tt) || tt->magic != TT_MAGIC) + { + set_errno (EINVAL); + return -1; + } + + tt->gettime (ovalue); + return 0; +} + extern "C" int timer_create (clockid_t clock_id, struct sigevent *evp, timer_t *timerid) { - if (evp && check_null_invalid_struct_errno (evp)) + if (evp && check_null_invalid_struct_errno (evp) + || check_null_invalid_struct_errno (timerid)) return -1; - if (check_null_invalid_struct_errno (timerid)) - return -1; - if (clock_id != CLOCK_REALTIME) { set_errno (EINVAL); @@ -234,8 +300,12 @@ timer_settime (timer_t timerid, int flags, const struct itimerspec *value, struct itimerspec *ovalue) { timer_tracker *tt = (timer_tracker *) timerid; - if (check_null_invalid_struct_errno (tt) || tt->magic != TT_MAGIC) - return -1; + if (check_null_invalid_struct (tt) || tt->magic != TT_MAGIC) + { + set_errno (EINVAL); + return -1; + } + return tt->settime (flags, value, ovalue); } @@ -243,21 +313,20 @@ extern "C" int timer_delete (timer_t timerid) { timer_tracker *in_tt = (timer_tracker *) timerid; - if (check_null_invalid_struct_errno (in_tt) || in_tt->magic != TT_MAGIC) - return -1; + if (check_null_invalid_struct (in_tt) || in_tt->magic != TT_MAGIC) + { + set_errno (EINVAL); + return -1; + } - timer_tracker::protect->acquire (); + lock_timer_tracker here; for (timer_tracker *tt = &ttstart; tt->next != NULL; tt = tt->next) if (tt->next == in_tt) { - timer_tracker *deleteme = tt->next; - tt->next = deleteme->next; - delete deleteme; - timer_tracker::protect->release (); + tt->next = in_tt->next; + delete in_tt; return 0; } - timer_tracker::protect->release (); - set_errno (EINVAL); return 0; } @@ -265,10 +334,104 @@ timer_delete (timer_t timerid) void fixup_timers_after_fork () { + ttstart.cancel = ttstart.syncthread = NULL; for (timer_tracker *tt = &ttstart; tt->next != NULL; /* nothing */) { timer_tracker *deleteme = tt->next; tt->next = deleteme->next; + deleteme->cancel = deleteme->syncthread = NULL; delete deleteme; } } + + +extern "C" int +setitimer (int which, const struct itimerval *value, struct itimerval *ovalue) +{ + if (which != ITIMER_REAL) + { + set_errno (EINVAL); + return -1; + } + struct itimerspec spec_value, spec_ovalue; + int ret; + spec_value.it_interval.tv_sec = value->it_interval.tv_sec; + spec_value.it_interval.tv_nsec = value->it_interval.tv_usec * 1000; + spec_value.it_value.tv_sec = value->it_value.tv_sec; + spec_value.it_value.tv_nsec = value->it_value.tv_usec * 1000; + ret = timer_settime ((timer_t) &ttstart, 0, &spec_value, &spec_ovalue); + if (!ret && ovalue) + { + ovalue->it_interval.tv_sec = spec_ovalue.it_interval.tv_sec; + ovalue->it_interval.tv_usec = spec_ovalue.it_interval.tv_nsec / 1000; + ovalue->it_value.tv_sec = spec_ovalue.it_value.tv_sec; + ovalue->it_value.tv_usec = spec_ovalue.it_value.tv_nsec / 1000; + } + syscall_printf ("%d = setitimer ()", ret); + return ret; +} + + +extern "C" int +getitimer (int which, struct itimerval *ovalue) +{ + if (which != ITIMER_REAL) + { + set_errno (EINVAL); + return -1; + } + if (ovalue == NULL) + { + set_errno (EFAULT); + return -1; + } + struct itimerspec spec_ovalue; + int ret = timer_gettime ((timer_t) &ttstart, &spec_ovalue); + if (!ret) + { + ovalue->it_interval.tv_sec = spec_ovalue.it_interval.tv_sec; + ovalue->it_interval.tv_usec = spec_ovalue.it_interval.tv_nsec / 1000; + ovalue->it_value.tv_sec = spec_ovalue.it_value.tv_sec; + ovalue->it_value.tv_usec = spec_ovalue.it_value.tv_nsec / 1000; + } + syscall_printf ("%d = getitimer ()", ret); + return ret; +} + +/* FIXME: POSIX - alarm survives exec */ +extern "C" unsigned int +alarm (unsigned int seconds) +{ + struct itimerspec newt = {}, oldt; + /* alarm cannot fail, but only needs not be + correct for arguments < 64k. Truncate */ + if (seconds > (HIRES_DELAY_MAX / 1000 - 1)) + seconds = (HIRES_DELAY_MAX / 1000 - 1); + newt.it_value.tv_sec = seconds; + timer_settime ((timer_t) &ttstart, 0, &newt, &oldt); + int ret = oldt.it_value.tv_sec + (oldt.it_value.tv_nsec > 0); + syscall_printf ("%d = alarm (%d)", ret, seconds); + return ret; +} + +extern "C" useconds_t +ualarm (useconds_t value, useconds_t interval) +{ + struct itimerspec timer = {}, otimer; + /* ualarm cannot fail. + Interpret negative arguments as zero */ + if (value > 0) + { + timer.it_value.tv_sec = (unsigned int) value / 1000000; + timer.it_value.tv_nsec = ((unsigned int) value % 1000000) * 1000; + } + if (interval > 0) + { + timer.it_interval.tv_sec = (unsigned int) interval / 1000000; + timer.it_interval.tv_nsec = ((unsigned int) interval % 1000000) * 1000; + } + timer_settime ((timer_t) &ttstart, 0, &timer, &otimer); + useconds_t ret = otimer.it_value.tv_sec * 1000000 + (otimer.it_value.tv_nsec + 999) / 1000; + syscall_printf ("%d = ualarm (%d , %d)", ret, value, interval); + return ret; +} diff --git a/winsup/cygwin/window.cc b/winsup/cygwin/window.cc index 2c5fcce8a..335ce3339 100644 --- a/winsup/cygwin/window.cc +++ b/winsup/cygwin/window.cc @@ -1,6 +1,6 @@ /* window.cc: hidden windows for signals/itimer support - Copyright 1997, 1998, 2000, 2001, 2002, 2003, 2004 Red Hat, Inc. + Copyright 1997, 1998, 2000, 2001, 2002, 2003, 2004, 2005 Red Hat, Inc. Written by Sergey Okhapkin @@ -30,12 +30,7 @@ details. */ wininfo NO_COPY winmsg; -muto NO_COPY *wininfo::lock; - -wininfo::wininfo () -{ - new_muto_name (lock, "!winlock"); -} +muto NO_COPY *wininfo::_lock; int __stdcall wininfo::process (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) @@ -50,23 +45,6 @@ wininfo::process (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) case WM_DESTROY: PostQuitMessage (0); return 0; - case WM_TIMER: - if (wParam == timer_active) - { - UINT elapse = itv.it_interval.tv_sec * 1000 + - itv.it_interval.tv_usec / 1000; - KillTimer (hwnd, timer_active); - if (!elapse) - timer_active = 0; - else - { - timer_active = SetTimer (hwnd, 1, elapse, NULL); - start_time = GetTickCount (); - itv.it_value = itv.it_interval; - } - raise (SIGALRM); - } - return 0; case WM_ASYNCIO: if (WSAGETSELECTEVENT (lParam) == FD_OOB) raise (SIGURG); @@ -92,7 +70,7 @@ wininfo::winthread () WNDCLASS wc; static NO_COPY char classname[] = "CygwinWndClass"; - lock->grab (); + _lock->grab (); /* Register the window class for the main window. */ wc.style = 0; @@ -116,7 +94,7 @@ wininfo::winthread () (LPVOID) NULL); if (!hwnd) api_fatal ("couldn't create window, %E"); - lock->release (); + release (); while (GetMessage (&msg, hwnd, 0, 0) == TRUE) DispatchMessage (&msg); @@ -136,156 +114,27 @@ HWND () if (hwnd) return hwnd; - lock->acquire (); + lock (); if (!hwnd) { - lock->upforgrabs (); + _lock->upforgrabs (); cygthread *h = new cygthread (::winthread, this, "win"); h->SetThreadPriority (THREAD_PRIORITY_HIGHEST); h->zap_h (); - lock->acquire (); + lock (); } - lock->release (); + release (); return hwnd; } -extern "C" int -setitimer (int which, const struct itimerval *value, struct itimerval *oldvalue) +void +wininfo::lock () { - if (which != ITIMER_REAL) - { - set_errno (ENOSYS); - return -1; - } - return winmsg.setitimer (value, oldvalue); + new_muto (_lock)->acquire (); } -/* FIXME: Very racy */ -int __stdcall -wininfo::setitimer (const struct itimerval *value, struct itimerval *oldvalue) +void +wininfo::release () { - /* Check if we will wrap */ - if (itv.it_value.tv_sec >= (long) (UINT_MAX / 1000)) - { - set_errno (EINVAL); - return -1; - } - if (timer_active) - { - KillTimer (winmsg, timer_active); - timer_active = 0; - } - if (oldvalue) - *oldvalue = itv; - if (value == NULL) - { - set_errno (EFAULT); - return -1; - } - itv = *value; - UINT elapse = itv.it_value.tv_sec * 1000 + itv.it_value.tv_usec / 1000; - if (elapse == 0) - if (itv.it_value.tv_usec) - elapse = 1; - else - return 0; - if (!(timer_active = SetTimer (winmsg, 1, elapse, NULL))) - { - __seterrno (); - return -1; - } - start_time = GetTickCount (); - return 0; -} - -extern "C" int -getitimer (int which, struct itimerval *value) -{ - if (which != ITIMER_REAL) - { - set_errno (EINVAL); - return -1; - } - if (value == NULL) - { - set_errno (EFAULT); - return -1; - } - return winmsg.getitimer (value); -} - -/* FIXME: racy */ -int __stdcall -wininfo::getitimer (struct itimerval *value) -{ - *value = itv; - if (!timer_active) - { - value->it_value.tv_sec = 0; - value->it_value.tv_usec = 0; - return 0; - } - - UINT elapse, val; - - elapse = GetTickCount () - start_time; - val = itv.it_value.tv_sec * 1000 + itv.it_value.tv_usec / 1000; - val -= elapse; - value->it_value.tv_sec = val / 1000; - value->it_value.tv_usec = val % 1000; - return 0; -} - -extern "C" unsigned int -alarm (unsigned int seconds) -{ - int ret; - struct itimerval newt, oldt; - - newt.it_value.tv_sec = seconds; - newt.it_value.tv_usec = 0; - newt.it_interval.tv_sec = 0; - newt.it_interval.tv_usec = 0; - setitimer (ITIMER_REAL, &newt, &oldt); - ret = oldt.it_value.tv_sec; - if (ret == 0 && oldt.it_value.tv_usec) - ret = 1; - return ret; -} - -extern "C" useconds_t -ualarm (useconds_t value, useconds_t interval) -{ - struct itimerval timer, otimer; - - timer.it_value.tv_sec = 0; - timer.it_value.tv_usec = value; - timer.it_interval.tv_sec = 0; - timer.it_interval.tv_usec = interval; - - if (setitimer (ITIMER_REAL, &timer, &otimer) < 0) - return (u_int)-1; - - return (otimer.it_value.tv_sec * 1000000) + otimer.it_value.tv_usec; -} - -bool -has_visible_window_station (void) -{ - HWINSTA station_hdl; - USEROBJECTFLAGS uof; - DWORD len; - - /* Check if the process is associated with a visible window station. - These are processes running on the local desktop as well as processes - running in terminal server sessions. - Processes running in a service session not explicitely associated - with the desktop (using the "Allow service to interact with desktop" - property) are running in an invisible window station. */ - if ((station_hdl = GetProcessWindowStation ()) - && GetUserObjectInformationA (station_hdl, UOI_FLAGS, &uof, - sizeof uof, &len) - && (uof.dwFlags & WSF_VISIBLE)) - return true; - return false; + _lock->release (); } diff --git a/winsup/cygwin/wininfo.h b/winsup/cygwin/wininfo.h index fd8fb52b0..bde386561 100644 --- a/winsup/cygwin/wininfo.h +++ b/winsup/cygwin/wininfo.h @@ -12,20 +12,13 @@ class muto; class wininfo { HWND hwnd; - static muto *lock; + static muto *_lock; public: - UINT timer_active; - struct itimerval itv; - DWORD start_time; - HANDLE window_started; operator HWND (); int __stdcall wininfo::process (HWND, UINT, WPARAM, LPARAM) __attribute__ ((regparm (3))); - int __stdcall setitimer (const struct itimerval *value, struct itimerval *oldvalue) - __attribute__ ((regparm (3))); - int __stdcall getitimer (struct itimerval *value) - __attribute__ ((regparm (2))); - wininfo (); + void lock (); + void release (); DWORD WINAPI winthread () __attribute__ ((regparm (1))); }; diff --git a/winsup/cygwin/winsup.h b/winsup/cygwin/winsup.h index f8c060bd7..515298ba2 100644 --- a/winsup/cygwin/winsup.h +++ b/winsup/cygwin/winsup.h @@ -223,9 +223,6 @@ void events_terminate (void); void __stdcall close_all_files (); -/* Check if running in a visible window station. */ -extern bool has_visible_window_station (void); - /* Globals that handle initialization of winsock in a child process. */ extern HANDLE wsock32_handle; extern HANDLE ws2_32_handle;