os/ossrv/genericopenlibs/openenvcore/libpthread/src/pthreadmisc.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
sl@0
     1
// Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
sl@0
     2
// All rights reserved.
sl@0
     3
// This component and the accompanying materials are made available
sl@0
     4
// under the terms of "Eclipse Public License v1.0"
sl@0
     5
// which accompanies this distribution, and is available
sl@0
     6
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0
     7
//
sl@0
     8
// Initial Contributors:
sl@0
     9
// Nokia Corporation - initial contribution.
sl@0
    10
//
sl@0
    11
// Contributors:
sl@0
    12
//
sl@0
    13
// Description:
sl@0
    14
// Name     : pthreadmisc.cpp
sl@0
    15
// Part of  : PThread library
sl@0
    16
// Thread Miscellaneous functions are implemented in this file.
sl@0
    17
// Version:
sl@0
    18
//
sl@0
    19
sl@0
    20
sl@0
    21
sl@0
    22
#include <pthread.h>
sl@0
    23
#include <stdio.h>
sl@0
    24
#include <errno.h>
sl@0
    25
#include <e32base.h>
sl@0
    26
#include "threadglobals.h"
sl@0
    27
sl@0
    28
#define THREAD_NAME_WIDTH 8
sl@0
    29
#define THREAD_COUNT_ZERO 0
sl@0
    30
#define MAX_THREAD_CREATE_FAILURE_COUNT 20
sl@0
    31
#define MAX_THREAD_NAME_LEN 255
sl@0
    32
sl@0
    33
#ifdef __EPOC32__
sl@0
    34
class XPthreadTLSCleanup
sl@0
    35
	{
sl@0
    36
public:
sl@0
    37
	~XPthreadTLSCleanup()
sl@0
    38
		{
sl@0
    39
		Dll::FreeTls();
sl@0
    40
		}
sl@0
    41
	};
sl@0
    42
sl@0
    43
// Create a global here. It's desctructor invoked on libpthread unload will reset libpthread's TLS
sl@0
    44
XPthreadTLSCleanup gPthreadTLSCleanup;
sl@0
    45
#endif
sl@0
    46
sl@0
    47
int _copy_already_defined_keys(_pthread_node_t* prev_node, _pthread_node_t* new_node);
sl@0
    48
sl@0
    49
// Internal Function
sl@0
    50
// return : NULL - means no memory
sl@0
    51
void* _pthread_getTls()
sl@0
    52
{
sl@0
    53
    _pthread_node_t *selfNodePtr;
sl@0
    54
    _global_data_t *glbPtr = glbHeadNode;
sl@0
    55
    
sl@0
    56
    THR_PRINTF("[pthread] Begin _pthread_getTls\n");
sl@0
    57
    // Get the TLS contents. 
sl@0
    58
    TAny *tlsAddr = Dll::Tls();
sl@0
    59
    
sl@0
    60
    // If TLS is already initialised then just return the node address
sl@0
    61
    if (NULL != tlsAddr)
sl@0
    62
    {
sl@0
    63
        THR_PRINTF("[pthread] End _pthread_getTls\n");
sl@0
    64
        return ((void*) tlsAddr);
sl@0
    65
    }
sl@0
    66
    
sl@0
    67
    // Create node for main thread and also global data structure.
sl@0
    68
    selfNodePtr = new _pthread_node_t;
sl@0
    69
    THR_NULL_ASSERT(selfNodePtr,NULL,
sl@0
    70
          "[pthread] FATAL: Memory alloc failed for threadnode");
sl@0
    71
    
sl@0
    72
    //Initialize the node
sl@0
    73
    selfNodePtr->next = NULL;
sl@0
    74
    if (selfNodePtr->lockNode.CreateLocal() != KErrNone)
sl@0
    75
    {
sl@0
    76
        delete selfNodePtr;
sl@0
    77
        THR_PRINTF("[pthread] FATAL :Mutex create failed");
sl@0
    78
        return ((void*)NULL);        
sl@0
    79
    }
sl@0
    80
    selfNodePtr->glbDataPtr = glbPtr;
sl@0
    81
    selfNodePtr->detachState = PTHREAD_CREATE_JOINABLE;
sl@0
    82
    selfNodePtr->threadState = _THREAD_RUNNING;
sl@0
    83
    selfNodePtr->returnValue = NULL;
sl@0
    84
    selfNodePtr->hasAnyThreadJoined = EFalse;
sl@0
    85
    selfNodePtr->threadId = (TUint)selfNodePtr->rtHandle.Id();
sl@0
    86
    selfNodePtr->priority = DEFAULT_THREAD_PRIORITY; 
sl@0
    87
    selfNodePtr->mainFlag = _MAIN_THREAD;
sl@0
    88
    selfNodePtr->tlsHead = NULL;
sl@0
    89
    selfNodePtr->cleanStackPtr = NULL; //added to solve memory leak problem
sl@0
    90
sl@0
    91
//    Insert the node in to the global linked list and increment thread count.
sl@0
    92
    glbPtr->lockThreadTable.Wait();
sl@0
    93
	//copy the already defined keys
sl@0
    94
	if( _copy_already_defined_keys(glbPtr->start, selfNodePtr))
sl@0
    95
	{
sl@0
    96
		delete selfNodePtr;
sl@0
    97
        THR_PRINTF("[pthread] FATAL :failed copying defined keys");
sl@0
    98
		
sl@0
    99
		glbPtr->lockThreadTable.Signal();
sl@0
   100
        return NULL;
sl@0
   101
	}
sl@0
   102
    selfNodePtr->next = glbPtr->start;
sl@0
   103
    
sl@0
   104
	glbPtr->start = selfNodePtr;
sl@0
   105
    glbPtr->threadCount++;
sl@0
   106
	
sl@0
   107
    glbPtr->lockThreadTable.Signal();
sl@0
   108
        
sl@0
   109
    //Set node address to TLS
sl@0
   110
    Dll::SetTls((TAny*)selfNodePtr);
sl@0
   111
    THR_PRINTF("[pthread] End _pthread_getTls\n");
sl@0
   112
    
sl@0
   113
    // libc needs to know whether application is multithreaded or not...
sl@0
   114
    __isthreaded = 1;
sl@0
   115
    
sl@0
   116
    return ((void*) selfNodePtr);
sl@0
   117
}
sl@0
   118
sl@0
   119
int _copy_already_defined_keys(_pthread_node_t* prev_node, _pthread_node_t* new_node)
sl@0
   120
{
sl@0
   121
	if(!prev_node || !new_node)
sl@0
   122
		return 0;
sl@0
   123
sl@0
   124
	_pkey_node_t *tlsPtr;
sl@0
   125
	_pkey_node_t *newTlsPtr, *prevTlsPtr=NULL;
sl@0
   126
    for (tlsPtr = prev_node->tlsHead; tlsPtr != NULL; tlsPtr = tlsPtr->next)
sl@0
   127
	{
sl@0
   128
		newTlsPtr = new _pkey_node_t;
sl@0
   129
		if (NULL == newTlsPtr)
sl@0
   130
        {
sl@0
   131
            return -1;
sl@0
   132
        }
sl@0
   133
		if(new_node->tlsHead == NULL)
sl@0
   134
			new_node->tlsHead = newTlsPtr;
sl@0
   135
		else{
sl@0
   136
			prevTlsPtr->next = newTlsPtr;
sl@0
   137
		}
sl@0
   138
        newTlsPtr->tls = NULL;
sl@0
   139
        newTlsPtr->keyNumber = tlsPtr->keyNumber;
sl@0
   140
		prevTlsPtr = newTlsPtr;
sl@0
   141
	}
sl@0
   142
	 
sl@0
   143
	return 0;
sl@0
   144
}
sl@0
   145
sl@0
   146
// This function has to be called holding global lock and node lock.
sl@0
   147
// Before returning all lock will be opened
sl@0
   148
void _pthread_deleteNode(_pthread_node_t *selfNodePtr, 
sl@0
   149
                           _global_data_t *glbPtr,
sl@0
   150
                           void ** retValPtr)
sl@0
   151
{
sl@0
   152
    _pthread_node_t *tempPtr;
sl@0
   153
    _pthread_node_t *prevPtr = NULL;
sl@0
   154
    
sl@0
   155
    THR_PRINTF("[pthread] Begin _pthread_deleteNode\n");
sl@0
   156
    // Traverse through the list, till node which has to be deleted is found
sl@0
   157
    for (tempPtr = glbPtr->start; 
sl@0
   158
         ((tempPtr != selfNodePtr) && (tempPtr != NULL)); 
sl@0
   159
         tempPtr = tempPtr->next)
sl@0
   160
    {
sl@0
   161
        prevPtr = tempPtr;             // Store the previous node ptr
sl@0
   162
    }
sl@0
   163
    
sl@0
   164
    if (NULL == tempPtr)              //Not found; this should never happen
sl@0
   165
    {
sl@0
   166
        THR_PRINTF("[pthread] FATAL: Unable to delete the node");
sl@0
   167
        selfNodePtr->lockNode.Signal();
sl@0
   168
        glbPtr->lockThreadTable.Signal();  //release global lock
sl@0
   169
        return;
sl@0
   170
    }
sl@0
   171
    if (tempPtr == glbPtr->start)       // Deleting first node
sl@0
   172
    {
sl@0
   173
        glbPtr->start = tempPtr->next;  //Update the link list
sl@0
   174
    }
sl@0
   175
    else
sl@0
   176
    {
sl@0
   177
        prevPtr->lockNode.Wait();       //Acquire the previous node lock
sl@0
   178
        prevPtr->next = tempPtr->next;  //Update the link list
sl@0
   179
        prevPtr->lockNode.Signal();     //Release the previous node lock
sl@0
   180
    }
sl@0
   181
    
sl@0
   182
    if (NULL != retValPtr)               // Get the return value
sl@0
   183
    {
sl@0
   184
        *retValPtr = selfNodePtr->returnValue;
sl@0
   185
    }
sl@0
   186
sl@0
   187
    selfNodePtr->lockNode.Signal();     // Unlock & Free the node 
sl@0
   188
    selfNodePtr->lockNode.Close();
sl@0
   189
    selfNodePtr->rtHandle.Close();
sl@0
   190
    
sl@0
   191
    delete selfNodePtr;
sl@0
   192
sl@0
   193
    //--(glbPtr->threadCount);           // Update the thread count
sl@0
   194
    //if (THREAD_COUNT_ZERO == glbPtr->threadCount)
sl@0
   195
    //{
sl@0
   196
    //    RProcess rp;
sl@0
   197
    //    rp.Kill(0);                    // Terminate the process
sl@0
   198
    //}
sl@0
   199
    
sl@0
   200
    glbPtr->lockThreadTable.Signal();  // release thread table lock
sl@0
   201
    THR_PRINTF("[pthread] End of _pthread_deleteNode\n");
sl@0
   202
}
sl@0
   203
sl@0
   204
sl@0
   205
void* _getKeyValueSetNull(int keyNumber,_pkey_node_t *tlsPtr)
sl@0
   206
{
sl@0
   207
    void* retVal;
sl@0
   208
    for ( ; tlsPtr != NULL; tlsPtr = tlsPtr->next)
sl@0
   209
    {
sl@0
   210
        if (tlsPtr->keyNumber == keyNumber)
sl@0
   211
        {
sl@0
   212
                retVal = tlsPtr->tls;
sl@0
   213
                tlsPtr->tls = NULL;
sl@0
   214
                return (retVal);
sl@0
   215
        }
sl@0
   216
    }
sl@0
   217
    //This should never happen; hence dest function will not be called
sl@0
   218
    return NULL;
sl@0
   219
}
sl@0
   220
// Before calling this function, global lock and node lock must be open
sl@0
   221
void _pthread_destroyKeys(_global_data_t *glbPtr,
sl@0
   222
                            _pthread_node_t *selfNodePtr)
sl@0
   223
{
sl@0
   224
    int loopvar;
sl@0
   225
    int allempty;
sl@0
   226
    int keyNumber;
sl@0
   227
    destructor_routine dest;
sl@0
   228
    void *arg;
sl@0
   229
    
sl@0
   230
    glbPtr->lockThreadTable.Wait();    // Acquire the thread table lock
sl@0
   231
    selfNodePtr->lockNode.Wait();      // Lock the TCB
sl@0
   232
sl@0
   233
    for (loopvar = 0, allempty = 1;
sl@0
   234
        allempty && (loopvar < PTHREAD_DESTRUCTOR_ITERATIONS);loopvar++) 
sl@0
   235
    {
sl@0
   236
        allempty = 0; // Assuming all keys are not used.
sl@0
   237
        
sl@0
   238
        for (keyNumber = 0; keyNumber < PTHREAD_KEYS_MAX; keyNumber++)
sl@0
   239
        {
sl@0
   240
            int temp;
sl@0
   241
            temp = keyNumber / 32;
sl@0
   242
            
sl@0
   243
            int bitPos;
sl@0
   244
            bitPos = keyNumber % 32;
sl@0
   245
        
sl@0
   246
            if (((glbPtr->statusflag[temp]) & (0x1<<bitPos)) &&      //Key used
sl@0
   247
                (glbPtr->pthread_key_list[keyNumber].destr != NULL))
sl@0
   248
            {
sl@0
   249
                if ((arg = _getKeyValueSetNull(keyNumber,selfNodePtr->tlsHead)) != NULL)
sl@0
   250
                {
sl@0
   251
                    dest = glbPtr->pthread_key_list[keyNumber].destr;
sl@0
   252
                
sl@0
   253
                    selfNodePtr->lockNode.Signal();    // Unlock TCB node
sl@0
   254
                    glbPtr->lockThreadTable.Signal();  // release thread table lock
sl@0
   255
sl@0
   256
                    dest(arg);  //Call destructor
sl@0
   257
sl@0
   258
                    glbPtr->lockThreadTable.Wait();// Acquire the thread table lock
sl@0
   259
                    selfNodePtr->lockNode.Wait();      // Lock the TCB
sl@0
   260
                    
sl@0
   261
                    allempty = 1;   // Atleast one key was used
sl@0
   262
                }
sl@0
   263
            }
sl@0
   264
        }
sl@0
   265
    }
sl@0
   266
    
sl@0
   267
    selfNodePtr->lockNode.Signal();    // Unlock TCB node
sl@0
   268
    glbPtr->lockThreadTable.Signal();  // release thread table lock
sl@0
   269
}
sl@0
   270
sl@0
   271
// End of File