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: tpd.c michael@0: ** Description: Exercising the thread private data bailywick. michael@0: */ michael@0: michael@0: #include "prmem.h" michael@0: #include "prinit.h" michael@0: #include "prlog.h" michael@0: #include "prprf.h" michael@0: #include "prthread.h" michael@0: #include "prtypes.h" michael@0: michael@0: #include "private/pprio.h" michael@0: michael@0: #include "plgetopt.h" michael@0: michael@0: static PRUintn key[128]; michael@0: static PRIntn debug = 0; michael@0: static PRBool failed = PR_FALSE; michael@0: static PRBool should = PR_TRUE; michael@0: static PRBool did = PR_TRUE; michael@0: static PRFileDesc *fout = NULL; michael@0: michael@0: static void PrintProgress(PRIntn line) michael@0: { michael@0: failed = failed || (should && !did); michael@0: failed = failed || (!should && did); michael@0: if (debug > 0) michael@0: { michael@0: #if defined(WIN16) michael@0: printf( michael@0: "@ line %d destructor should%s have been called and was%s\n", michael@0: line, ((should) ? "" : " NOT"), ((did) ? "" : " NOT")); michael@0: #else michael@0: PR_fprintf( michael@0: fout, "@ line %d destructor should%s have been called and was%s\n", michael@0: line, ((should) ? "" : " NOT"), ((did) ? "" : " NOT")); michael@0: #endif michael@0: } michael@0: } /* PrintProgress */ michael@0: michael@0: static void MyAssert(const char *expr, const char *file, PRIntn line) michael@0: { michael@0: if (debug > 0) michael@0: (void)PR_fprintf(fout, "'%s' in file: %s: %d\n", expr, file, line); michael@0: } /* MyAssert */ michael@0: michael@0: #define MY_ASSERT(_expr) \ michael@0: ((_expr)?((void)0):MyAssert(# _expr,__FILE__,__LINE__)) michael@0: michael@0: michael@0: static void PR_CALLBACK Destructor(void *data) michael@0: { michael@0: MY_ASSERT(NULL != data); michael@0: if (should) did = PR_TRUE; michael@0: else failed = PR_TRUE; michael@0: /* michael@0: * We don't actually free the storage since it's actually allocated michael@0: * on the stack. Normally, this would not be the case and this is michael@0: * the opportunity to free whatever. michael@0: PR_Free(data); michael@0: */ michael@0: } /* Destructor */ michael@0: michael@0: static void PR_CALLBACK Thread(void *null) michael@0: { michael@0: void *pd; michael@0: PRStatus rv; michael@0: PRUintn keys; michael@0: char *key_string[] = { michael@0: "Key #0", "Key #1", "Key #2", "Key #3", michael@0: "Bogus #5", "Bogus #6", "Bogus #7", "Bogus #8"}; michael@0: michael@0: did = should = PR_FALSE; michael@0: for (keys = 0; keys < 8; ++keys) michael@0: { michael@0: pd = PR_GetThreadPrivate(key[keys]); michael@0: MY_ASSERT(NULL == pd); michael@0: } michael@0: PrintProgress(__LINE__); michael@0: michael@0: did = should = PR_FALSE; michael@0: for (keys = 0; keys < 4; ++keys) michael@0: { michael@0: rv = PR_SetThreadPrivate(key[keys], key_string[keys]); michael@0: MY_ASSERT(PR_SUCCESS == rv); michael@0: } michael@0: PrintProgress(__LINE__); michael@0: michael@0: did = should = PR_FALSE; michael@0: for (keys = 4; keys < 8; ++keys) michael@0: { michael@0: rv = PR_SetThreadPrivate(key[keys], key_string[keys]); michael@0: MY_ASSERT(PR_FAILURE == rv); michael@0: } michael@0: PrintProgress(__LINE__); michael@0: michael@0: did = PR_FALSE; should = PR_TRUE; michael@0: for (keys = 0; keys < 4; ++keys) michael@0: { michael@0: rv = PR_SetThreadPrivate(key[keys], key_string[keys]); michael@0: MY_ASSERT(PR_SUCCESS == rv); michael@0: } michael@0: PrintProgress(__LINE__); michael@0: michael@0: did = PR_FALSE; should = PR_TRUE; michael@0: for (keys = 0; keys < 4; ++keys) michael@0: { michael@0: rv = PR_SetThreadPrivate(key[keys], NULL); michael@0: MY_ASSERT(PR_SUCCESS == rv); michael@0: } michael@0: PrintProgress(__LINE__); michael@0: michael@0: did = should = PR_FALSE; michael@0: for (keys = 0; keys < 4; ++keys) michael@0: { michael@0: rv = PR_SetThreadPrivate(key[keys], NULL); michael@0: MY_ASSERT(PR_SUCCESS == rv); michael@0: } michael@0: PrintProgress(__LINE__); michael@0: michael@0: did = should = PR_FALSE; michael@0: for (keys = 8; keys < 127; ++keys) michael@0: { michael@0: rv = PR_SetThreadPrivate(key[keys], "EXTENSION"); michael@0: MY_ASSERT(PR_SUCCESS == rv); michael@0: } michael@0: PrintProgress(__LINE__); michael@0: michael@0: did = PR_FALSE; should = PR_TRUE; michael@0: for (keys = 8; keys < 127; ++keys) michael@0: { michael@0: rv = PR_SetThreadPrivate(key[keys], NULL); michael@0: MY_ASSERT(PR_SUCCESS == rv); michael@0: } michael@0: PrintProgress(__LINE__); michael@0: michael@0: did = should = PR_FALSE; michael@0: for (keys = 8; keys < 127; ++keys) michael@0: { michael@0: rv = PR_SetThreadPrivate(key[keys], NULL); michael@0: MY_ASSERT(PR_SUCCESS == rv); michael@0: } michael@0: michael@0: /* put in keys and leave them there for thread exit */ michael@0: did = should = PR_FALSE; michael@0: for (keys = 0; keys < 4; ++keys) michael@0: { michael@0: rv = PR_SetThreadPrivate(key[keys], key_string[keys]); michael@0: MY_ASSERT(PR_SUCCESS == rv); michael@0: } michael@0: PrintProgress(__LINE__); michael@0: did = PR_FALSE; should = PR_TRUE; michael@0: michael@0: } /* Thread */ michael@0: michael@0: static PRIntn PR_CALLBACK Tpd(PRIntn argc, char **argv) michael@0: { michael@0: void *pd; michael@0: PRStatus rv; michael@0: PRUintn keys; michael@0: PRThread *thread; michael@0: char *key_string[] = { michael@0: "Key #0", "Key #1", "Key #2", "Key #3", michael@0: "Bogus #5", "Bogus #6", "Bogus #7", "Bogus #8"}; michael@0: michael@0: fout = PR_STDOUT; michael@0: michael@0: did = should = PR_FALSE; michael@0: for (keys = 0; keys < 4; ++keys) michael@0: { michael@0: rv = PR_NewThreadPrivateIndex(&key[keys], Destructor); michael@0: MY_ASSERT(PR_SUCCESS == rv); michael@0: } michael@0: PrintProgress(__LINE__); michael@0: michael@0: did = should = PR_FALSE; michael@0: for (keys = 0; keys < 8; ++keys) michael@0: { michael@0: pd = PR_GetThreadPrivate(key[keys]); michael@0: MY_ASSERT(NULL == pd); michael@0: } michael@0: PrintProgress(__LINE__); michael@0: michael@0: did = should = PR_FALSE; michael@0: for (keys = 0; keys < 4; ++keys) michael@0: { michael@0: rv = PR_SetThreadPrivate(key[keys], key_string[keys]); michael@0: MY_ASSERT(PR_SUCCESS == rv); michael@0: } michael@0: PrintProgress(__LINE__); michael@0: michael@0: for (keys = 4; keys < 8; ++keys) michael@0: key[keys] = 4096; /* set to invalid value */ michael@0: did = should = PR_FALSE; michael@0: for (keys = 4; keys < 8; ++keys) michael@0: { michael@0: rv = PR_SetThreadPrivate(key[keys], key_string[keys]); michael@0: MY_ASSERT(PR_FAILURE == rv); michael@0: } michael@0: PrintProgress(__LINE__); michael@0: michael@0: did = PR_FALSE; should = PR_TRUE; michael@0: for (keys = 0; keys < 4; ++keys) michael@0: { michael@0: rv = PR_SetThreadPrivate(key[keys], key_string[keys]); michael@0: MY_ASSERT(PR_SUCCESS == rv); michael@0: } michael@0: PrintProgress(__LINE__); michael@0: michael@0: did = PR_FALSE; should = PR_TRUE; michael@0: for (keys = 0; keys < 4; ++keys) michael@0: { michael@0: rv = PR_SetThreadPrivate(key[keys], NULL); michael@0: MY_ASSERT(PR_SUCCESS == rv); michael@0: } michael@0: PrintProgress(__LINE__); michael@0: michael@0: did = should = PR_FALSE; michael@0: for (keys = 0; keys < 4; ++keys) michael@0: { michael@0: rv = PR_SetThreadPrivate(key[keys], NULL); michael@0: MY_ASSERT(PR_SUCCESS == rv); michael@0: } michael@0: PrintProgress(__LINE__); michael@0: michael@0: did = should = PR_FALSE; michael@0: for (keys = 8; keys < 127; ++keys) michael@0: { michael@0: rv = PR_NewThreadPrivateIndex(&key[keys], Destructor); michael@0: MY_ASSERT(PR_SUCCESS == rv); michael@0: rv = PR_SetThreadPrivate(key[keys], "EXTENSION"); michael@0: MY_ASSERT(PR_SUCCESS == rv); michael@0: } michael@0: PrintProgress(__LINE__); michael@0: michael@0: did = PR_FALSE; should = PR_TRUE; michael@0: for (keys = 8; keys < 127; ++keys) michael@0: { michael@0: rv = PR_SetThreadPrivate(key[keys], NULL); michael@0: MY_ASSERT(PR_SUCCESS == rv); michael@0: } michael@0: PrintProgress(__LINE__); michael@0: michael@0: did = should = PR_FALSE; michael@0: for (keys = 8; keys < 127; ++keys) michael@0: { michael@0: rv = PR_SetThreadPrivate(key[keys], NULL); michael@0: MY_ASSERT(PR_SUCCESS == rv); michael@0: } michael@0: michael@0: thread = PR_CreateThread( michael@0: PR_USER_THREAD, Thread, NULL, PR_PRIORITY_NORMAL, michael@0: PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0); michael@0: michael@0: (void)PR_JoinThread(thread); michael@0: michael@0: PrintProgress(__LINE__); michael@0: michael@0: #if defined(WIN16) michael@0: printf( michael@0: "%s\n",((PR_TRUE == failed) ? "FAILED" : "PASSED")); michael@0: #else michael@0: (void)PR_fprintf( michael@0: fout, "%s\n",((PR_TRUE == failed) ? "FAILED" : "PASSED")); michael@0: #endif michael@0: michael@0: return 0; michael@0: michael@0: } /* Tpd */ michael@0: michael@0: int main(int argc, char **argv) michael@0: { michael@0: PLOptStatus os; michael@0: PLOptState *opt = PL_CreateOptState(argc, argv, "dl:r:"); 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 = PR_TRUE; michael@0: break; michael@0: default: michael@0: break; michael@0: } michael@0: } michael@0: PL_DestroyOptState(opt); michael@0: PR_STDIO_INIT(); michael@0: return PR_Initialize(Tpd, argc, argv, 0); michael@0: } /* main */ michael@0: michael@0: /* tpd.c */