summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsrinivas%netscape.com <devnull@localhost>1999-10-28 02:48:01 +0000
committersrinivas%netscape.com <devnull@localhost>1999-10-28 02:48:01 +0000
commit1dccc6c9d12cb57c19e9d79c45e47a33e96cfcd1 (patch)
tree8a3c3e0768e0cbc7666cb6bb64339755c202283c
parent30a8bc8fa16a0ab17ad92f8d2bbe2057a8f3c730 (diff)
downloadnspr-hg-1dccc6c9d12cb57c19e9d79c45e47a33e96cfcd1.tar.gz
Add PR_Block/Unblock_Interrupt functions. Bugzilla 17055
-rw-r--r--pr/include/private/primpl.h15
-rw-r--r--pr/include/prthread.h10
-rw-r--r--pr/src/pthreads/ptio.c4
-rw-r--r--pr/src/pthreads/ptsynch.c4
-rw-r--r--pr/src/pthreads/ptthread.c12
-rw-r--r--pr/src/threads/prcthr.c24
-rw-r--r--pr/tests/intrupt.c115
7 files changed, 157 insertions, 27 deletions
diff --git a/pr/include/private/primpl.h b/pr/include/private/primpl.h
index 88d26566..28f294cb 100644
--- a/pr/include/private/primpl.h
+++ b/pr/include/private/primpl.h
@@ -166,6 +166,12 @@ struct _PT_Notified
#define PT_THREAD_FOREIGN 0x80 /* thread is not one of ours */
#define PT_THREAD_BOUND 0x100 /* a bound-global thread */
+#define _PT_THREAD_INTERRUPTED(thr) \
+ (!(thr->interrupt_blocked) && (thr->state & PT_THREAD_ABORTED))
+#define _PT_THREAD_BLOCK_INTERRUPT(thr) \
+ (thr->interrupt_blocked = 1)
+#define _PT_THREAD_UNBLOCK_INTERRUPT(thr) \
+ (thr->interrupt_blocked = 0)
/*
** Possible values for thread's suspend field
** Note that the first two can be the same as they are really mutually exclusive,
@@ -575,6 +581,7 @@ typedef struct _PRPerThreadExit {
#define _PR_IDLE_THREAD 0x200 /* this is an idle thread */
#define _PR_GCABLE_THREAD 0x400 /* this is a collectable thread */
#define _PR_BOUND_THREAD 0x800 /* a bound thread */
+#define _PR_INTERRUPT_BLOCKED 0x1000 /* interrupts blocked */
/* PRThread.state */
#define _PR_UNBORN 0
@@ -617,7 +624,12 @@ typedef struct _PRPerThreadExit {
#define _PR_ADJUST_STACKSIZE(stackSize)
#endif
-#define _PR_PENDING_INTERRUPT(_thread) ((_thread)->flags & _PR_INTERRUPT)
+#define _PR_PENDING_INTERRUPT(thr) \
+ (!((thr)->flags & _PR_INTERRUPT_BLOCKED) && ((thr)->flags & _PR_INTERRUPT))
+#define _PR_THREAD_BLOCK_INTERRUPT(thr) \
+ (thr->flags |= _PR_INTERRUPT_BLOCKED)
+#define _PR_THREAD_UNBLOCK_INTERRUPT(thr) \
+ (thr->flags &= ~_PR_INTERRUPT_BLOCKED)
#define _PR_THREAD_PTR(_qp) \
((PRThread*) ((char*) (_qp) - offsetof(PRThread,links)))
@@ -1424,6 +1436,7 @@ struct PRThread {
pthread_mutex_t suspendResumeMutex;
pthread_cond_t suspendResumeCV;
#endif
+ PRUint32 interrupt_blocked; /* interrupt blocked */
#elif defined(_PR_BTHREADS)
PRUint32 flags;
_MDThread md;
diff --git a/pr/include/prthread.h b/pr/include/prthread.h
index f0833892..8072ef14 100644
--- a/pr/include/prthread.h
+++ b/pr/include/prthread.h
@@ -227,6 +227,16 @@ PR_EXTERN(PRStatus) PR_Interrupt(PRThread *thread);
PR_EXTERN(void) PR_ClearInterrupt(void);
/*
+** Block the interrupt for the calling thread.
+*/
+PR_EXTERN(void) PR_BlockInterrupt(void);
+
+/*
+** Unblock the interrupt for the calling thread.
+*/
+PR_EXTERN(void) PR_UnblockInterrupt(void);
+
+/*
** Make the current thread sleep until "ticks" time amount of time
** has expired. If "ticks" is PR_INTERVAL_NO_WAIT then the call is
** equivalent to calling PR_Yield. Calling PR_Sleep with an argument
diff --git a/pr/src/pthreads/ptio.c b/pr/src/pthreads/ptio.c
index 68a8778c..a91b397e 100644
--- a/pr/src/pthreads/ptio.c
+++ b/pr/src/pthreads/ptio.c
@@ -642,7 +642,7 @@ static void pt_ContinuationThreadInternal(pt_Continuation *my_op)
** (perhaps) resetting it are safe 'cause it's the only modifiable
** bit in that word.
*/
- if (tqp->thread->state & PT_THREAD_ABORTED)
+ if (_PT_THREAD_INTERRUPTED(tqp->thread))
{
my_op->status = pt_continuation_abort;
tqp->thread->state &= ~PT_THREAD_ABORTED;
@@ -1383,7 +1383,7 @@ PR_IMPLEMENT(PRFileDesc*) PR_GetSpecialFD(PRSpecialFD osfd)
static PRBool pt_TestAbort(void)
{
PRThread *me = PR_CurrentThread();
- if(me->state & PT_THREAD_ABORTED)
+ if(_PT_THREAD_INTERRUPTED(me))
{
PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
me->state &= ~PT_THREAD_ABORTED;
diff --git a/pr/src/pthreads/ptsynch.c b/pr/src/pthreads/ptsynch.c
index 7beaf450..119e9e47 100644
--- a/pr/src/pthreads/ptsynch.c
+++ b/pr/src/pthreads/ptsynch.c
@@ -333,7 +333,7 @@ PR_IMPLEMENT(PRStatus) PR_WaitCondVar(PRCondVar *cvar, PRIntervalTime timeout)
/* and it better be by us */
PR_ASSERT(pthread_equal(cvar->lock->owner, pthread_self()));
- if (thred->state & PT_THREAD_ABORTED) goto aborted;
+ if (_PT_THREAD_INTERRUPTED(thred)) goto aborted;
/*
* The thread waiting is used for PR_Interrupt
@@ -367,7 +367,7 @@ PR_IMPLEMENT(PRStatus) PR_WaitCondVar(PRCondVar *cvar, PRIntervalTime timeout)
PR_ASSERT(0 == cvar->lock->notified.length);
thred->waiting = NULL; /* and now we're not */
- if (thred->state & PT_THREAD_ABORTED) goto aborted;
+ if (_PT_THREAD_INTERRUPTED(thred)) goto aborted;
return (rv == 0) ? PR_SUCCESS : PR_FAILURE;
aborted:
diff --git a/pr/src/pthreads/ptthread.c b/pr/src/pthreads/ptthread.c
index 77636a6e..2df58a06 100644
--- a/pr/src/pthreads/ptthread.c
+++ b/pr/src/pthreads/ptthread.c
@@ -719,6 +719,18 @@ PR_IMPLEMENT(void) PR_ClearInterrupt()
me->state &= ~PT_THREAD_ABORTED;
} /* PR_ClearInterrupt */
+PR_IMPLEMENT(void) PR_BlockInterrupt()
+{
+ PRThread *me = PR_CurrentThread();
+ _PT_THREAD_BLOCK_INTERRUPT(me);
+} /* PR_BlockInterrupt */
+
+PR_IMPLEMENT(void) PR_UnblockInterrupt()
+{
+ PRThread *me = PR_CurrentThread();
+ _PT_THREAD_UNBLOCK_INTERRUPT(me);
+} /* PR_UnblockInterrupt */
+
PR_IMPLEMENT(PRStatus) PR_Yield()
{
static PRBool warning = PR_TRUE;
diff --git a/pr/src/threads/prcthr.c b/pr/src/threads/prcthr.c
index 9dfb49d1..65ad9663 100644
--- a/pr/src/threads/prcthr.c
+++ b/pr/src/threads/prcthr.c
@@ -258,6 +258,30 @@ PR_IMPLEMENT(void) PR_ClearInterrupt()
if ( !_PR_IS_NATIVE_THREAD(me)) _PR_INTSON(is);
}
+PR_IMPLEMENT(void) PR_BlockInterrupt()
+{
+ PRIntn is;
+ PRThread *me = _PR_MD_CURRENT_THREAD();
+
+ if ( !_PR_IS_NATIVE_THREAD(me)) _PR_INTSOFF(is);
+ _PR_THREAD_LOCK(me);
+ _PR_THREAD_BLOCK_INTERRUPT(me);
+ _PR_THREAD_UNLOCK(me);
+ if ( !_PR_IS_NATIVE_THREAD(me)) _PR_INTSON(is);
+} /* PR_BlockInterrupt */
+
+PR_IMPLEMENT(void) PR_UnblockInterrupt()
+{
+ PRIntn is;
+ PRThread *me = _PR_MD_CURRENT_THREAD();
+
+ if ( !_PR_IS_NATIVE_THREAD(me)) _PR_INTSOFF(is);
+ _PR_THREAD_LOCK(me);
+ _PR_THREAD_UNBLOCK_INTERRUPT(me);
+ _PR_THREAD_UNLOCK(me);
+ if ( !_PR_IS_NATIVE_THREAD(me)) _PR_INTSON(is);
+} /* PR_UnblockInterrupt */
+
/*
** Return the thread stack pointer of the given thread.
*/
diff --git a/pr/tests/intrupt.c b/pr/tests/intrupt.c
index b4ad81e8..9e0845eb 100644
--- a/pr/tests/intrupt.c
+++ b/pr/tests/intrupt.c
@@ -42,6 +42,8 @@
extern void SetupMacPrintfLog(char *logFile);
#endif
+#define DEFAULT_TCP_PORT 12500
+
static PRLock *ml = NULL;
static PRCondVar *cv = NULL;
@@ -149,13 +151,90 @@ static void PR_CALLBACK AbortJoin(void *arg)
{
} /* AbortJoin */
+static void setup_listen_socket(PRFileDesc **listner, PRNetAddr *netaddr)
+{
+ PRStatus rv;
+ PRInt16 port = DEFAULT_TCP_PORT;
+
+ *listner = PR_NewTCPSocket();
+ PR_ASSERT(*listner != NULL);
+ memset(netaddr, 0, sizeof(*netaddr));
+ (*netaddr).inet.ip = PR_htonl(PR_INADDR_ANY);
+ (*netaddr).inet.family = PR_AF_INET;
+ do
+ {
+ (*netaddr).inet.port = PR_htons(port);
+ rv = PR_Bind(*listner, netaddr);
+ port += 1;
+ PR_ASSERT(port < (DEFAULT_TCP_PORT + 10));
+ } while (PR_FAILURE == rv);
+
+ rv = PR_Listen(*listner, 5);
+
+ if (PR_GetSockName(*listner, netaddr) < 0) {
+ if (debug_mode) printf("intrupt: ERROR - PR_GetSockName failed\n");
+ passed = PR_FALSE;
+ return;
+ }
+
+}
+
+static void PR_CALLBACK IntrBlock(void *arg)
+{
+ PRStatus rv;
+ PRNetAddr netaddr;
+ PRFileDesc *listner;
+
+ /* some other thread (main) is doing the interrupt */
+ /* block the interrupt */
+ PR_BlockInterrupt();
+ PR_Lock(ml);
+ rv = PR_WaitCondVar(cv, PR_SecondsToInterval(4));
+ PR_Unlock(ml);
+ if (debug_mode)
+ {
+ printf("Expected success on wait CV and ");
+ if (PR_FAILURE == rv)
+ {
+ printf(
+ "%s\n", (PR_PENDING_INTERRUPT_ERROR == PR_GetError()) ?
+ "got interrupted" : "got a random failure");
+ } else
+ printf("got it\n");
+ }
+ passed = ((PR_TRUE == passed) && (PR_SUCCESS == rv)) ? PR_TRUE : PR_FALSE;
+
+ setup_listen_socket(&listner, &netaddr);
+ PR_UnblockInterrupt();
+ if (PR_Accept(listner, &netaddr, PR_INTERVAL_NO_TIMEOUT) == NULL)
+ {
+ PRInt32 error = PR_GetError();
+ if (debug_mode) printf("Expected interrupt on PR_Accept() and ");
+ if (PR_PENDING_INTERRUPT_ERROR == error)
+ {
+ if (debug_mode) printf("got it\n");
+ }
+ else
+ {
+ if (debug_mode) printf("failed\n");
+ passed = PR_FALSE;
+ }
+ }
+ else
+ {
+ if (debug_mode) printf("Failed to interrupt PR_Accept()\n");
+ passed = PR_FALSE;
+ }
+
+ (void)PR_Close(listner); listner = NULL;
+} /* TestIntrBlock */
+
void PR_CALLBACK Intrupt(void *arg)
{
PRStatus rv;
PRNetAddr netaddr;
PRFileDesc *listner;
- PRInt16 port = 12848;
- PRThread *abortCV, *abortIO, *abortJoin;
+ PRThread *abortCV, *abortIO, *abortJoin, *intrBlock;
ml = PR_NewLock();
cv = PR_NewCondVar(ml);
@@ -192,26 +271,7 @@ void PR_CALLBACK Intrupt(void *arg)
/* Part III */
if (debug_mode) printf("Part III\n");
- listner = PR_NewTCPSocket();
- memset(&netaddr, 0, sizeof(netaddr));
- netaddr.inet.ip = PR_htonl(PR_INADDR_ANY);
- netaddr.inet.family = PR_AF_INET;
- do
- {
- netaddr.inet.port = PR_htons(port);
- rv = PR_Bind(listner, &netaddr);
- port += 1;
- PR_ASSERT(port < (12848 + 10));
- } while (PR_FAILURE == rv);
-
- rv = PR_Listen(listner, 5);
-
- if (PR_GetSockName(listner, &netaddr) < 0) {
- if (debug_mode) printf("intrupt: ERROR - PR_GetSockName failed\n");
- passed = PR_FALSE;
- return;
- }
-
+ setup_listen_socket(&listner, &netaddr);
abortIO = PR_CreateThread(
PR_USER_THREAD, AbortIO, PR_CurrentThread(), PR_PRIORITY_NORMAL,
thread_scope, PR_JOINABLE_THREAD, 0);
@@ -240,6 +300,17 @@ void PR_CALLBACK Intrupt(void *arg)
rv = PR_JoinThread(abortIO);
PR_ASSERT(PR_SUCCESS == rv);
+ /* Part VI */
+ if (debug_mode) printf("Part VI\n");
+ intrBlock = PR_CreateThread(
+ PR_USER_THREAD, IntrBlock, 0, PR_PRIORITY_NORMAL,
+ thread_scope, PR_JOINABLE_THREAD, 0);
+
+ PR_Sleep(PR_SecondsToInterval(2));
+ rv = PR_Interrupt(intrBlock);
+ PR_ASSERT(PR_SUCCESS == rv);
+ rv = PR_JoinThread(intrBlock);
+ PR_ASSERT(PR_SUCCESS == rv);
PR_DestroyCondVar(cv);
PR_DestroyLock(ml);