* 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.
This commit is contained in:
Christopher Faylor 2005-03-27 01:57:38 +00:00
parent 9eba97c0d5
commit ec98d19a08
25 changed files with 510 additions and 288 deletions

View File

@ -1,3 +1,70 @@
2005-03-26 Pierre Humblet <pierre.humblet@ieee.org>
Christopher Faylor <cgf@timesys.com>
* 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 <cgf@timesys.com>
* 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 <corinna@vinschen.de>
* fhandler.h (fhandler_socket::secret_event): Remove.

View File

@ -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 \

View File

@ -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 */

View File

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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -10,6 +10,8 @@ Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */
#include "winsup.h"
#include <wingdi.h>
#include <winuser.h>
#include <imagehlp.h>
#include <stdlib.h>
#include <setjmp.h>
@ -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)

View File

@ -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 <cgf@cygnus.com>

View File

@ -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)

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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).

View File

@ -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

View File

@ -0,0 +1,64 @@
/*-
* Written by J.T. Conklin <jtc@netbsd.org>
* 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 <sys/cdefs.h>
#include <sys/types.h>
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_ */

56
winsup/cygwin/lsearch.cc Normal file
View File

@ -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 <sys/types.h>
#include <sys/cdefs.h>
#define _SEARCH_PRIVATE
#include <search.h>
#include <stdint.h> /* for uint8_t */
#include <stdlib.h> /* for NULL */
#include <string.h> /* 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;
}

View File

@ -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 <corinna@vinschen.de>

View File

@ -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 <cgf@cygnus.com>

View File

@ -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 (&notify_thread, tt.evp.sigev_notify_attributes,
(void * (*) (void *)) tt.evp.sigev_notify_function,
tt.evp.sigev_value.sival_ptr);
int rc = pthread_create (&notify_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 = &it;
}
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;
}

View File

@ -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 <sos@prospect.com.ru>
@ -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 ();
}

View File

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

View File

@ -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;