diff options
author | srinivas%netscape.com <devnull@localhost> | 1999-10-28 02:48:01 +0000 |
---|---|---|
committer | srinivas%netscape.com <devnull@localhost> | 1999-10-28 02:48:01 +0000 |
commit | 1dccc6c9d12cb57c19e9d79c45e47a33e96cfcd1 (patch) | |
tree | 8a3c3e0768e0cbc7666cb6bb64339755c202283c | |
parent | 30a8bc8fa16a0ab17ad92f8d2bbe2057a8f3c730 (diff) | |
download | nspr-hg-1dccc6c9d12cb57c19e9d79c45e47a33e96cfcd1.tar.gz |
Add PR_Block/Unblock_Interrupt functions. Bugzilla 17055
-rw-r--r-- | pr/include/private/primpl.h | 15 | ||||
-rw-r--r-- | pr/include/prthread.h | 10 | ||||
-rw-r--r-- | pr/src/pthreads/ptio.c | 4 | ||||
-rw-r--r-- | pr/src/pthreads/ptsynch.c | 4 | ||||
-rw-r--r-- | pr/src/pthreads/ptthread.c | 12 | ||||
-rw-r--r-- | pr/src/threads/prcthr.c | 24 | ||||
-rw-r--r-- | pr/tests/intrupt.c | 115 |
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); |