2002-06-25 Thomas Pfaff <tpfaff@gmx.net>

* include/pthread.h (PTHREAD_CANCELED): Defined a reasonable
        value.
	* pthread.cc (pthread_exit): Call method instead of function.
	(pthread_setcancelstate): Ditto.
	(pthread_setcanceltype): Ditto.
	(pthread_testcancel): Ditto.
	* thread.h (pthread::cancel_event): New member.
        (__pthread_cancel_self): New prototype.
	(pthread::exit): New Method.
	(pthread::cancel): Ditto.
	(pthread::testcancel): Ditto.
	(pthread::cancel_self): Ditto.
	(pthread::static_cancel_self): Ditto.
	(pthread::setcancelstate): Ditto.
	(pthread::setcanceltype): Ditto.
	(__pthread_cancel): Give c++ linkage.
	(__pthread_exit): Remove.
	(__pthread_setcancelstate): Ditto.
	(__pthread_setcanceltype): Ditto.
	(__pthread_testcancel): Ditto.
	 * thread.cc (pthread::pthread): Inititialize cancel_event.
	(pthread::~pthread): Close cancel_event if needed.
	(pthread::create): Create cancel_event.
	(pthread::exit): New method. Replacement for __pthread_exit.
	(pthread::cancel): New method.
	(pthread::testcancel): Ditto.
	(pthread::static_cancel_self); New static method.
	(pthread::setcancelstate): New method. Replacement for
	__pthread_setcancelstate.
	(pthread::setcanceltype): New method. Replacement for
	__pthread_setcanceltype.
	(pthread::pop_cleanup_handler): Added lock for async cancel safe
	cancellation.
	(pthread::thread_init_wrapper): Change __pthread_exit to
	thread->exit().
	(__pthread_cancel): Call method thread->cancel().
	(__pthread_exit): Remove.
	(__pthread_setcancelstate): Ditto.
	(__pthread_setcanceltype): Ditto.
	(__pthread_testcancel): Ditto.
This commit is contained in:
Robert Collins 2002-07-04 14:17:30 +00:00
parent 875beea460
commit d288c1c78c
5 changed files with 385 additions and 281 deletions

View File

@ -1,3 +1,46 @@
2002-06-25 Thomas Pfaff <tpfaff@gmx.net>
* include/pthread.h (PTHREAD_CANCELED): Defined a reasonable
value.
* pthread.cc (pthread_exit): Call method instead of function.
(pthread_setcancelstate): Ditto.
(pthread_setcanceltype): Ditto.
(pthread_testcancel): Ditto.
* thread.h (pthread::cancel_event): New member.
(__pthread_cancel_self): New prototype.
(pthread::exit): New Method.
(pthread::cancel): Ditto.
(pthread::testcancel): Ditto.
(pthread::cancel_self): Ditto.
(pthread::static_cancel_self): Ditto.
(pthread::setcancelstate): Ditto.
(pthread::setcanceltype): Ditto.
(__pthread_cancel): Give c++ linkage.
(__pthread_exit): Remove.
(__pthread_setcancelstate): Ditto.
(__pthread_setcanceltype): Ditto.
(__pthread_testcancel): Ditto.
* thread.cc (pthread::pthread): Inititialize cancel_event.
(pthread::~pthread): Close cancel_event if needed.
(pthread::create): Create cancel_event.
(pthread::exit): New method. Replacement for __pthread_exit.
(pthread::cancel): New method.
(pthread::testcancel): Ditto.
(pthread::static_cancel_self); New static method.
(pthread::setcancelstate): New method. Replacement for
__pthread_setcancelstate.
(pthread::setcanceltype): New method. Replacement for
__pthread_setcanceltype.
(pthread::pop_cleanup_handler): Added lock for async cancel safe
cancellation.
(pthread::thread_init_wrapper): Change __pthread_exit to
thread->exit().
(__pthread_cancel): Call method thread->cancel().
(__pthread_exit): Remove.
(__pthread_setcancelstate): Ditto.
(__pthread_setcanceltype): Ditto.
(__pthread_testcancel): Ditto.
2002-06-02 Christopher Faylor <cgf@redhat.com>
* configure.in: Complain about lack of w32api directory.

View File

@ -42,7 +42,7 @@ extern "C"
#define PTHREAD_CANCEL_ENABLE 0
#define PTHREAD_CANCEL_DEFERRED 0
#define PTHREAD_CANCEL_DISABLE 1
#define PTHREAD_CANCELED
#define PTHREAD_CANCELED ((void *)-1)
/* this should be a value that can never be a valid address */
#define PTHREAD_COND_INITIALIZER (void *)21
#define PTHREAD_CREATE_DETACHED 1

View File

@ -140,7 +140,7 @@ pthread_attr_getstackaddr (const pthread_attr_t * attr, void **stackaddr)
void
pthread_exit (void *value_ptr)
{
return __pthread_exit (value_ptr);
return pthread::self()->exit (value_ptr);
}
int
@ -428,25 +428,25 @@ pthread_cancel (pthread_t thread)
int
pthread_setcancelstate (int state, int *oldstate)
{
return __pthread_setcancelstate (state, oldstate);
return pthread::self()->setcancelstate (state, oldstate);
}
int
pthread_setcanceltype (int type, int *oldtype)
{
return __pthread_setcanceltype (type, oldtype);
return pthread::self()->setcanceltype (type, oldtype);
}
void
pthread_testcancel (void)
{
__pthread_testcancel ();
pthread::self()->testcancel ();
}
void
_pthread_cleanup_push (__pthread_cleanup_handler *handler)
{
pthread::self()->push_cleanup_handler(handler);
pthread::self()->push_cleanup_handler (handler);
}
void

View File

@ -355,7 +355,8 @@ pthread::self ()
/* member methods */
pthread::pthread ():verifyable_object (PTHREAD_MAGIC), win32_obj_id (0),
cancelstate (0), canceltype (0), joiner (NULL), cleanup_stack(NULL)
cancelstate (0), canceltype (0), cancel_event(0),
joiner (NULL), cleanup_stack(NULL)
{
}
@ -363,6 +364,8 @@ pthread::~pthread ()
{
if (win32_obj_id)
CloseHandle (win32_obj_id);
if (cancel_event)
CloseHandle (cancel_event);
}
@ -394,6 +397,15 @@ pthread::create (void *(*func) (void *), pthread_attr *newattr,
return;
}
cancel_event = ::CreateEvent (NULL,TRUE,FALSE,NULL);
if (!cancel_event)
{
system_printf ("couldn't create cancel event, this %p LastError %d", this, GetLastError () );
/*we need the event for correct behaviour */
magic = 0;
return;
}
win32_obj_id = ::CreateThread (&sec_none_nih, attr.stacksize,
(LPTHREAD_START_ROUTINE) thread_init_wrapper,
this, CREATE_SUSPENDED, &thread_id);
@ -416,6 +428,304 @@ pthread::create (void *(*func) (void *), pthread_attr *newattr,
}
}
void
pthread::exit (void *value_ptr)
{
class pthread *thread = this;
// run cleanup handlers
pop_all_cleanup_handlers ();
MT_INTERFACE->destructors.IterateNull ();
mutex.Lock ();
// cleanup if thread is in detached state and not joined
if( __pthread_equal(&joiner, &thread ) )
delete this;
else
{
return_ptr = value_ptr;
mutex.UnLock ();
}
if (InterlockedDecrement (&MT_INTERFACE->threadcount) == 0)
::exit (0);
else
ExitThread (0);
}
int
pthread::cancel (void)
{
class pthread *thread = this;
class pthread *self = pthread::self ();
mutex.Lock ();
if (canceltype == PTHREAD_CANCEL_DEFERRED ||
cancelstate == PTHREAD_CANCEL_DISABLE)
{
// cancel deferred
mutex.UnLock ();
SetEvent (cancel_event);
return 0;
}
else if (__pthread_equal(&thread, &self))
{
mutex.UnLock ();
cancel_self ();
return 0; // Never reached
}
// cancel asynchronous
SuspendThread (win32_obj_id);
if (WaitForSingleObject (win32_obj_id, 0) == WAIT_TIMEOUT)
{
CONTEXT context;
context.ContextFlags = CONTEXT_CONTROL;
GetThreadContext (win32_obj_id, &context);
context.Eip = (DWORD) pthread::static_cancel_self;
SetThreadContext (win32_obj_id, &context);
}
mutex.UnLock ();
ResumeThread (win32_obj_id);
return 0;
/*
TODO: insert pthread_testcancel into the required functions
the required function list is: *indicates done, X indicates not present in cygwin.
aio_suspend ()
*close ()
*creat ()
fcntl ()
fsync ()
getmsg ()
getpmsg ()
lockf ()
mq_receive ()
mq_send ()
msgrcv ()
msgsnd ()
msync ()
nanosleep ()
open ()
pause ()
poll ()
pread ()
pthread_cond_timedwait ()
pthread_cond_wait ()
*pthread_join ()
pthread_testcancel ()
putmsg ()
putpmsg ()
pwrite ()
read ()
readv ()
select ()
sem_wait ()
sigpause ()
sigsuspend ()
sigtimedwait ()
sigwait ()
sigwaitinfo ()
*sleep ()
system ()
tcdrain ()
*usleep ()
wait ()
wait3()
waitid ()
waitpid ()
write ()
writev ()
the optional list is:
catclose ()
catgets ()
catopen ()
closedir ()
closelog ()
ctermid ()
dbm_close ()
dbm_delete ()
dbm_fetch ()
dbm_nextkey ()
dbm_open ()
dbm_store ()
dlclose ()
dlopen ()
endgrent ()
endpwent ()
endutxent ()
fclose ()
fcntl ()
fflush ()
fgetc ()
fgetpos ()
fgets ()
fgetwc ()
fgetws ()
fopen ()
fprintf ()
fputc ()
fputs ()
fputwc ()
fputws ()
fread ()
freopen ()
fscanf ()
fseek ()
fseeko ()
fsetpos ()
ftell ()
ftello ()
ftw ()
fwprintf ()
fwrite ()
fwscanf ()
getc ()
getc_unlocked ()
getchar ()
getchar_unlocked ()
getcwd ()
getdate ()
getgrent ()
getgrgid ()
getgrgid_r ()
getgrnam ()
getgrnam_r ()
getlogin ()
getlogin_r ()
getpwent ()
*getpwnam ()
*getpwnam_r ()
*getpwuid ()
*getpwuid_r ()
gets ()
getutxent ()
getutxid ()
getutxline ()
getw ()
getwc ()
getwchar ()
getwd ()
glob ()
iconv_close ()
iconv_open ()
ioctl ()
lseek ()
mkstemp ()
nftw ()
opendir ()
openlog ()
pclose ()
perror ()
popen ()
printf ()
putc ()
putc_unlocked ()
putchar ()
putchar_unlocked ()
puts ()
pututxline ()
putw ()
putwc ()
putwchar ()
readdir ()
readdir_r ()
remove ()
rename ()
rewind ()
rewinddir ()
scanf ()
seekdir ()
semop ()
setgrent ()
setpwent ()
setutxent ()
strerror ()
syslog ()
tmpfile ()
tmpnam ()
ttyname ()
ttyname_r ()
ungetc ()
ungetwc ()
unlink ()
vfprintf ()
vfwprintf ()
vprintf ()
vwprintf ()
wprintf ()
wscanf ()
Note, that for fcntl (), for any value of the cmd argument.
And we must not introduce cancellation points anywhere else that's part of the posix or
opengroup specs.
*/
}
void
pthread::testcancel (void)
{
if (cancelstate == PTHREAD_CANCEL_DISABLE)
return;
if( WAIT_OBJECT_0 == WaitForSingleObject (cancel_event, 0 ) )
cancel_self ();
}
void
pthread::static_cancel_self (void)
{
pthread::self()->cancel_self ();
}
int
pthread::setcancelstate (int state, int *oldstate)
{
int result = 0;
mutex.Lock ();
if (state != PTHREAD_CANCEL_ENABLE && state != PTHREAD_CANCEL_DISABLE)
result = EINVAL;
else
{
if (oldstate)
*oldstate = cancelstate;
cancelstate = state;
}
mutex.UnLock ();
return result;
}
int
pthread::setcanceltype (int type, int *oldtype)
{
int result = 0;
mutex.Lock ();
if (type != PTHREAD_CANCEL_DEFERRED && type != PTHREAD_CANCEL_ASYNCHRONOUS)
result = EINVAL;
else
{
if (oldtype)
*oldtype = canceltype;
canceltype = type;
}
mutex.UnLock ();
return result;
}
void
pthread::push_cleanup_handler (__pthread_cleanup_handler *handler)
{
@ -433,6 +743,8 @@ pthread::pop_cleanup_handler (int const execute)
// TODO: send a signal or something to the thread ?
api_fatal ("Attempt to execute a cleanup handler across threads");
mutex.Lock ();
if (cleanup_stack != NULL)
{
__pthread_cleanup_handler *handler = cleanup_stack;
@ -441,6 +753,8 @@ pthread::pop_cleanup_handler (int const execute)
(*handler->function) (handler->arg);
cleanup_stack = handler->next;
}
mutex.UnLock ();
}
void
@ -967,11 +1281,11 @@ pthread::thread_init_wrapper (void *_arg)
/*the OS doesn't check this for <= 64 Tls entries (pre win2k) */
TlsSetValue (MT_INTERFACE->thread_self_dwTlsIndex, thread);
thread->mutex.Lock();
thread->mutex.Lock ();
// if thread is detached force cleanup on exit
if (thread->attr.joinable == PTHREAD_CREATE_DETACHED && thread->joiner == NULL)
thread->joiner = pthread::self ();
thread->mutex.UnLock();
thread->mutex.UnLock ();
#ifdef _CYG_THREAD_FAILSAFE
if (_REENT == _impure_ptr)
@ -984,7 +1298,7 @@ pthread::thread_init_wrapper (void *_arg)
// call the user's thread
void *ret = thread->function (thread->arg);
__pthread_exit (ret);
thread->exit (ret);
#if 0
// ??? This code only runs if the thread exits by returning.
@ -1038,251 +1352,13 @@ __pthread_once (pthread_once_t *once_control, void (*init_routine) (void))
return 0;
}
/*Cancelability states */
/*Perform the actual cancel */
void
__pthread_cleanup (pthread_t thread)
{
}
int
__pthread_cancel (pthread_t thread)
{
if (verifyable_object_isvalid (&thread, PTHREAD_MAGIC) != VALID_OBJECT)
return ESRCH;
if (thread->cancelstate == PTHREAD_CANCEL_ENABLE)
{
#if 0
/*once all the functions call testcancel (), we will do this */
if (thread->canceltype == PTHREAD_CANCEL_DEFERRED)
{
}
else
{
/*possible FIXME: this function is meant to return asynchronously
*from the cancellation routine actually firing. So we may need some sort
*of signal to be sent that is immediately recieved and acted on.
*/
__pthread_cleanup (thread);
}
#endif
}
/* return 0;
*/
return ESRCH;
/*
we return ESRCH until all the required functions call testcancel ();
this will give applications predictable behaviour.
the required function list is: *indicates done, X indicates not present in cygwin.
aio_suspend ()
*close ()
*creat ()
fcntl ()
fsync ()
getmsg ()
getpmsg ()
lockf ()
mq_receive ()
mq_send ()
msgrcv ()
msgsnd ()
msync ()
nanosleep ()
open ()
pause ()
poll ()
pread ()
pthread_cond_timedwait ()
pthread_cond_wait ()
*pthread_join ()
pthread_testcancel ()
putmsg ()
putpmsg ()
pwrite ()
read ()
readv ()
select ()
sem_wait ()
sigpause ()
sigsuspend ()
sigtimedwait ()
sigwait ()
sigwaitinfo ()
*sleep ()
system ()
tcdrain ()
*usleep ()
wait ()
wait3()
waitid ()
waitpid ()
write ()
writev ()
the optional list is:
catclose ()
catgets ()
catopen ()
closedir ()
closelog ()
ctermid ()
dbm_close ()
dbm_delete ()
dbm_fetch ()
dbm_nextkey ()
dbm_open ()
dbm_store ()
dlclose ()
dlopen ()
endgrent ()
endpwent ()
endutxent ()
fclose ()
fcntl ()
fflush ()
fgetc ()
fgetpos ()
fgets ()
fgetwc ()
fgetws ()
fopen ()
fprintf ()
fputc ()
fputs ()
fputwc ()
fputws ()
fread ()
freopen ()
fscanf ()
fseek ()
fseeko ()
fsetpos ()
ftell ()
ftello ()
ftw ()
fwprintf ()
fwrite ()
fwscanf ()
getc ()
getc_unlocked ()
getchar ()
getchar_unlocked ()
getcwd ()
getdate ()
getgrent ()
getgrgid ()
getgrgid_r ()
getgrnam ()
getgrnam_r ()
getlogin ()
getlogin_r ()
getpwent ()
*getpwnam ()
*getpwnam_r ()
*getpwuid ()
*getpwuid_r ()
gets ()
getutxent ()
getutxid ()
getutxline ()
getw ()
getwc ()
getwchar ()
getwd ()
glob ()
iconv_close ()
iconv_open ()
ioctl ()
lseek ()
mkstemp ()
nftw ()
opendir ()
openlog ()
pclose ()
perror ()
popen ()
printf ()
putc ()
putc_unlocked ()
putchar ()
putchar_unlocked ()
puts ()
pututxline ()
putw ()
putwc ()
putwchar ()
readdir ()
readdir_r ()
remove ()
rename ()
rewind ()
rewinddir ()
scanf ()
seekdir ()
semop ()
setgrent ()
setpwent ()
setutxent ()
strerror ()
syslog ()
tmpfile ()
tmpnam ()
ttyname ()
ttyname_r ()
ungetc ()
ungetwc ()
unlink ()
vfprintf ()
vfwprintf ()
vprintf ()
vwprintf ()
wprintf ()
wscanf ()
Note, that for fcntl (), for any value of the cmd argument.
And we must not introduce cancellation points anywhere else that's part of the posix or
opengroup specs.
*/
}
/*no races in these three functions: they are all current-thread-only */
int
__pthread_setcancelstate (int state, int *oldstate)
{
class pthread *thread = pthread::self ();
if (state != PTHREAD_CANCEL_ENABLE && state != PTHREAD_CANCEL_DISABLE)
return EINVAL;
*oldstate = thread->cancelstate;
thread->cancelstate = state;
return 0;
}
int
__pthread_setcanceltype (int type, int *oldtype)
{
class pthread *thread = pthread::self ();
if (type != PTHREAD_CANCEL_DEFERRED && type != PTHREAD_CANCEL_ASYNCHRONOUS)
return EINVAL;
*oldtype = thread->canceltype;
thread->canceltype = type;
return 0;
}
/*deferred cancellation request handler */
void
__pthread_testcancel (void)
{
class pthread *thread = pthread::self ();
if (thread->cancelstate == PTHREAD_CANCEL_DISABLE)
return;
/*check the cancellation event object here - not neededuntil pthread_cancel actually
*does something*/
return thread->cancel ();
}
/*
@ -1556,32 +1632,6 @@ __pthread_attr_destroy (pthread_attr_t *attr)
return 0;
}
void
__pthread_exit (void *value_ptr)
{
pthread * thread = pthread::self ();
// run cleanup handlers
thread->pop_all_cleanup_handlers ();
MT_INTERFACE->destructors.IterateNull ();
thread->mutex.Lock();
// cleanup if thread is in detached state and not joined
if( __pthread_equal(&thread->joiner, &thread ) )
delete thread;
else
{
thread->return_ptr = value_ptr;
thread->mutex.UnLock();
}
if (InterlockedDecrement (&MT_INTERFACE->threadcount) == 0)
exit (0);
else
ExitThread (0);
}
int
__pthread_join (pthread_t *thread, void **return_val)
{

View File

@ -266,6 +266,7 @@ public:
void *return_ptr;
bool suspended;
int cancelstate, canceltype;
HANDLE cancel_event;
pthread_t joiner;
// int joinable;
@ -287,6 +288,19 @@ public:
pthread ();
~pthread ();
void exit (void *value_ptr);
int cancel ();
void testcancel ();
void cancel_self ()
{
exit (PTHREAD_CANCELED);
}
static void static_cancel_self ();
int setcancelstate (int state, int *oldstate);
int setcanceltype (int type, int *oldtype);
void push_cleanup_handler (__pthread_cleanup_handler *handler);
void pop_cleanup_handler (int const execute);
@ -298,7 +312,6 @@ private:
__pthread_cleanup_handler *cleanup_stack;
pthread_mutex mutex;
friend void __pthread_exit (void *value_ptr);
friend int __pthread_join (pthread_t * thread, void **return_val);
friend int __pthread_detach (pthread_t * thread);
@ -406,8 +419,10 @@ void __pthread_atforkprepare(void);
void __pthread_atforkparent(void);
void __pthread_atforkchild(void);
/* Cancellation */
int __pthread_cancel (pthread_t thread);
/* Thread Exit */
void __pthread_exit (void *value_ptr);
int __pthread_join (pthread_t * thread, void **return_val);
int __pthread_detach (pthread_t * thread);
@ -504,10 +519,6 @@ int __pthread_setschedparam (pthread_t thread, int policy,
const struct sched_param *param);
/* cancelability states */
int __pthread_cancel (pthread_t thread);
int __pthread_setcancelstate (int state, int *oldstate);
int __pthread_setcanceltype (int type, int *oldtype);
void __pthread_testcancel (void);
/* Semaphores */
int __sem_init (sem_t * sem, int pshared, unsigned int value);