Add PR_Block/Unblock_Interrupt functions. Bugzilla 17055
authorsrinivas%netscape.com
Thu, 28 Oct 1999 02:48:01 +0000
changeset 913 3ce3dc6a4a494b376aac72f015dd7dcc386de8e2
parent 912 d7f88731f56f90b2574f6f83989478ec004c567f
child 914 22b495dd280bc35d215760cf102658d5a00ebc1f
push idunknown
push userunknown
push dateunknown
bugs17055
Add PR_Block/Unblock_Interrupt functions. Bugzilla 17055
pr/include/private/primpl.h
pr/include/prthread.h
pr/src/pthreads/ptio.c
pr/src/pthreads/ptsynch.c
pr/src/pthreads/ptthread.c
pr/src/threads/prcthr.c
pr/tests/intrupt.c
--- a/pr/include/private/primpl.h
+++ b/pr/include/private/primpl.h
@@ -161,16 +161,22 @@ struct _PT_Notified
 #define PT_THREAD_SYSTEM    0x04    /* system (not user) thread */
 #define PT_THREAD_PRIMORD   0x08    /* this is the primordial thread */
 #define PT_THREAD_ABORTED   0x10    /* thread has been interrupted */
 #define PT_THREAD_GCABLE    0x20    /* thread is garbage collectible */
 #define PT_THREAD_SUSPENDED 0x40    /* thread has been suspended */
 #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,
 ** i.e. both cannot be happening at the same time. We have two symbolic names
 ** just as a mnemonic.
 **/
 #define PT_THREAD_RESUMED   0x80    /* thread has been resumed */
 #define PT_THREAD_SETGCABLE 0x100   /* set the GCAble flag */
@@ -570,16 +576,17 @@ typedef struct _PRPerThreadExit {
 #define _PR_PRIMORDIAL      0x08        /* the thread that called PR_Init */
 #define _PR_ON_SLEEPQ       0x10        /* thread is on the sleepQ */
 #define _PR_ON_PAUSEQ       0x20        /* thread is on the pauseQ */
 #define _PR_SUSPENDING      0x40        /* thread wants to suspend */
 #define _PR_GLOBAL_SCOPE    0x80        /* thread is global scope */
 #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
 #define _PR_RUNNABLE     1
 #define _PR_RUNNING      2
 #define _PR_LOCK_WAIT    3
 #define _PR_COND_WAIT    4
 #define _PR_JOIN_WAIT    5
@@ -612,17 +619,22 @@ typedef struct _PRPerThreadExit {
                 stackSize = _MD_MINIMUM_STACK_SIZE; \
     stackSize = (stackSize + (1 << _pr_pageShift) - 1) >> _pr_pageShift; \
     stackSize <<= _pr_pageShift; \
         PR_END_MACRO
 #else
 #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)))
 
 #define _PR_ACTIVE_THREAD_PTR(_qp) \
     ((PRThread*) ((char*) (_qp) - offsetof(PRThread,active)))
 
 #define _PR_THREAD_CONDQ_PTR(_qp) \
@@ -1419,16 +1431,17 @@ struct PRThread {
 	PRIntn io_tq_index;             /* the io-queue index for this thread */
     void *sp;                       /* recorded sp for garbage collection */
     PRThread *next, *prev;          /* simple linked list of all threads */
     PRUint32 suspend;               /* used to store suspend and resume flags */
 #ifdef PT_NO_SIGTIMEDWAIT
     pthread_mutex_t suspendResumeMutex;
     pthread_cond_t suspendResumeCV;
 #endif
+    PRUint32 interrupt_blocked;     /* interrupt blocked */
 #elif defined(_PR_BTHREADS)
     PRUint32 flags;
     _MDThread md;
     PRBool io_pending;
     PRInt32 io_fd;
     PRBool io_suspended;
 #else /* not pthreads or Be threads */
     _MDLock threadLock;             /* Lock to protect thread state variables.
--- a/pr/include/prthread.h
+++ b/pr/include/prthread.h
@@ -222,16 +222,26 @@ PR_EXTERN(PRStatus) PR_Interrupt(PRThrea
 
 /*
 ** Clear the interrupt request for the calling thread. If no such request
 ** is pending, this operation is a noop.
 */
 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
 ** equivalent to PR_INTERVAL_NO_TIMEOUT is an error and will result
 ** in a PR_FAILURE error return.
 */
 PR_EXTERN(PRStatus) PR_Sleep(PRIntervalTime ticks);
 
--- a/pr/src/pthreads/ptio.c
+++ b/pr/src/pthreads/ptio.c
@@ -637,17 +637,17 @@ static void pt_ContinuationThreadInterna
         ** the thread state will have the PT_THREAD_ABORTED bit set. This
         ** overrides good completions as well as timeouts.
         **
         ** BTW, it does no good to hold the lock here. This lock doesn't
         ** protect the thread structure in any way. Testing the bit and
         ** (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;
         }
 
 
         /*
          * Build up a polling list.
@@ -1378,17 +1378,17 @@ PR_IMPLEMENT(PRFileDesc*) PR_GetSpecialF
 
 /*****************************************************************************/
 /***************************** I/O private methods ***************************/
 /*****************************************************************************/
 
 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;
         return PR_TRUE;
     }
     return PR_FALSE;
 }  /* pt_TestAbort */
 
--- a/pr/src/pthreads/ptsynch.c
+++ b/pr/src/pthreads/ptsynch.c
@@ -328,17 +328,17 @@ PR_IMPLEMENT(PRStatus) PR_WaitCondVar(PR
     PRThread *thred = PR_CurrentThread();
 
     PR_ASSERT(cvar != NULL);
     /* We'd better be locked */
     PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(cvar->lock->mutex));
     /* 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
      */
     thred->waiting = cvar;  /* this is where we're waiting */
 
     /*
      * If we have pending notifies, post them now.
@@ -362,17 +362,17 @@ PR_IMPLEMENT(PRStatus) PR_WaitCondVar(PR
         rv = pt_TimedWait(&cvar->cv, &cvar->lock->mutex, timeout);
 
     /* We just got the lock back - this better be empty */
     PR_ASSERT(_PT_PTHREAD_THR_HANDLE_IS_ZERO(cvar->lock->owner));
     _PT_PTHREAD_COPY_THR_HANDLE(pthread_self(), cvar->lock->owner);
 
     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:
     PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
     thred->state &= ~PT_THREAD_ABORTED;
     return PR_FAILURE;
 }  /* PR_WaitCondVar */
 
--- a/pr/src/pthreads/ptthread.c
+++ b/pr/src/pthreads/ptthread.c
@@ -714,16 +714,28 @@ PR_IMPLEMENT(PRStatus) PR_Interrupt(PRTh
 }  /* PR_Interrupt */
 
 PR_IMPLEMENT(void) PR_ClearInterrupt()
 {
     PRThread *me = PR_CurrentThread();
     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;
     if (warning) warning = _PR_Obsolete(
         "PR_Yield()", "PR_Sleep(PR_INTERVAL_NO_WAIT)");
     return PR_Sleep(PR_INTERVAL_NO_WAIT);
 }
 
--- a/pr/src/threads/prcthr.c
+++ b/pr/src/threads/prcthr.c
@@ -253,16 +253,40 @@ PR_IMPLEMENT(void) PR_ClearInterrupt()
 
         if ( !_PR_IS_NATIVE_THREAD(me)) _PR_INTSOFF(is);
     _PR_THREAD_LOCK(me);
          me->flags &= ~_PR_INTERRUPT;
     _PR_THREAD_UNLOCK(me);
         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.
 */
 PR_IMPLEMENT(void *) PR_GetSP(PRThread *thread)
 {
         return (void *)_PR_MD_GET_SP(thread);
 }
 
--- a/pr/tests/intrupt.c
+++ b/pr/tests/intrupt.c
@@ -37,16 +37,18 @@
 #include <string.h>
 
 #ifdef XP_MAC
 #include "prlog.h"
 #define printf PR_LogPrint
 extern void SetupMacPrintfLog(char *logFile);
 #endif
 
+#define DEFAULT_TCP_PORT 12500
+
 static PRLock *ml = NULL;
 static PRCondVar *cv = NULL;
 
 static PRBool passed = PR_TRUE;
 static PRBool debug_mode = PR_FALSE;
 static PRThreadScope thread_scope = PR_LOCAL_THREAD;
 
 static void PR_CALLBACK AbortCV(void *arg)
@@ -144,23 +146,100 @@ static void PR_CALLBACK AbortIO(void *ar
     rv = PR_Interrupt((PRThread*)arg);
     PR_ASSERT(PR_SUCCESS == rv);
 }  /* AbortIO */
 
 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);
 
 #ifdef XP_MAC
 	SetupMacPrintfLog("intrupt.log");
 	debug_mode = PR_TRUE;
 #endif
@@ -187,36 +266,17 @@ void PR_CALLBACK Intrupt(void *arg)
     rv = PR_Interrupt(abortJoin);
     PR_ASSERT(PR_SUCCESS == rv);
     rv = PR_JoinThread(abortJoin);
     PR_ASSERT(PR_SUCCESS == rv);
     if (debug_mode) printf("and succeeded\n");
 
     /* 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);
 
     if (PR_Accept(listner, &netaddr, PR_INTERVAL_NO_TIMEOUT) == NULL)
     {
         PRInt32 error = PR_GetError();
         if (debug_mode) printf("Expected interrupt on PR_Accept() and ");
@@ -235,16 +295,27 @@ void PR_CALLBACK Intrupt(void *arg)
         if (debug_mode) printf("Failed to interrupt PR_Accept()\n");
         passed = PR_FALSE;
     }
 
     (void)PR_Close(listner); listner = NULL;
 
     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);    
 }  /* Intrupt */
 
 PRIntn main(PRIntn argc, char **argv)
 {
     PRThread *intrupt;