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.cpp michael@0: ** Description: Exercising the thread private data bailywick. michael@0: */ michael@0: michael@0: #include "prlog.h" michael@0: #include "prprf.h" michael@0: #include "rcthread.h" michael@0: michael@0: #include michael@0: michael@0: #include "plgetopt.h" michael@0: michael@0: /* michael@0: ** class MyThread michael@0: */ michael@0: class MyThread: public RCThread michael@0: { michael@0: public: michael@0: MyThread(); michael@0: michael@0: private: michael@0: ~MyThread(); michael@0: void RootFunction(); michael@0: }; /* MyThread */ michael@0: michael@0: /* michael@0: ** class MyPrivateData michael@0: */ michael@0: class MyPrivateData: public RCThreadPrivateData michael@0: { michael@0: public: michael@0: virtual ~MyPrivateData(); michael@0: michael@0: MyPrivateData(); michael@0: MyPrivateData(char*); michael@0: MyPrivateData(const MyPrivateData&); michael@0: michael@0: void Release(); michael@0: michael@0: private: michael@0: char *string; michael@0: }; /* MyPrivateData */ 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: PR_fprintf( michael@0: fout, "@ line %d destructor should %shave been called and was%s\n", michael@0: line, ((should) ? "" : "NOT "), ((did) ? "" : " NOT")); 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: int main(PRIntn argc, char *argv[]) michael@0: { michael@0: PRStatus rv; michael@0: PRUintn keys; michael@0: MyThread *thread; michael@0: const RCThreadPrivateData *pd; michael@0: PLOptStatus os; michael@0: PLOptState *opt = PL_CreateOptState(argc, argv, "d"); michael@0: RCThread *primordial = RCThread::WrapPrimordialThread(); 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: michael@0: fout = PR_STDOUT; michael@0: michael@0: MyPrivateData extension = MyPrivateData("EXTENSION"); michael@0: MyPrivateData 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: michael@0: did = should = PR_FALSE; michael@0: for (keys = 0; keys < 4; ++keys) michael@0: { michael@0: rv = RCThread::NewPrivateIndex(&key[keys]); michael@0: key[keys + 4] = key[keys] + 4; michael@0: MY_ASSERT(PR_SUCCESS == rv); michael@0: } michael@0: PrintProgress(__LINE__); michael@0: michael@0: /* the first four should be bu null, the last four undefined and null */ michael@0: did = should = PR_FALSE; michael@0: for (keys = 0; keys < 8; ++keys) michael@0: { michael@0: pd = RCThread::GetPrivateData(key[keys]); michael@0: MY_ASSERT(NULL == pd); michael@0: } michael@0: PrintProgress(__LINE__); michael@0: michael@0: /* initially set private data for new keys */ michael@0: did = should = PR_FALSE; michael@0: for (keys = 0; keys < 4; ++keys) michael@0: { michael@0: rv = RCThread::SetPrivateData(key[keys], &key_string[keys]); michael@0: MY_ASSERT(PR_SUCCESS == rv); michael@0: } michael@0: PrintProgress(__LINE__); michael@0: michael@0: /* re-assign the private data, albeit the same content */ michael@0: did = PR_FALSE; should = PR_TRUE; michael@0: for (keys = 0; keys < 4; ++keys) michael@0: { michael@0: pd = RCThread::GetPrivateData(key[keys]); michael@0: PR_ASSERT(NULL != pd); michael@0: rv = RCThread::SetPrivateData(key[keys], &key_string[keys]); michael@0: MY_ASSERT(PR_SUCCESS == rv); michael@0: } michael@0: PrintProgress(__LINE__); michael@0: michael@0: /* set private to */ michael@0: did = PR_FALSE; should = PR_TRUE; michael@0: for (keys = 0; keys < 4; ++keys) michael@0: { michael@0: rv = RCThread::SetPrivateData(key[keys]); michael@0: MY_ASSERT(PR_SUCCESS == rv); michael@0: } michael@0: PrintProgress(__LINE__); michael@0: michael@0: /* should all be null now */ michael@0: did = should = PR_FALSE; michael@0: for (keys = 0; keys < 4; ++keys) michael@0: { michael@0: pd = RCThread::GetPrivateData(key[keys]); michael@0: PR_ASSERT(NULL == pd); michael@0: } michael@0: PrintProgress(__LINE__); michael@0: michael@0: /* allocate another batch of keys and assign data to them */ michael@0: did = should = PR_FALSE; michael@0: for (keys = 8; keys < 127; ++keys) michael@0: { michael@0: rv = RCThread::NewPrivateIndex(&key[keys]); michael@0: MY_ASSERT(PR_SUCCESS == rv); michael@0: rv = RCThread::SetPrivateData(key[keys], &extension); michael@0: MY_ASSERT(PR_SUCCESS == rv); michael@0: } michael@0: PrintProgress(__LINE__); michael@0: michael@0: /* set all the extended slots to */ michael@0: did = PR_FALSE; should = PR_TRUE; michael@0: for (keys = 8; keys < 127; ++keys) michael@0: { michael@0: rv = RCThread::SetPrivateData(key[keys]); michael@0: MY_ASSERT(PR_SUCCESS == rv); michael@0: } michael@0: PrintProgress(__LINE__); michael@0: michael@0: /* set all the extended slots to again (noop) */ michael@0: did = should = PR_FALSE; michael@0: for (keys = 8; keys < 127; ++keys) michael@0: { michael@0: rv = RCThread::SetPrivateData(key[keys]); michael@0: MY_ASSERT(PR_SUCCESS == rv); michael@0: } michael@0: michael@0: if (debug) PR_fprintf(fout, "Creating thread\n"); michael@0: thread = new MyThread(); michael@0: if (debug) PR_fprintf(fout, "Starting thread\n"); michael@0: thread->Start(); michael@0: if (debug) PR_fprintf(fout, "Joining thread\n"); michael@0: (void)thread->Join(); michael@0: if (debug) PR_fprintf(fout, "Joined thread\n"); michael@0: michael@0: failed |= (PR_FAILURE == RCPrimordialThread::Cleanup()); michael@0: michael@0: (void)PR_fprintf( michael@0: fout, "%s\n",((PR_TRUE == failed) ? "FAILED" : "PASSED")); michael@0: michael@0: return (failed) ? 1 : 0; michael@0: michael@0: } /* main */ michael@0: michael@0: /* michael@0: ** class MyPrivateData michael@0: */ michael@0: MyPrivateData::~MyPrivateData() michael@0: { michael@0: PR_fprintf( michael@0: fout, "MyPrivateData::~MyPrivateData[%s]\n", michael@0: (NULL != string) ? string : "NULL"); michael@0: } /* MyPrivateData::~MyPrivateData */ michael@0: michael@0: MyPrivateData::MyPrivateData(): RCThreadPrivateData() michael@0: { michael@0: PR_fprintf(fout, "MyPrivateData::MyPrivateData()\n"); michael@0: string = NULL; michael@0: } /* MyPrivateData::MyPrivateData */ michael@0: michael@0: MyPrivateData::MyPrivateData(char* data): RCThreadPrivateData() michael@0: { michael@0: PR_fprintf(fout, "MyPrivateData::MyPrivateData(char* data)\n"); michael@0: string = data; michael@0: } /* MyPrivateData:: MyPrivateData */ michael@0: michael@0: MyPrivateData::MyPrivateData(const MyPrivateData& him): RCThreadPrivateData(him) michael@0: { michael@0: PR_fprintf(fout, "MyPrivateData::MyPrivateData(const MyPrivateData& him)\n"); michael@0: string = him.string; michael@0: } /* MyPrivateData:: MyPrivateData */ michael@0: michael@0: void MyPrivateData::Release() michael@0: { michael@0: if (should) did = PR_TRUE; michael@0: else failed = PR_TRUE; michael@0: } /* MyPrivateData::operator= */ michael@0: michael@0: /* michael@0: ** class MyThread michael@0: */ michael@0: MyThread::~MyThread() { } michael@0: MyThread::MyThread(): RCThread(RCThread::global, RCThread::joinable) { } michael@0: michael@0: michael@0: void MyThread::RootFunction() michael@0: { michael@0: PRStatus rv; michael@0: PRUintn keys; michael@0: const RCThreadPrivateData *pd; michael@0: michael@0: MyPrivateData extension = MyPrivateData("EXTENSION"); michael@0: MyPrivateData 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 = GetPrivateData(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 = SetPrivateData(keys, &key_string[keys]); michael@0: MY_ASSERT(PR_SUCCESS == rv); michael@0: } michael@0: PrintProgress(__LINE__); michael@0: michael@0: #if !defined(DEBUG) michael@0: did = should = PR_FALSE; michael@0: for (keys = 4; keys < 8; ++keys) michael@0: { michael@0: rv = SetPrivateData(keys, &key_string[keys]); michael@0: MY_ASSERT(PR_FAILURE == rv); michael@0: } michael@0: PrintProgress(__LINE__); michael@0: #endif michael@0: michael@0: did = PR_FALSE; should = PR_TRUE; michael@0: for (keys = 0; keys < 4; ++keys) michael@0: { michael@0: rv = SetPrivateData(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 = SetPrivateData(key[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 = 0; keys < 4; ++keys) michael@0: { michael@0: rv = SetPrivateData(key[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 = 8; keys < 127; ++keys) michael@0: { michael@0: rv = SetPrivateData(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 = SetPrivateData(key[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 = 8; keys < 127; ++keys) michael@0: { michael@0: rv = SetPrivateData(key[keys]); michael@0: MY_ASSERT(PR_SUCCESS == rv); michael@0: } michael@0: } /* MyThread::RootFunction */ michael@0: michael@0: /* tpd.c */