michael@0: /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /* michael@0: * File: intrupt.c michael@0: * Purpose: testing thread interrupts michael@0: */ michael@0: michael@0: #include "plgetopt.h" michael@0: #include "prcvar.h" michael@0: #include "prerror.h" michael@0: #include "prinit.h" michael@0: #include "prinrval.h" michael@0: #include "prio.h" michael@0: #include "prlock.h" michael@0: #include "prlog.h" michael@0: #include "prthread.h" michael@0: #include "prtypes.h" michael@0: #include "prnetdb.h" michael@0: michael@0: #include michael@0: #include michael@0: michael@0: #define DEFAULT_TCP_PORT 12500 michael@0: michael@0: static PRLock *ml = NULL; michael@0: static PRCondVar *cv = NULL; michael@0: michael@0: static PRBool passed = PR_TRUE; michael@0: static PRBool debug_mode = PR_FALSE; michael@0: static PRThreadScope thread_scope = PR_LOCAL_THREAD; michael@0: michael@0: static void PR_CALLBACK AbortCV(void *arg) michael@0: { michael@0: PRStatus rv; michael@0: PRThread *me = PR_GetCurrentThread(); michael@0: michael@0: /* some other thread (main) is doing the interrupt */ michael@0: PR_Lock(ml); michael@0: rv = PR_WaitCondVar(cv, PR_INTERVAL_NO_TIMEOUT); michael@0: if (debug_mode) printf( "Expected interrupt on wait CV and "); michael@0: if (PR_FAILURE == rv) michael@0: { michael@0: if (PR_PENDING_INTERRUPT_ERROR == PR_GetError()) michael@0: { michael@0: if (debug_mode) printf("got it\n"); michael@0: } michael@0: else michael@0: { michael@0: if (debug_mode) printf("got random error\n"); michael@0: passed = PR_FALSE; michael@0: } michael@0: } michael@0: else michael@0: { michael@0: if (debug_mode) printf("got a successful completion\n"); michael@0: passed = PR_FALSE; michael@0: } michael@0: michael@0: rv = PR_WaitCondVar(cv, 10); michael@0: if (debug_mode) michael@0: { michael@0: printf( michael@0: "Expected success on wait CV and %s\n", michael@0: (PR_SUCCESS == rv) ? "got it" : "failed"); michael@0: } michael@0: passed = ((PR_TRUE == passed) && (PR_SUCCESS == rv)) ? PR_TRUE : PR_FALSE; michael@0: michael@0: /* interrupt myself, then clear */ michael@0: PR_Interrupt(me); michael@0: PR_ClearInterrupt(); michael@0: rv = PR_WaitCondVar(cv, 10); michael@0: if (debug_mode) michael@0: { michael@0: printf("Expected success on wait CV and "); michael@0: if (PR_FAILURE == rv) michael@0: { michael@0: printf( michael@0: "%s\n", (PR_PENDING_INTERRUPT_ERROR == PR_GetError()) ? michael@0: "got interrupted" : "a random failure"); michael@0: } michael@0: printf("got it\n"); michael@0: } michael@0: passed = ((PR_TRUE == passed) && (PR_SUCCESS == rv)) ? PR_TRUE : PR_FALSE; michael@0: michael@0: /* set, then wait - interrupt - then wait again */ michael@0: PR_Interrupt(me); michael@0: rv = PR_WaitCondVar(cv, 10); michael@0: if (debug_mode) printf( "Expected interrupt on wait CV and "); michael@0: if (PR_FAILURE == rv) michael@0: { michael@0: if (PR_PENDING_INTERRUPT_ERROR == PR_GetError()) michael@0: { michael@0: if (debug_mode) printf("got it\n"); michael@0: } michael@0: else michael@0: { michael@0: if (debug_mode) printf("failed\n"); michael@0: passed = PR_FALSE; michael@0: } michael@0: } michael@0: else michael@0: { michael@0: if (debug_mode) printf("got a successful completion\n"); michael@0: passed = PR_FALSE; michael@0: } michael@0: michael@0: rv = PR_WaitCondVar(cv, 10); michael@0: if (debug_mode) michael@0: { michael@0: printf( michael@0: "Expected success on wait CV and %s\n", michael@0: (PR_SUCCESS == rv) ? "got it" : "failed"); michael@0: } michael@0: passed = ((PR_TRUE == passed) && (PR_SUCCESS == rv)) ? PR_TRUE : PR_FALSE; michael@0: michael@0: PR_Unlock(ml); michael@0: michael@0: } /* AbortCV */ michael@0: michael@0: static void PR_CALLBACK AbortIO(void *arg) michael@0: { michael@0: PRStatus rv; michael@0: PR_Sleep(PR_SecondsToInterval(2)); michael@0: rv = PR_Interrupt((PRThread*)arg); michael@0: PR_ASSERT(PR_SUCCESS == rv); michael@0: } /* AbortIO */ michael@0: michael@0: static void PR_CALLBACK AbortJoin(void *arg) michael@0: { michael@0: } /* AbortJoin */ michael@0: michael@0: static void setup_listen_socket(PRFileDesc **listner, PRNetAddr *netaddr) michael@0: { michael@0: PRStatus rv; michael@0: PRInt16 port = DEFAULT_TCP_PORT; michael@0: michael@0: *listner = PR_NewTCPSocket(); michael@0: PR_ASSERT(*listner != NULL); michael@0: memset(netaddr, 0, sizeof(*netaddr)); michael@0: (*netaddr).inet.ip = PR_htonl(PR_INADDR_ANY); michael@0: (*netaddr).inet.family = PR_AF_INET; michael@0: do michael@0: { michael@0: (*netaddr).inet.port = PR_htons(port); michael@0: rv = PR_Bind(*listner, netaddr); michael@0: port += 1; michael@0: PR_ASSERT(port < (DEFAULT_TCP_PORT + 10)); michael@0: } while (PR_FAILURE == rv); michael@0: michael@0: rv = PR_Listen(*listner, 5); michael@0: michael@0: if (PR_GetSockName(*listner, netaddr) < 0) { michael@0: if (debug_mode) printf("intrupt: ERROR - PR_GetSockName failed\n"); michael@0: passed = PR_FALSE; michael@0: return; michael@0: } michael@0: michael@0: } michael@0: michael@0: static void PR_CALLBACK IntrBlock(void *arg) michael@0: { michael@0: PRStatus rv; michael@0: PRNetAddr netaddr; michael@0: PRFileDesc *listner; michael@0: michael@0: /* some other thread (main) is doing the interrupt */ michael@0: /* block the interrupt */ michael@0: PR_BlockInterrupt(); michael@0: PR_Lock(ml); michael@0: rv = PR_WaitCondVar(cv, PR_SecondsToInterval(4)); michael@0: PR_Unlock(ml); michael@0: if (debug_mode) michael@0: { michael@0: printf("Expected success on wait CV and "); michael@0: if (PR_FAILURE == rv) michael@0: { michael@0: printf( michael@0: "%s\n", (PR_PENDING_INTERRUPT_ERROR == PR_GetError()) ? michael@0: "got interrupted" : "got a random failure"); michael@0: } else michael@0: printf("got it\n"); michael@0: } michael@0: passed = ((PR_TRUE == passed) && (PR_SUCCESS == rv)) ? PR_TRUE : PR_FALSE; michael@0: michael@0: setup_listen_socket(&listner, &netaddr); michael@0: PR_UnblockInterrupt(); michael@0: if (PR_Accept(listner, &netaddr, PR_INTERVAL_NO_TIMEOUT) == NULL) michael@0: { michael@0: PRInt32 error = PR_GetError(); michael@0: if (debug_mode) printf("Expected interrupt on PR_Accept() and "); michael@0: if (PR_PENDING_INTERRUPT_ERROR == error) michael@0: { michael@0: if (debug_mode) printf("got it\n"); michael@0: } michael@0: else michael@0: { michael@0: if (debug_mode) printf("failed\n"); michael@0: passed = PR_FALSE; michael@0: } michael@0: } michael@0: else michael@0: { michael@0: if (debug_mode) printf("Failed to interrupt PR_Accept()\n"); michael@0: passed = PR_FALSE; michael@0: } michael@0: michael@0: (void)PR_Close(listner); listner = NULL; michael@0: } /* TestIntrBlock */ michael@0: michael@0: void PR_CALLBACK Intrupt(void *arg) michael@0: { michael@0: PRStatus rv; michael@0: PRNetAddr netaddr; michael@0: PRFileDesc *listner; michael@0: PRThread *abortCV, *abortIO, *abortJoin, *intrBlock; michael@0: michael@0: ml = PR_NewLock(); michael@0: cv = PR_NewCondVar(ml); michael@0: michael@0: /* Part I */ michael@0: if (debug_mode) printf("Part I\n"); michael@0: abortCV = PR_CreateThread( michael@0: PR_USER_THREAD, AbortCV, 0, PR_PRIORITY_NORMAL, michael@0: thread_scope, PR_JOINABLE_THREAD, 0); michael@0: michael@0: PR_Sleep(PR_SecondsToInterval(2)); michael@0: rv = PR_Interrupt(abortCV); michael@0: PR_ASSERT(PR_SUCCESS == rv); michael@0: rv = PR_JoinThread(abortCV); michael@0: PR_ASSERT(PR_SUCCESS == rv); michael@0: michael@0: /* Part II */ michael@0: if (debug_mode) printf("Part II\n"); michael@0: abortJoin = PR_CreateThread( michael@0: PR_USER_THREAD, AbortJoin, 0, PR_PRIORITY_NORMAL, michael@0: thread_scope, PR_JOINABLE_THREAD, 0); michael@0: PR_Sleep(PR_SecondsToInterval(2)); michael@0: if (debug_mode) printf("Expecting to interrupt an exited thread "); michael@0: rv = PR_Interrupt(abortJoin); michael@0: PR_ASSERT(PR_SUCCESS == rv); michael@0: rv = PR_JoinThread(abortJoin); michael@0: PR_ASSERT(PR_SUCCESS == rv); michael@0: if (debug_mode) printf("and succeeded\n"); michael@0: michael@0: /* Part III */ michael@0: if (debug_mode) printf("Part III\n"); michael@0: setup_listen_socket(&listner, &netaddr); michael@0: abortIO = PR_CreateThread( michael@0: PR_USER_THREAD, AbortIO, PR_GetCurrentThread(), PR_PRIORITY_NORMAL, michael@0: thread_scope, PR_JOINABLE_THREAD, 0); michael@0: michael@0: if (PR_Accept(listner, &netaddr, PR_INTERVAL_NO_TIMEOUT) == NULL) michael@0: { michael@0: PRInt32 error = PR_GetError(); michael@0: if (debug_mode) printf("Expected interrupt on PR_Accept() and "); michael@0: if (PR_PENDING_INTERRUPT_ERROR == error) michael@0: { michael@0: if (debug_mode) printf("got it\n"); michael@0: } michael@0: else michael@0: { michael@0: if (debug_mode) printf("failed\n"); michael@0: passed = PR_FALSE; michael@0: } michael@0: } michael@0: else michael@0: { michael@0: if (debug_mode) printf("Failed to interrupt PR_Accept()\n"); michael@0: passed = PR_FALSE; michael@0: } michael@0: michael@0: (void)PR_Close(listner); listner = NULL; michael@0: michael@0: rv = PR_JoinThread(abortIO); michael@0: PR_ASSERT(PR_SUCCESS == rv); michael@0: /* Part VI */ michael@0: if (debug_mode) printf("Part VI\n"); michael@0: intrBlock = PR_CreateThread( michael@0: PR_USER_THREAD, IntrBlock, 0, PR_PRIORITY_NORMAL, michael@0: thread_scope, PR_JOINABLE_THREAD, 0); michael@0: michael@0: PR_Sleep(PR_SecondsToInterval(2)); michael@0: rv = PR_Interrupt(intrBlock); michael@0: PR_ASSERT(PR_SUCCESS == rv); michael@0: rv = PR_JoinThread(intrBlock); michael@0: PR_ASSERT(PR_SUCCESS == rv); michael@0: michael@0: PR_DestroyCondVar(cv); michael@0: PR_DestroyLock(ml); michael@0: } /* Intrupt */ michael@0: michael@0: int main(int argc, char **argv) michael@0: { michael@0: PRThread *intrupt; michael@0: PLOptStatus os; michael@0: PLOptState *opt = PL_CreateOptState(argc, argv, "dG"); michael@0: while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) michael@0: { michael@0: if (PL_OPT_BAD == os) continue; michael@0: switch (opt->option) michael@0: { michael@0: case 'd': /* debug mode */ michael@0: debug_mode = PR_TRUE; michael@0: break; michael@0: case 'G': /* use global threads */ michael@0: thread_scope = PR_GLOBAL_THREAD; michael@0: break; michael@0: } michael@0: } michael@0: PL_DestroyOptState(opt); michael@0: PR_STDIO_INIT(); michael@0: intrupt = PR_CreateThread( michael@0: PR_USER_THREAD, Intrupt, NULL, PR_PRIORITY_NORMAL, michael@0: thread_scope, PR_JOINABLE_THREAD, 0); michael@0: if (intrupt == NULL) { michael@0: fprintf(stderr, "cannot create thread\n"); michael@0: passed = PR_FALSE; michael@0: } else { michael@0: PRStatus rv; michael@0: rv = PR_JoinThread(intrupt); michael@0: PR_ASSERT(rv == PR_SUCCESS); michael@0: } michael@0: printf("%s\n", ((passed) ? "PASSED" : "FAILED")); michael@0: return ((passed) ? 0 : 1); michael@0: } /* main */ michael@0: michael@0: /* intrupt.c */