Fix problems with cancellation while in critical regions.
o Cancellation flags were not getting properly set/cleared. o Loops waiting for internal locks were not being exited correctly by a cancelled thread. o Minor spelling (cancelation -> cancellation) and formatting corrections (missing tab). Found by: tg Reviewed by: jasone
This commit is contained in:
parent
5cb0438d6f
commit
7e691e1eb4
@ -20,8 +20,16 @@ pthread_cancel(pthread_t pthread)
|
||||
/* Protect the scheduling queues: */
|
||||
_thread_kern_sig_defer();
|
||||
|
||||
/* Check if we need to kick it back into the run queue: */
|
||||
if ((pthread->cancelflags & PTHREAD_CANCEL_DISABLE) == 0)
|
||||
if (((pthread->cancelflags & PTHREAD_CANCEL_DISABLE) != 0) ||
|
||||
(((pthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) == 0) &&
|
||||
((pthread->cancelflags & PTHREAD_AT_CANCEL_POINT) == 0)))
|
||||
/* Just mark it for cancellation: */
|
||||
pthread->cancelflags |= PTHREAD_CANCELLING;
|
||||
else {
|
||||
/*
|
||||
* Check if we need to kick it back into the
|
||||
* run queue:
|
||||
*/
|
||||
switch (pthread->state) {
|
||||
case PS_RUNNING:
|
||||
/* No need to resume: */
|
||||
@ -33,7 +41,7 @@ pthread_cancel(pthread_t pthread)
|
||||
case PS_FDW_WAIT:
|
||||
case PS_POLL_WAIT:
|
||||
case PS_SELECT_WAIT:
|
||||
/* Remove these threads from the work queue: */
|
||||
/* Remove these threads from the work queue: */
|
||||
if ((pthread->flags & PTHREAD_FLAGS_IN_WORKQ)
|
||||
!= 0)
|
||||
PTHREAD_WORKQ_REMOVE(pthread);
|
||||
@ -75,7 +83,9 @@ pthread_cancel(pthread_t pthread)
|
||||
case PS_STATE_MAX:
|
||||
/* Ignore - only here to silence -Wall: */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Unprotect the scheduling queues: */
|
||||
_thread_kern_sig_undefer();
|
||||
|
||||
@ -96,7 +106,7 @@ pthread_setcancelstate(int state, int *oldstate)
|
||||
case PTHREAD_CANCEL_ENABLE:
|
||||
if (oldstate != NULL)
|
||||
*oldstate = ostate;
|
||||
_thread_run->cancelflags &= PTHREAD_CANCEL_ENABLE;
|
||||
_thread_run->cancelflags &= ~PTHREAD_CANCEL_DISABLE;
|
||||
if ((_thread_run->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) != 0)
|
||||
pthread_testcancel();
|
||||
ret = 0;
|
||||
@ -145,7 +155,6 @@ pthread_setcanceltype(int type, int *oldtype)
|
||||
void
|
||||
pthread_testcancel(void)
|
||||
{
|
||||
|
||||
if (((_thread_run->cancelflags & PTHREAD_CANCEL_DISABLE) == 0) &&
|
||||
((_thread_run->cancelflags & PTHREAD_CANCELLING) != 0)) {
|
||||
/*
|
||||
|
@ -274,6 +274,7 @@ pthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex)
|
||||
}
|
||||
|
||||
if ((_thread_run->cancelflags & PTHREAD_CANCEL_NEEDED) != 0) {
|
||||
_thread_run->cancelflags &= ~PTHREAD_CANCEL_NEEDED;
|
||||
_thread_exit_cleanup();
|
||||
pthread_exit(PTHREAD_CANCELED);
|
||||
}
|
||||
@ -431,6 +432,7 @@ pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
|
||||
}
|
||||
|
||||
if ((_thread_run->cancelflags & PTHREAD_CANCEL_NEEDED) != 0) {
|
||||
_thread_run->cancelflags &= ~PTHREAD_CANCEL_NEEDED;
|
||||
_thread_exit_cleanup();
|
||||
pthread_exit(PTHREAD_CANCELED);
|
||||
}
|
||||
|
@ -398,12 +398,13 @@ _thread_fd_lock(int fd, int lock_type, struct timespec * timeout)
|
||||
}
|
||||
|
||||
/* Check the file descriptor and lock types: */
|
||||
if (lock_type == FD_WRITE || lock_type == FD_RDWR) {
|
||||
if (_thread_run->interrupted == 0 &&
|
||||
(lock_type == FD_WRITE || lock_type == FD_RDWR)) {
|
||||
/*
|
||||
* Enter a loop to wait for the file descriptor to be
|
||||
* locked for write for the current thread:
|
||||
* Wait for the file descriptor to be locked
|
||||
* for write for the current thread:
|
||||
*/
|
||||
while (_thread_fd_table[fd]->w_owner != _thread_run) {
|
||||
if (_thread_fd_table[fd]->w_owner != _thread_run) {
|
||||
/*
|
||||
* Check if the file descriptor is locked by
|
||||
* another thread:
|
||||
@ -483,6 +484,7 @@ _thread_fd_lock(int fd, int lock_type, struct timespec * timeout)
|
||||
ret = -1;
|
||||
errno = EINTR;
|
||||
} else {
|
||||
_thread_run->cancelflags &= ~PTHREAD_CANCEL_NEEDED;
|
||||
_thread_exit_cleanup();
|
||||
pthread_exit(PTHREAD_CANCELED);
|
||||
}
|
||||
@ -639,10 +641,10 @@ _thread_fd_lock_debug(int fd, int lock_type, struct timespec * timeout,
|
||||
/* Check the file descriptor and lock types: */
|
||||
if (lock_type == FD_READ || lock_type == FD_RDWR) {
|
||||
/*
|
||||
* Enter a loop to wait for the file descriptor to be
|
||||
* locked for read for the current thread:
|
||||
* Wait for the file descriptor to be locked
|
||||
* for read for the current thread:
|
||||
*/
|
||||
while (_thread_fd_table[fd]->r_owner != _thread_run) {
|
||||
if (_thread_fd_table[fd]->r_owner != _thread_run) {
|
||||
/*
|
||||
* Check if the file descriptor is locked by
|
||||
* another thread:
|
||||
@ -691,6 +693,10 @@ _thread_fd_lock_debug(int fd, int lock_type, struct timespec * timeout,
|
||||
*/
|
||||
_SPINLOCK(&_thread_fd_table[fd]->lock);
|
||||
|
||||
if (_thread_run->interrupted != 0) {
|
||||
FDQ_REMOVE(&_thread_fd_table[fd]->r_queue,
|
||||
_thread_run);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* The running thread now owns the
|
||||
@ -713,17 +719,19 @@ _thread_fd_lock_debug(int fd, int lock_type, struct timespec * timeout,
|
||||
}
|
||||
}
|
||||
|
||||
/* Increment the read lock count: */
|
||||
_thread_fd_table[fd]->r_lockcount++;
|
||||
if (_thread_fd_table[fd]->r_owner == _thread_run)
|
||||
/* Increment the read lock count: */
|
||||
_thread_fd_table[fd]->r_lockcount++;
|
||||
}
|
||||
|
||||
/* Check the file descriptor and lock types: */
|
||||
if (lock_type == FD_WRITE || lock_type == FD_RDWR) {
|
||||
if (_thread_run->interrupted == 0 &&
|
||||
(lock_type == FD_WRITE || lock_type == FD_RDWR)) {
|
||||
/*
|
||||
* Enter a loop to wait for the file descriptor to be
|
||||
* locked for write for the current thread:
|
||||
* Wait for the file descriptor to be locked
|
||||
* for write for the current thread:
|
||||
*/
|
||||
while (_thread_fd_table[fd]->w_owner != _thread_run) {
|
||||
if (_thread_fd_table[fd]->w_owner != _thread_run) {
|
||||
/*
|
||||
* Check if the file descriptor is locked by
|
||||
* another thread:
|
||||
@ -771,6 +779,11 @@ _thread_fd_lock_debug(int fd, int lock_type, struct timespec * timeout,
|
||||
* table entry again:
|
||||
*/
|
||||
_SPINLOCK(&_thread_fd_table[fd]->lock);
|
||||
|
||||
if (_thread_run->interrupted != 0) {
|
||||
FDQ_REMOVE(&_thread_fd_table[fd]->w_queue,
|
||||
_thread_run);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* The running thread now owns the
|
||||
@ -794,8 +807,9 @@ _thread_fd_lock_debug(int fd, int lock_type, struct timespec * timeout,
|
||||
}
|
||||
}
|
||||
|
||||
/* Increment the write lock count: */
|
||||
_thread_fd_table[fd]->w_lockcount++;
|
||||
if (_thread_fd_table[fd]->w_owner == _thread_run)
|
||||
/* Increment the write lock count: */
|
||||
_thread_fd_table[fd]->w_lockcount++;
|
||||
}
|
||||
|
||||
/* Unlock the file descriptor table entry: */
|
||||
@ -806,6 +820,7 @@ _thread_fd_lock_debug(int fd, int lock_type, struct timespec * timeout,
|
||||
ret = -1;
|
||||
errno = EINTR;
|
||||
} else {
|
||||
_thread_run->cancelflags &= ~PTHREAD_CANCEL_NEEDED;
|
||||
_thread_exit_cleanup();
|
||||
pthread_exit(PTHREAD_CANCELED);
|
||||
}
|
||||
|
@ -256,7 +256,8 @@ _flockfile_debug(FILE * fp, char *fname, int lineno)
|
||||
_thread_kern_sig_undefer();
|
||||
|
||||
if (((_thread_run->cancelflags & PTHREAD_CANCEL_NEEDED) != 0) &&
|
||||
(_thread_run->cancelflags & PTHREAD_CANCEL_DISABLE) != 0) {
|
||||
(_thread_run->cancelflags & PTHREAD_CANCEL_DISABLE) != 0) {
|
||||
_thread_run->cancelflags &= ~PTHREAD_CANCEL_NEEDED;
|
||||
_thread_exit_cleanup();
|
||||
pthread_exit(PTHREAD_CANCELED);
|
||||
}
|
||||
|
@ -98,6 +98,7 @@ pthread_join(pthread_t pthread, void **thread_return)
|
||||
_thread_kern_sig_undefer();
|
||||
|
||||
if ((_thread_run->cancelflags & PTHREAD_CANCEL_NEEDED) != 0) {
|
||||
_thread_run->cancelflags &= ~PTHREAD_CANCEL_NEEDED;
|
||||
_thread_exit_cleanup();
|
||||
pthread_exit(PTHREAD_CANCELED);
|
||||
}
|
||||
|
@ -111,7 +111,7 @@ __asm__("fnsave %0": :"m"(*fdata));
|
||||
if (((_thread_run->cancelflags & PTHREAD_AT_CANCEL_POINT) == 0) &&
|
||||
((_thread_run->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) != 0)) {
|
||||
/*
|
||||
* Cancelations override signals.
|
||||
* Cancellations override signals.
|
||||
*
|
||||
* Stick a cancellation point at the start of
|
||||
* each async-cancellable thread's resumption.
|
||||
|
@ -623,6 +623,7 @@ pthread_mutex_lock(pthread_mutex_t * mutex)
|
||||
_thread_kern_sig_undefer();
|
||||
|
||||
if ((_thread_run->cancelflags & PTHREAD_CANCEL_NEEDED) != 0) {
|
||||
_thread_run->cancelflags &= ~PTHREAD_CANCEL_NEEDED;
|
||||
_thread_exit_cleanup();
|
||||
pthread_exit(PTHREAD_CANCELED);
|
||||
}
|
||||
|
@ -67,8 +67,8 @@ write(int fd, const void *buf, size_t nbytes)
|
||||
/* File is not open for write: */
|
||||
errno = EBADF;
|
||||
_FD_UNLOCK(fd, FD_WRITE);
|
||||
_thread_leave_cancellation_point();
|
||||
return (-1);
|
||||
_thread_leave_cancellation_point();
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Check if file operations are to block */
|
||||
|
@ -20,8 +20,16 @@ pthread_cancel(pthread_t pthread)
|
||||
/* Protect the scheduling queues: */
|
||||
_thread_kern_sig_defer();
|
||||
|
||||
/* Check if we need to kick it back into the run queue: */
|
||||
if ((pthread->cancelflags & PTHREAD_CANCEL_DISABLE) == 0)
|
||||
if (((pthread->cancelflags & PTHREAD_CANCEL_DISABLE) != 0) ||
|
||||
(((pthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) == 0) &&
|
||||
((pthread->cancelflags & PTHREAD_AT_CANCEL_POINT) == 0)))
|
||||
/* Just mark it for cancellation: */
|
||||
pthread->cancelflags |= PTHREAD_CANCELLING;
|
||||
else {
|
||||
/*
|
||||
* Check if we need to kick it back into the
|
||||
* run queue:
|
||||
*/
|
||||
switch (pthread->state) {
|
||||
case PS_RUNNING:
|
||||
/* No need to resume: */
|
||||
@ -33,7 +41,7 @@ pthread_cancel(pthread_t pthread)
|
||||
case PS_FDW_WAIT:
|
||||
case PS_POLL_WAIT:
|
||||
case PS_SELECT_WAIT:
|
||||
/* Remove these threads from the work queue: */
|
||||
/* Remove these threads from the work queue: */
|
||||
if ((pthread->flags & PTHREAD_FLAGS_IN_WORKQ)
|
||||
!= 0)
|
||||
PTHREAD_WORKQ_REMOVE(pthread);
|
||||
@ -75,7 +83,9 @@ pthread_cancel(pthread_t pthread)
|
||||
case PS_STATE_MAX:
|
||||
/* Ignore - only here to silence -Wall: */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Unprotect the scheduling queues: */
|
||||
_thread_kern_sig_undefer();
|
||||
|
||||
@ -96,7 +106,7 @@ pthread_setcancelstate(int state, int *oldstate)
|
||||
case PTHREAD_CANCEL_ENABLE:
|
||||
if (oldstate != NULL)
|
||||
*oldstate = ostate;
|
||||
_thread_run->cancelflags &= PTHREAD_CANCEL_ENABLE;
|
||||
_thread_run->cancelflags &= ~PTHREAD_CANCEL_DISABLE;
|
||||
if ((_thread_run->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) != 0)
|
||||
pthread_testcancel();
|
||||
ret = 0;
|
||||
@ -145,7 +155,6 @@ pthread_setcanceltype(int type, int *oldtype)
|
||||
void
|
||||
pthread_testcancel(void)
|
||||
{
|
||||
|
||||
if (((_thread_run->cancelflags & PTHREAD_CANCEL_DISABLE) == 0) &&
|
||||
((_thread_run->cancelflags & PTHREAD_CANCELLING) != 0)) {
|
||||
/*
|
||||
|
@ -274,6 +274,7 @@ pthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex)
|
||||
}
|
||||
|
||||
if ((_thread_run->cancelflags & PTHREAD_CANCEL_NEEDED) != 0) {
|
||||
_thread_run->cancelflags &= ~PTHREAD_CANCEL_NEEDED;
|
||||
_thread_exit_cleanup();
|
||||
pthread_exit(PTHREAD_CANCELED);
|
||||
}
|
||||
@ -431,6 +432,7 @@ pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
|
||||
}
|
||||
|
||||
if ((_thread_run->cancelflags & PTHREAD_CANCEL_NEEDED) != 0) {
|
||||
_thread_run->cancelflags &= ~PTHREAD_CANCEL_NEEDED;
|
||||
_thread_exit_cleanup();
|
||||
pthread_exit(PTHREAD_CANCELED);
|
||||
}
|
||||
|
@ -98,6 +98,7 @@ pthread_join(pthread_t pthread, void **thread_return)
|
||||
_thread_kern_sig_undefer();
|
||||
|
||||
if ((_thread_run->cancelflags & PTHREAD_CANCEL_NEEDED) != 0) {
|
||||
_thread_run->cancelflags &= ~PTHREAD_CANCEL_NEEDED;
|
||||
_thread_exit_cleanup();
|
||||
pthread_exit(PTHREAD_CANCELED);
|
||||
}
|
||||
|
@ -111,7 +111,7 @@ __asm__("fnsave %0": :"m"(*fdata));
|
||||
if (((_thread_run->cancelflags & PTHREAD_AT_CANCEL_POINT) == 0) &&
|
||||
((_thread_run->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) != 0)) {
|
||||
/*
|
||||
* Cancelations override signals.
|
||||
* Cancellations override signals.
|
||||
*
|
||||
* Stick a cancellation point at the start of
|
||||
* each async-cancellable thread's resumption.
|
||||
|
@ -623,6 +623,7 @@ pthread_mutex_lock(pthread_mutex_t * mutex)
|
||||
_thread_kern_sig_undefer();
|
||||
|
||||
if ((_thread_run->cancelflags & PTHREAD_CANCEL_NEEDED) != 0) {
|
||||
_thread_run->cancelflags &= ~PTHREAD_CANCEL_NEEDED;
|
||||
_thread_exit_cleanup();
|
||||
pthread_exit(PTHREAD_CANCELED);
|
||||
}
|
||||
|
@ -67,8 +67,8 @@ write(int fd, const void *buf, size_t nbytes)
|
||||
/* File is not open for write: */
|
||||
errno = EBADF;
|
||||
_FD_UNLOCK(fd, FD_WRITE);
|
||||
_thread_leave_cancellation_point();
|
||||
return (-1);
|
||||
_thread_leave_cancellation_point();
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Check if file operations are to block */
|
||||
|
@ -20,8 +20,16 @@ pthread_cancel(pthread_t pthread)
|
||||
/* Protect the scheduling queues: */
|
||||
_thread_kern_sig_defer();
|
||||
|
||||
/* Check if we need to kick it back into the run queue: */
|
||||
if ((pthread->cancelflags & PTHREAD_CANCEL_DISABLE) == 0)
|
||||
if (((pthread->cancelflags & PTHREAD_CANCEL_DISABLE) != 0) ||
|
||||
(((pthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) == 0) &&
|
||||
((pthread->cancelflags & PTHREAD_AT_CANCEL_POINT) == 0)))
|
||||
/* Just mark it for cancellation: */
|
||||
pthread->cancelflags |= PTHREAD_CANCELLING;
|
||||
else {
|
||||
/*
|
||||
* Check if we need to kick it back into the
|
||||
* run queue:
|
||||
*/
|
||||
switch (pthread->state) {
|
||||
case PS_RUNNING:
|
||||
/* No need to resume: */
|
||||
@ -33,7 +41,7 @@ pthread_cancel(pthread_t pthread)
|
||||
case PS_FDW_WAIT:
|
||||
case PS_POLL_WAIT:
|
||||
case PS_SELECT_WAIT:
|
||||
/* Remove these threads from the work queue: */
|
||||
/* Remove these threads from the work queue: */
|
||||
if ((pthread->flags & PTHREAD_FLAGS_IN_WORKQ)
|
||||
!= 0)
|
||||
PTHREAD_WORKQ_REMOVE(pthread);
|
||||
@ -75,7 +83,9 @@ pthread_cancel(pthread_t pthread)
|
||||
case PS_STATE_MAX:
|
||||
/* Ignore - only here to silence -Wall: */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Unprotect the scheduling queues: */
|
||||
_thread_kern_sig_undefer();
|
||||
|
||||
@ -96,7 +106,7 @@ pthread_setcancelstate(int state, int *oldstate)
|
||||
case PTHREAD_CANCEL_ENABLE:
|
||||
if (oldstate != NULL)
|
||||
*oldstate = ostate;
|
||||
_thread_run->cancelflags &= PTHREAD_CANCEL_ENABLE;
|
||||
_thread_run->cancelflags &= ~PTHREAD_CANCEL_DISABLE;
|
||||
if ((_thread_run->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) != 0)
|
||||
pthread_testcancel();
|
||||
ret = 0;
|
||||
@ -145,7 +155,6 @@ pthread_setcanceltype(int type, int *oldtype)
|
||||
void
|
||||
pthread_testcancel(void)
|
||||
{
|
||||
|
||||
if (((_thread_run->cancelflags & PTHREAD_CANCEL_DISABLE) == 0) &&
|
||||
((_thread_run->cancelflags & PTHREAD_CANCELLING) != 0)) {
|
||||
/*
|
||||
|
@ -274,6 +274,7 @@ pthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex)
|
||||
}
|
||||
|
||||
if ((_thread_run->cancelflags & PTHREAD_CANCEL_NEEDED) != 0) {
|
||||
_thread_run->cancelflags &= ~PTHREAD_CANCEL_NEEDED;
|
||||
_thread_exit_cleanup();
|
||||
pthread_exit(PTHREAD_CANCELED);
|
||||
}
|
||||
@ -431,6 +432,7 @@ pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
|
||||
}
|
||||
|
||||
if ((_thread_run->cancelflags & PTHREAD_CANCEL_NEEDED) != 0) {
|
||||
_thread_run->cancelflags &= ~PTHREAD_CANCEL_NEEDED;
|
||||
_thread_exit_cleanup();
|
||||
pthread_exit(PTHREAD_CANCELED);
|
||||
}
|
||||
|
@ -98,6 +98,7 @@ pthread_join(pthread_t pthread, void **thread_return)
|
||||
_thread_kern_sig_undefer();
|
||||
|
||||
if ((_thread_run->cancelflags & PTHREAD_CANCEL_NEEDED) != 0) {
|
||||
_thread_run->cancelflags &= ~PTHREAD_CANCEL_NEEDED;
|
||||
_thread_exit_cleanup();
|
||||
pthread_exit(PTHREAD_CANCELED);
|
||||
}
|
||||
|
@ -111,7 +111,7 @@ __asm__("fnsave %0": :"m"(*fdata));
|
||||
if (((_thread_run->cancelflags & PTHREAD_AT_CANCEL_POINT) == 0) &&
|
||||
((_thread_run->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) != 0)) {
|
||||
/*
|
||||
* Cancelations override signals.
|
||||
* Cancellations override signals.
|
||||
*
|
||||
* Stick a cancellation point at the start of
|
||||
* each async-cancellable thread's resumption.
|
||||
|
@ -623,6 +623,7 @@ pthread_mutex_lock(pthread_mutex_t * mutex)
|
||||
_thread_kern_sig_undefer();
|
||||
|
||||
if ((_thread_run->cancelflags & PTHREAD_CANCEL_NEEDED) != 0) {
|
||||
_thread_run->cancelflags &= ~PTHREAD_CANCEL_NEEDED;
|
||||
_thread_exit_cleanup();
|
||||
pthread_exit(PTHREAD_CANCELED);
|
||||
}
|
||||
|
@ -67,8 +67,8 @@ write(int fd, const void *buf, size_t nbytes)
|
||||
/* File is not open for write: */
|
||||
errno = EBADF;
|
||||
_FD_UNLOCK(fd, FD_WRITE);
|
||||
_thread_leave_cancellation_point();
|
||||
return (-1);
|
||||
_thread_leave_cancellation_point();
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Check if file operations are to block */
|
||||
|
Loading…
Reference in New Issue
Block a user