sl@0: // Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // Name : pthreadmisc.cpp sl@0: // Part of : PThread library sl@0: // Thread Miscellaneous functions are implemented in this file. sl@0: // Version: sl@0: // sl@0: sl@0: sl@0: sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include "threadglobals.h" sl@0: sl@0: #define THREAD_NAME_WIDTH 8 sl@0: #define THREAD_COUNT_ZERO 0 sl@0: #define MAX_THREAD_CREATE_FAILURE_COUNT 20 sl@0: #define MAX_THREAD_NAME_LEN 255 sl@0: sl@0: #ifdef __EPOC32__ sl@0: class XPthreadTLSCleanup sl@0: { sl@0: public: sl@0: ~XPthreadTLSCleanup() sl@0: { sl@0: Dll::FreeTls(); sl@0: } sl@0: }; sl@0: sl@0: // Create a global here. It's desctructor invoked on libpthread unload will reset libpthread's TLS sl@0: XPthreadTLSCleanup gPthreadTLSCleanup; sl@0: #endif sl@0: sl@0: int _copy_already_defined_keys(_pthread_node_t* prev_node, _pthread_node_t* new_node); sl@0: sl@0: // Internal Function sl@0: // return : NULL - means no memory sl@0: void* _pthread_getTls() sl@0: { sl@0: _pthread_node_t *selfNodePtr; sl@0: _global_data_t *glbPtr = glbHeadNode; sl@0: sl@0: THR_PRINTF("[pthread] Begin _pthread_getTls\n"); sl@0: // Get the TLS contents. sl@0: TAny *tlsAddr = Dll::Tls(); sl@0: sl@0: // If TLS is already initialised then just return the node address sl@0: if (NULL != tlsAddr) sl@0: { sl@0: THR_PRINTF("[pthread] End _pthread_getTls\n"); sl@0: return ((void*) tlsAddr); sl@0: } sl@0: sl@0: // Create node for main thread and also global data structure. sl@0: selfNodePtr = new _pthread_node_t; sl@0: THR_NULL_ASSERT(selfNodePtr,NULL, sl@0: "[pthread] FATAL: Memory alloc failed for threadnode"); sl@0: sl@0: //Initialize the node sl@0: selfNodePtr->next = NULL; sl@0: if (selfNodePtr->lockNode.CreateLocal() != KErrNone) sl@0: { sl@0: delete selfNodePtr; sl@0: THR_PRINTF("[pthread] FATAL :Mutex create failed"); sl@0: return ((void*)NULL); sl@0: } sl@0: selfNodePtr->glbDataPtr = glbPtr; sl@0: selfNodePtr->detachState = PTHREAD_CREATE_JOINABLE; sl@0: selfNodePtr->threadState = _THREAD_RUNNING; sl@0: selfNodePtr->returnValue = NULL; sl@0: selfNodePtr->hasAnyThreadJoined = EFalse; sl@0: selfNodePtr->threadId = (TUint)selfNodePtr->rtHandle.Id(); sl@0: selfNodePtr->priority = DEFAULT_THREAD_PRIORITY; sl@0: selfNodePtr->mainFlag = _MAIN_THREAD; sl@0: selfNodePtr->tlsHead = NULL; sl@0: selfNodePtr->cleanStackPtr = NULL; //added to solve memory leak problem sl@0: sl@0: // Insert the node in to the global linked list and increment thread count. sl@0: glbPtr->lockThreadTable.Wait(); sl@0: //copy the already defined keys sl@0: if( _copy_already_defined_keys(glbPtr->start, selfNodePtr)) sl@0: { sl@0: delete selfNodePtr; sl@0: THR_PRINTF("[pthread] FATAL :failed copying defined keys"); sl@0: sl@0: glbPtr->lockThreadTable.Signal(); sl@0: return NULL; sl@0: } sl@0: selfNodePtr->next = glbPtr->start; sl@0: sl@0: glbPtr->start = selfNodePtr; sl@0: glbPtr->threadCount++; sl@0: sl@0: glbPtr->lockThreadTable.Signal(); sl@0: sl@0: //Set node address to TLS sl@0: Dll::SetTls((TAny*)selfNodePtr); sl@0: THR_PRINTF("[pthread] End _pthread_getTls\n"); sl@0: sl@0: // libc needs to know whether application is multithreaded or not... sl@0: __isthreaded = 1; sl@0: sl@0: return ((void*) selfNodePtr); sl@0: } sl@0: sl@0: int _copy_already_defined_keys(_pthread_node_t* prev_node, _pthread_node_t* new_node) sl@0: { sl@0: if(!prev_node || !new_node) sl@0: return 0; sl@0: sl@0: _pkey_node_t *tlsPtr; sl@0: _pkey_node_t *newTlsPtr, *prevTlsPtr=NULL; sl@0: for (tlsPtr = prev_node->tlsHead; tlsPtr != NULL; tlsPtr = tlsPtr->next) sl@0: { sl@0: newTlsPtr = new _pkey_node_t; sl@0: if (NULL == newTlsPtr) sl@0: { sl@0: return -1; sl@0: } sl@0: if(new_node->tlsHead == NULL) sl@0: new_node->tlsHead = newTlsPtr; sl@0: else{ sl@0: prevTlsPtr->next = newTlsPtr; sl@0: } sl@0: newTlsPtr->tls = NULL; sl@0: newTlsPtr->keyNumber = tlsPtr->keyNumber; sl@0: prevTlsPtr = newTlsPtr; sl@0: } sl@0: sl@0: return 0; sl@0: } sl@0: sl@0: // This function has to be called holding global lock and node lock. sl@0: // Before returning all lock will be opened sl@0: void _pthread_deleteNode(_pthread_node_t *selfNodePtr, sl@0: _global_data_t *glbPtr, sl@0: void ** retValPtr) sl@0: { sl@0: _pthread_node_t *tempPtr; sl@0: _pthread_node_t *prevPtr = NULL; sl@0: sl@0: THR_PRINTF("[pthread] Begin _pthread_deleteNode\n"); sl@0: // Traverse through the list, till node which has to be deleted is found sl@0: for (tempPtr = glbPtr->start; sl@0: ((tempPtr != selfNodePtr) && (tempPtr != NULL)); sl@0: tempPtr = tempPtr->next) sl@0: { sl@0: prevPtr = tempPtr; // Store the previous node ptr sl@0: } sl@0: sl@0: if (NULL == tempPtr) //Not found; this should never happen sl@0: { sl@0: THR_PRINTF("[pthread] FATAL: Unable to delete the node"); sl@0: selfNodePtr->lockNode.Signal(); sl@0: glbPtr->lockThreadTable.Signal(); //release global lock sl@0: return; sl@0: } sl@0: if (tempPtr == glbPtr->start) // Deleting first node sl@0: { sl@0: glbPtr->start = tempPtr->next; //Update the link list sl@0: } sl@0: else sl@0: { sl@0: prevPtr->lockNode.Wait(); //Acquire the previous node lock sl@0: prevPtr->next = tempPtr->next; //Update the link list sl@0: prevPtr->lockNode.Signal(); //Release the previous node lock sl@0: } sl@0: sl@0: if (NULL != retValPtr) // Get the return value sl@0: { sl@0: *retValPtr = selfNodePtr->returnValue; sl@0: } sl@0: sl@0: selfNodePtr->lockNode.Signal(); // Unlock & Free the node sl@0: selfNodePtr->lockNode.Close(); sl@0: selfNodePtr->rtHandle.Close(); sl@0: sl@0: delete selfNodePtr; sl@0: sl@0: //--(glbPtr->threadCount); // Update the thread count sl@0: //if (THREAD_COUNT_ZERO == glbPtr->threadCount) sl@0: //{ sl@0: // RProcess rp; sl@0: // rp.Kill(0); // Terminate the process sl@0: //} sl@0: sl@0: glbPtr->lockThreadTable.Signal(); // release thread table lock sl@0: THR_PRINTF("[pthread] End of _pthread_deleteNode\n"); sl@0: } sl@0: sl@0: sl@0: void* _getKeyValueSetNull(int keyNumber,_pkey_node_t *tlsPtr) sl@0: { sl@0: void* retVal; sl@0: for ( ; tlsPtr != NULL; tlsPtr = tlsPtr->next) sl@0: { sl@0: if (tlsPtr->keyNumber == keyNumber) sl@0: { sl@0: retVal = tlsPtr->tls; sl@0: tlsPtr->tls = NULL; sl@0: return (retVal); sl@0: } sl@0: } sl@0: //This should never happen; hence dest function will not be called sl@0: return NULL; sl@0: } sl@0: // Before calling this function, global lock and node lock must be open sl@0: void _pthread_destroyKeys(_global_data_t *glbPtr, sl@0: _pthread_node_t *selfNodePtr) sl@0: { sl@0: int loopvar; sl@0: int allempty; sl@0: int keyNumber; sl@0: destructor_routine dest; sl@0: void *arg; sl@0: sl@0: glbPtr->lockThreadTable.Wait(); // Acquire the thread table lock sl@0: selfNodePtr->lockNode.Wait(); // Lock the TCB sl@0: sl@0: for (loopvar = 0, allempty = 1; sl@0: allempty && (loopvar < PTHREAD_DESTRUCTOR_ITERATIONS);loopvar++) sl@0: { sl@0: allempty = 0; // Assuming all keys are not used. sl@0: sl@0: for (keyNumber = 0; keyNumber < PTHREAD_KEYS_MAX; keyNumber++) sl@0: { sl@0: int temp; sl@0: temp = keyNumber / 32; sl@0: sl@0: int bitPos; sl@0: bitPos = keyNumber % 32; sl@0: sl@0: if (((glbPtr->statusflag[temp]) & (0x1<pthread_key_list[keyNumber].destr != NULL)) sl@0: { sl@0: if ((arg = _getKeyValueSetNull(keyNumber,selfNodePtr->tlsHead)) != NULL) sl@0: { sl@0: dest = glbPtr->pthread_key_list[keyNumber].destr; sl@0: sl@0: selfNodePtr->lockNode.Signal(); // Unlock TCB node sl@0: glbPtr->lockThreadTable.Signal(); // release thread table lock sl@0: sl@0: dest(arg); //Call destructor sl@0: sl@0: glbPtr->lockThreadTable.Wait();// Acquire the thread table lock sl@0: selfNodePtr->lockNode.Wait(); // Lock the TCB sl@0: sl@0: allempty = 1; // Atleast one key was used sl@0: } sl@0: } sl@0: } sl@0: } sl@0: sl@0: selfNodePtr->lockNode.Signal(); // Unlock TCB node sl@0: glbPtr->lockThreadTable.Signal(); // release thread table lock sl@0: } sl@0: sl@0: // End of File