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> 2002-06-02 Christopher Faylor <cgf@redhat.com>
* configure.in: Complain about lack of w32api directory. * configure.in: Complain about lack of w32api directory.

View File

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

View File

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

View File

@ -355,7 +355,8 @@ pthread::self ()
/* member methods */ /* member methods */
pthread::pthread ():verifyable_object (PTHREAD_MAGIC), win32_obj_id (0), 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) if (win32_obj_id)
CloseHandle (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; 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, win32_obj_id = ::CreateThread (&sec_none_nih, attr.stacksize,
(LPTHREAD_START_ROUTINE) thread_init_wrapper, (LPTHREAD_START_ROUTINE) thread_init_wrapper,
this, CREATE_SUSPENDED, &thread_id); 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 void
pthread::push_cleanup_handler (__pthread_cleanup_handler *handler) 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 ? // TODO: send a signal or something to the thread ?
api_fatal ("Attempt to execute a cleanup handler across threads"); api_fatal ("Attempt to execute a cleanup handler across threads");
mutex.Lock ();
if (cleanup_stack != NULL) if (cleanup_stack != NULL)
{ {
__pthread_cleanup_handler *handler = cleanup_stack; __pthread_cleanup_handler *handler = cleanup_stack;
@ -441,6 +753,8 @@ pthread::pop_cleanup_handler (int const execute)
(*handler->function) (handler->arg); (*handler->function) (handler->arg);
cleanup_stack = handler->next; cleanup_stack = handler->next;
} }
mutex.UnLock ();
} }
void void
@ -967,11 +1281,11 @@ pthread::thread_init_wrapper (void *_arg)
/*the OS doesn't check this for <= 64 Tls entries (pre win2k) */ /*the OS doesn't check this for <= 64 Tls entries (pre win2k) */
TlsSetValue (MT_INTERFACE->thread_self_dwTlsIndex, thread); TlsSetValue (MT_INTERFACE->thread_self_dwTlsIndex, thread);
thread->mutex.Lock(); thread->mutex.Lock ();
// if thread is detached force cleanup on exit // if thread is detached force cleanup on exit
if (thread->attr.joinable == PTHREAD_CREATE_DETACHED && thread->joiner == NULL) if (thread->attr.joinable == PTHREAD_CREATE_DETACHED && thread->joiner == NULL)
thread->joiner = pthread::self (); thread->joiner = pthread::self ();
thread->mutex.UnLock(); thread->mutex.UnLock ();
#ifdef _CYG_THREAD_FAILSAFE #ifdef _CYG_THREAD_FAILSAFE
if (_REENT == _impure_ptr) if (_REENT == _impure_ptr)
@ -984,7 +1298,7 @@ pthread::thread_init_wrapper (void *_arg)
// call the user's thread // call the user's thread
void *ret = thread->function (thread->arg); void *ret = thread->function (thread->arg);
__pthread_exit (ret); thread->exit (ret);
#if 0 #if 0
// ??? This code only runs if the thread exits by returning. // ??? 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; return 0;
} }
/*Cancelability states */
/*Perform the actual cancel */
void
__pthread_cleanup (pthread_t thread)
{
}
int int
__pthread_cancel (pthread_t thread) __pthread_cancel (pthread_t thread)
{ {
if (verifyable_object_isvalid (&thread, PTHREAD_MAGIC) != VALID_OBJECT) if (verifyable_object_isvalid (&thread, PTHREAD_MAGIC) != VALID_OBJECT)
return ESRCH; 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; return thread->cancel ();
/*
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*/
} }
/* /*
@ -1556,32 +1632,6 @@ __pthread_attr_destroy (pthread_attr_t *attr)
return 0; 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 int
__pthread_join (pthread_t *thread, void **return_val) __pthread_join (pthread_t *thread, void **return_val)
{ {

View File

@ -266,6 +266,7 @@ public:
void *return_ptr; void *return_ptr;
bool suspended; bool suspended;
int cancelstate, canceltype; int cancelstate, canceltype;
HANDLE cancel_event;
pthread_t joiner; pthread_t joiner;
// int joinable; // int joinable;
@ -287,6 +288,19 @@ public:
pthread (); pthread ();
~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 push_cleanup_handler (__pthread_cleanup_handler *handler);
void pop_cleanup_handler (int const execute); void pop_cleanup_handler (int const execute);
@ -298,7 +312,6 @@ private:
__pthread_cleanup_handler *cleanup_stack; __pthread_cleanup_handler *cleanup_stack;
pthread_mutex mutex; pthread_mutex mutex;
friend void __pthread_exit (void *value_ptr);
friend int __pthread_join (pthread_t * thread, void **return_val); friend int __pthread_join (pthread_t * thread, void **return_val);
friend int __pthread_detach (pthread_t * thread); friend int __pthread_detach (pthread_t * thread);
@ -406,8 +419,10 @@ void __pthread_atforkprepare(void);
void __pthread_atforkparent(void); void __pthread_atforkparent(void);
void __pthread_atforkchild(void); void __pthread_atforkchild(void);
/* Cancellation */
int __pthread_cancel (pthread_t thread);
/* Thread Exit */ /* Thread Exit */
void __pthread_exit (void *value_ptr);
int __pthread_join (pthread_t * thread, void **return_val); int __pthread_join (pthread_t * thread, void **return_val);
int __pthread_detach (pthread_t * thread); int __pthread_detach (pthread_t * thread);
@ -504,10 +519,6 @@ int __pthread_setschedparam (pthread_t thread, int policy,
const struct sched_param *param); const struct sched_param *param);
/* cancelability states */ /* 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 */ /* Semaphores */
int __sem_init (sem_t * sem, int pshared, unsigned int value); int __sem_init (sem_t * sem, int pshared, unsigned int value);