ioconthr.c (3384B)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 /* 7 * This is a test for the io continuation thread machinery 8 * in pthreads. 9 */ 10 11 #include "nspr.h" 12 #include <stdio.h> 13 14 int num_threads = 10; /* must be an even number */ 15 PRThreadScope thread_scope = PR_GLOBAL_THREAD; 16 17 void ThreadFunc(void* arg) { 18 PRFileDesc* fd = (PRFileDesc*)arg; 19 char buf[1024]; 20 PRInt32 nbytes; 21 PRErrorCode err; 22 23 nbytes = PR_Recv(fd, buf, sizeof(buf), 0, PR_SecondsToInterval(20)); 24 if (nbytes == -1) { 25 err = PR_GetError(); 26 if (err != PR_PENDING_INTERRUPT_ERROR) { 27 fprintf(stderr, "PR_Recv failed: (%d, %d)\n", err, PR_GetOSError()); 28 PR_ProcessExit(1); 29 } 30 /* 31 * After getting an I/O interrupt, this thread must 32 * close the fd before it exits due to a limitation 33 * of our NT implementation. 34 */ 35 if (PR_Close(fd) == PR_FAILURE) { 36 fprintf(stderr, "PR_Close failed\n"); 37 PR_ProcessExit(1); 38 } 39 } else { 40 fprintf(stderr, "PR_Recv received %d bytes!?\n", nbytes); 41 PR_ProcessExit(1); 42 } 43 } 44 45 int main(int argc, char** argv) { 46 PRFileDesc** fds; 47 PRThread** threads; 48 PRIntervalTime start, elapsed; 49 int index; 50 51 fds = (PRFileDesc**)PR_MALLOC(2 * num_threads * sizeof(PRFileDesc*)); 52 PR_ASSERT(fds != NULL); 53 threads = (PRThread**)PR_MALLOC(num_threads * sizeof(PRThread*)); 54 PR_ASSERT(threads != NULL); 55 56 for (index = 0; index < num_threads; index++) { 57 if (PR_NewTCPSocketPair(&fds[2 * index]) == PR_FAILURE) { 58 fprintf(stderr, "PR_NewTCPSocket failed\n"); 59 PR_ProcessExit(1); 60 } 61 threads[index] = PR_CreateThread(PR_USER_THREAD, ThreadFunc, fds[2 * index], 62 PR_PRIORITY_NORMAL, thread_scope, 63 PR_JOINABLE_THREAD, 0); 64 if (NULL == threads[index]) { 65 fprintf(stderr, "PR_CreateThread failed\n"); 66 PR_ProcessExit(1); 67 } 68 } 69 70 /* Let the threads block in PR_Recv */ 71 PR_Sleep(PR_SecondsToInterval(2)); 72 73 printf("Interrupting the threads\n"); 74 fflush(stdout); 75 start = PR_IntervalNow(); 76 for (index = 0; index < num_threads; index++) { 77 if (PR_Interrupt(threads[index]) == PR_FAILURE) { 78 fprintf(stderr, "PR_Interrupt failed\n"); 79 PR_ProcessExit(1); 80 } 81 } 82 for (index = 0; index < num_threads; index++) { 83 if (PR_JoinThread(threads[index]) == PR_FAILURE) { 84 fprintf(stderr, "PR_JoinThread failed\n"); 85 PR_ProcessExit(1); 86 } 87 } 88 elapsed = (PRIntervalTime)(PR_IntervalNow() - start); 89 printf("Threads terminated in %d milliseconds\n", 90 PR_IntervalToMilliseconds(elapsed)); 91 fflush(stdout); 92 93 /* We are being very generous and allow 10 seconds. */ 94 if (elapsed >= PR_SecondsToInterval(10)) { 95 fprintf(stderr, "Interrupting threads took longer than 10 seconds!!\n"); 96 PR_ProcessExit(1); 97 } 98 99 for (index = 0; index < num_threads; index++) { 100 /* fds[2 * index] was passed to and closed by threads[index]. */ 101 if (PR_Close(fds[2 * index + 1]) == PR_FAILURE) { 102 fprintf(stderr, "PR_Close failed\n"); 103 PR_ProcessExit(1); 104 } 105 } 106 PR_DELETE(threads); 107 PR_DELETE(fds); 108 printf("PASS\n"); 109 PR_Cleanup(); 110 return 0; 111 }