Ejemplo n.º 1
0
//--------------------------------------------------------------------------------------------------
static Service_t* GetService
(
    le_msg_ProtocolRef_t    protocolRef,
    const char*             serviceName
)
//--------------------------------------------------------------------------------------------------
{
    ServiceId_t id;

    id.protocolRef = protocolRef;
    LE_FATAL_IF(le_utf8_Copy(id.name, serviceName, sizeof(id.name), NULL) == LE_OVERFLOW,
                "Service ID '%s' too long (should only be %zu bytes total).",
                serviceName,
                sizeof(id.name));

    Service_t* servicePtr = le_hashmap_Get(ServiceMapRef, &id);
    if (servicePtr == NULL)
    {
        servicePtr = CreateService(protocolRef, serviceName);
    }
    else
    {
        le_mem_AddRef(servicePtr);
    }

    return servicePtr;
}
Ejemplo n.º 2
0
//--------------------------------------------------------------------------------------------------
le_mcc_CallRef_t le_mcc_Create
(
    const char* phoneNumPtr
        ///< [IN]
        ///< The target number we are going to
        ///< call.
)
{
    if (phoneNumPtr == NULL)
    {
        LE_KILL_CLIENT("phoneNumPtr is NULL !");
        return NULL;
    }

    if(strlen(phoneNumPtr) > (LE_MDMDEFS_PHONE_NUM_MAX_BYTES-1))
    {
        LE_KILL_CLIENT("strlen(phoneNumPtr) > %d", (LE_MDMDEFS_PHONE_NUM_MAX_BYTES-1));
        return NULL;
    }

    // Create the Call object.
    le_mcc_Call_t* mccCallPtr = GetCallObject(phoneNumPtr, -1, false);

    if (mccCallPtr != NULL)
    {
        le_mem_AddRef(mccCallPtr);
        mccCallPtr->refCount++;
    }
    else
    {
        mccCallPtr = CreateCallObject (phoneNumPtr,
                                        -1,
                                        LE_MCC_EVENT_TERMINATED,
                                        LE_MCC_TERM_UNDEFINED,
                                        -1);
    }

    // Manage client session
    SessionRefNode_t* newSessionRefPtr = le_mem_ForceAlloc(SessionRefPool);
    newSessionRefPtr->sessionRef = le_mcc_GetClientSessionRef();
    newSessionRefPtr->link = LE_DLS_LINK_INIT;

    // Add the new sessionRef into the the sessionRef list
    le_dls_Queue(&mccCallPtr->sessionRefList,
                    &(newSessionRefPtr->link));

    if (mccCallPtr==NULL)
    {
        LE_ERROR("mccCallPtr null!!!!");
        return NULL;
    }

    LE_DEBUG("Create Call ref.%p", mccCallPtr->callRef);

    // Return a Safe Reference for this Call object.
    return (mccCallPtr->callRef);
}
Ejemplo n.º 3
0
//--------------------------------------------------------------------------------------------------
static void UpdateReferenceCount
(
    le_mcc_Call_t* callPtr
)
{
    while (callPtr->refCount < CallHandlerCount)
    {
        callPtr->refCount++;
        le_mem_AddRef(callPtr);
    }
}
Ejemplo n.º 4
0
//--------------------------------------------------------------------------------------------------
void msgService_AddSession
(
    le_msg_ServiceRef_t serviceRef,
    le_msg_SessionRef_t sessionRef
)
//--------------------------------------------------------------------------------------------------
{
    // The Session object holds a reference to the Service object.
    le_mem_AddRef(serviceRef);

    le_dls_Queue(&serviceRef->sessionList, msgSession_GetListLink(sessionRef));
}
Ejemplo n.º 5
0
//--------------------------------------------------------------------------------------------------
void tu_SessionConnected
(
    le_msg_SessionRef_t sessionRef  ///< [IN] The session just connected.
)
//--------------------------------------------------------------------------------------------------
{
    bool wasCreated;
    tu_UserRef_t userRef = GetUserInfo(sessionRef, &wasCreated);

    if (   (wasCreated == false)
        && (tu_GetUserId(userRef) != 0))
    {
        le_mem_AddRef(userRef);
    }
}
Ejemplo n.º 6
0
//--------------------------------------------------------------------------------------------------
static void FdEventHandler
(
    int fd,
    short events
)
//--------------------------------------------------------------------------------------------------
{
    Parser_t* parserPtr = le_fdMonitor_GetContextPtr();

    // Increment the reference count on the Parser object so it won't go away until we are done
    // with it, even if the client calls le_json_Cleanup() for this parser.
    le_mem_AddRef(parserPtr);

    if (events & POLLIN)    // Data available to read?
    {
        ReadData(parserPtr, fd);
    }

    // Error or hang-up?
    if (NotStopped(parserPtr) && ((events & POLLERR) || (events & POLLHUP) || (events & POLLRDHUP)))
    {
        char msg[256];
        size_t bytesPrinted = snprintf(msg, sizeof(msg), "Read error flags set:");
        if (events & POLLERR)
        {
            bytesPrinted += snprintf(msg + bytesPrinted, sizeof(msg) - bytesPrinted, " POLLERR");
        }
        if (events & POLLHUP)
        {
            bytesPrinted += snprintf(msg + bytesPrinted, sizeof(msg) - bytesPrinted, " POLLHUP");
        }
        if (events & POLLRDHUP)
        {
            bytesPrinted += snprintf(msg + bytesPrinted, sizeof(msg) - bytesPrinted, " POLLRDHUP");
        }
        Error(parserPtr, LE_JSON_READ_ERROR, msg);
    }

    // We are finished with the parser object now.
    le_mem_Release(parserPtr);
}
Ejemplo n.º 7
0
//--------------------------------------------------------------------------------------------------
static pthread_t StartThread
(
    pthread_attr_t* attrPtr,
    void* completionObjPtr  ///< [in] Pointer to the object whose reference count is used to signal
                            ///       the completion of the test.
)
{
    // Increment the reference count on the "completion object".  This will be released by
    // ThreadMain() when the thread completes and has cleaned up its Legato thread-specific data.
    le_mem_AddRef(completionObjPtr);

    pthread_t handle;

    int result = pthread_create(&handle,
                                attrPtr,
                                ThreadMain,
                                completionObjPtr);
    LE_FATAL_IF(result != 0,  "pthread_create() failed with errno %m.");

    return handle;
}
Ejemplo n.º 8
0
//--------------------------------------------------------------------------------------------------
static void StringEventHandler
(
    Parser_t    *parserPtr,
    void        *unused
)
{
    char c;

    LE_UNUSED(unused);

    // Increment the reference count on the Parser object so it won't go away until we are done
    // with it, even if the client calls le_json_Cleanup() for this parser.
    le_mem_AddRef(parserPtr);

    while (NotStopped(parserPtr))
    {
        c = parserPtr->jsonString[parserPtr->bytesRead];
        if (c == '\0') // End of string?
        {
            // The document has been truncated.
            Error(parserPtr, LE_JSON_READ_ERROR, "Unexpected end of JSON string");
            break;
        }
        else
        {
            parserPtr->bytesRead++;
            if (c == '\n')
            {
                parserPtr->line++;
            }
            ProcessChar(parserPtr, c);
        }
    }

    // We are finished with the parser object now.
    le_mem_Release(parserPtr);
}
Ejemplo n.º 9
0
//--------------------------------------------------------------------------------------------------
static void DispatchToHandler
(
    void* param1Ptr,    ///< FD Monitor safe reference.
    void* param2Ptr     ///< epoll() event flags.
)
//--------------------------------------------------------------------------------------------------
{
    uint32_t epollEventFlags = (uint32_t)(size_t)param2Ptr;

    LOCK

    // Get a pointer to the FD Monitor object for this fd.
    FdMonitor_t* fdMonitorPtr = le_ref_Lookup(FdMonitorRefMap, param1Ptr);

    UNLOCK

    // If the FD Monitor object has been deleted, we can just ignore this.
    if (fdMonitorPtr == NULL)
    {
        TRACE("Discarding events for non-existent FD Monitor %p.", param1Ptr);
        return;
    }

    // Sanity check: The FD monitor must belong to the current thread.
    LE_ASSERT(thread_GetEventRecPtr() == fdMonitorPtr->threadRecPtr);

    // Mask out any events that have been disabled since epoll_wait() reported these events to us.
    epollEventFlags &= (fdMonitorPtr->epollEvents | EPOLLERR | EPOLLHUP | EPOLLRDHUP);

    // If there's nothing left to report to the handler, don't call it.
    if (epollEventFlags == 0)
    {
        // Note: if the fd is always ready to read or write (is not supported by epoll()), then
        //       we will only end up in here if both POLLIN and POLLOUT are disabled, in which case
        //       returning now will prevent re-queuing of DispatchToHandler(), which is what we
        //       want.  When either POLLIN or POLLOUT are re-enabled, le_fdMonitor_Enable() will
        //       call fdMon_Report() to get things going again.
        return;
    }

    // Translate the epoll() events into poll() events.
    short pollEvents = EPollToPoll(epollEventFlags);

    if (IS_TRACE_ENABLED())
    {
        char eventsTextBuff[128];

        TRACE("Calling event handler for FD Monitor %s (fd %d, events %s).",
              fdMonitorPtr->name,
              fdMonitorPtr->fd,
              GetPollEventsText(eventsTextBuff, sizeof(eventsTextBuff), pollEvents));
    }

    // Increment the reference count on the Monitor object in case the handler deletes it.
    le_mem_AddRef(fdMonitorPtr);

    // Store a pointer to the FD Monitor as thread-specific data so le_fdMonitor_GetMonitor()
    // and le_fdMonitor_GetContextPtr() can find it.
    LE_ASSERT(pthread_setspecific(FDMonitorPtrKey, fdMonitorPtr) == 0);

    // Set the thread's event loop Context Pointer.
    event_SetCurrentContextPtr(fdMonitorPtr->contextPtr);

    // Call the handler function.
    fdMonitorPtr->handlerFunc(fdMonitorPtr->fd, pollEvents);

    // Clear the thread-specific pointer to the FD Monitor.
    LE_ASSERT(pthread_setspecific(FDMonitorPtrKey, NULL) == 0);

    // If this fd is always ready (is not supported by epoll) and either POLLIN or POLLOUT
    // are enabled, then queue up another dispatcher for this FD Monitor.
    // If neither are enabled, then le_fdMonitor_Enable() will queue the dispatcher
    // when one of them is re-enabled.
    if ((fdMonitorPtr->isAlwaysReady) && (fdMonitorPtr->epollEvents & (EPOLLIN | EPOLLOUT)))
    {
        fdMon_Report(fdMonitorPtr->safeRef, fdMonitorPtr->epollEvents & (EPOLLIN | EPOLLOUT));
    }

    // Release our reference.  We don't need the Monitor object anymore.
    le_mem_Release(fdMonitorPtr);
}
Ejemplo n.º 10
0
int main(int argc, char *argv[])
{
    le_mem_PoolRef_t idPool, colourPool;
    idObj_t* idsPtr[ID_POOL_SIZE + NUM_EXTRA_ID] = {NULL};
    colourObj_t* coloursPtr[COLOUR_POOL_SIZE] = {NULL};
    unsigned int i = 0;
    unsigned int numRelease = 0;


    printf("\n");
    printf("*** Unit Test for le_mem module. ***\n");


    //
    // Create multiple pools.
    //
    idPool = le_mem_CreatePool("ID Pool", sizeof(idObj_t));
    colourPool = le_mem_CreatePool("Colour Pool", sizeof(colourObj_t));

    printf("Created two memory pools.\n");


    //
    // Expand the pools.
    //
    idPool = le_mem_ExpandPool(idPool, ID_POOL_SIZE);
    colourPool = le_mem_ExpandPool(colourPool, COLOUR_POOL_SIZE);

    printf("Expanded all pools.\n");


    //
    // Set destructors.
    //
    le_mem_SetDestructor(idPool, IdDestructor);


    //
    // Spawn child process and perform Assert allocation until failure.
    //
    pid_t pID = fork();
    if (pID == 0)
    {
        // This is the child.

        // Allocate more than the available objects so the assert will kill the process.
        for (i = 0; i < ID_POOL_SIZE + 1; i++)
        {
            idsPtr[i] = le_mem_AssertAlloc(idPool);
        }

        return LE_OK;
    }
    else
    {
        int status;

        // wait for the child to terminate.
        wait(&status);

        if ( WEXITSTATUS(status) == EXIT_FAILURE ) // Child terminated with an error.
        {
            printf("Assert allocation performed correctly.\n");
        }
        else
        {
            printf("Assert allocation incorrect: %d", __LINE__);
            return LE_FAULT;
        }
    }

    //
    // Allocate all objects.
    //
    for (i = 0; i < ID_POOL_SIZE; i++)
    {
        idsPtr[i] = le_mem_TryAlloc(idPool);

        if (idsPtr[i] == NULL)
        {
            printf("Allocation error: %d", __LINE__);
            return LE_FAULT;
        }

        idsPtr[i]->id = i;
    }

    for (i = 0; i < COLOUR_POOL_SIZE; i++)
    {
        coloursPtr[i] = le_mem_TryAlloc(colourPool);

        if (coloursPtr[i] == NULL)
        {
            printf("Allocation error: %d", __LINE__);
            return LE_FAULT;
        }

        coloursPtr[i]->r = i;
        coloursPtr[i]->g = i + 1;
        coloursPtr[i]->b = i + 2;
    }

    printf("Allocated all objects from all pools.\n");


    //
    // Check objects
    //
    for (i = 0; i < ID_POOL_SIZE; i++)
    {
        if (idsPtr[i]->id != i)
        {
            printf("Object error: %d", __LINE__);
            return LE_FAULT;
        }
    }

    for (i = 0; i < COLOUR_POOL_SIZE; i++)
    {
        if ( (coloursPtr[i]->r != i) ||
                (coloursPtr[i]->g != i+1) ||
                (coloursPtr[i]->b != i+2) )
        {
            printf("Object error: %d", __LINE__);
            return LE_FAULT;
        }
    }

    printf("Checked all objects in pools.\n");


    //
    // Randomly release some objects.
    //
    {
        //seed the random number generator with the clock
        srand((unsigned int)clock());

        idObj_t* objPtr;
        size_t numNotReleased = 0;
        NumRelease = 0;
        for (i = 0; i < ID_POOL_SIZE; i++)
        {
            objPtr = idsPtr[i];

            if (rand() < REMOVE_THRESHOLD)
            {
                // Increase the ref number for these objects.
                le_mem_AddRef(objPtr);

                // These objects should not get freed.
                numNotReleased++;
            }
            else
            {
                idsPtr[i] = NULL;
            }

            // Release all objects but only objects that did not have their ref count increased will be released.
            le_mem_Release(objPtr);
        }

        if (NumRelease != ID_POOL_SIZE - numNotReleased)
        {
            printf("Released objects incorrectly: %d", __LINE__);
            return LE_FAULT;
        }

        // Release the rest of the objects.
        for (i = 0; i < ID_POOL_SIZE; i++)
        {
            if (idsPtr[i] != NULL)
            {
                le_mem_Release(idsPtr[i]);
                idsPtr[i] = NULL;
            }
        }

        // Check the number of free objects.
        le_mem_PoolStats_t stats;
        le_mem_GetStats(idPool, &stats);

        if (stats.numFree != ID_POOL_SIZE)
        {
            printf("Released objects incorrectly: %d", __LINE__);
            return LE_FAULT;
        }

        // Spawn child process and try to release an object that is already released.
        pid_t pID = fork();
        if (pID == 0)
        {
            // This is the child.
            // This allocation should fail and kill the process.
            le_mem_Release(objPtr);

            return LE_OK;
        }
        else
        {
            int status;

            // wait for the child to terminate.
            wait(&status);

            if ( WEXITSTATUS(status) == EXIT_FAILURE ) // Child terminated with an error.
            {
                printf("Ref count correct.\n");
            }
            else
            {
                printf("Ref count incorrect: %d", __LINE__);
                return LE_FAULT;
            }
        }
    }
    printf("Released objects according to ref counts correctly.\n");
    printf("Checked that destructors were called correctly.\n");


    //
    // Try allocate until full.
    //
    for (i = 0; i < ID_POOL_SIZE; i++)
    {
        if (idsPtr[i] == NULL)
        {
            idsPtr[i] = le_mem_TryAlloc(idPool);

            if (idsPtr[i] == NULL)
            {
                printf("Allocation error: %d.", __LINE__);
                return LE_FAULT;
            }
        }
    }

    // The pool should now be empty.
    if (le_mem_TryAlloc(idPool) != NULL)
    {
        printf("Allocation error: %d.", __LINE__);
        return LE_FAULT;
    }

    printf("Tried allocating from empty pool.\n");

    //
    // Force allocate.
    //
    le_mem_SetNumObjsToForce(idPool, FORCE_SIZE);
    for (i = ID_POOL_SIZE; i < ID_POOL_SIZE + NUM_EXTRA_ID; i++)
    {
        idsPtr[i] = le_mem_ForceAlloc(idPool);

        if (idsPtr[i] == NULL)
        {
            printf("Allocation error: %d.", __LINE__);
            return LE_FAULT;
        }
    }
    printf("Forced allocated objects.\n");


    //
    // Get stats.
    //
    le_mem_PoolStats_t stats;
    le_mem_GetStats(idPool, &stats);

    if ( (stats.numAllocs != ID_POOL_SIZE + NUM_EXTRA_ID + NumRelease) ||
            (stats.numOverflows != (unsigned int)ceil(((1.0*NUM_EXTRA_ID / FORCE_SIZE)))) ||
            (stats.numFree != (stats.numOverflows*FORCE_SIZE) % NUM_EXTRA_ID) )
    {
        printf("Stats are incorrect: %d", __LINE__);
        return LE_FAULT;
    }
    printf("Stats are correct.\n");


    //
    // Get pool size.
    //
    if (le_mem_GetTotalNumObjs(idPool) != ID_POOL_SIZE + (stats.numOverflows * FORCE_SIZE))
    {
        printf("Pool size incorrect: %d", __LINE__);
        return LE_FAULT;
    }
    printf("Checked pool size.\n");


    //
    // Get object size.
    //
    if (le_mem_GetObjectSize(idPool) != sizeof(idObj_t))
    {
        printf("Object size incorrect: %d", __LINE__);
        return LE_FAULT;
    }
    printf("Checked object size.\n");


    //
    // Reset stats.
    //
    {
        size_t numFree = stats.numFree;

        le_mem_ResetStats(idPool);
        le_mem_GetStats(idPool, &stats);

        if ( (stats.numAllocs != 0) ||
                (stats.numOverflows != 0) ||
                (stats.numFree != numFree) )
        {
            printf("Stats are incorrect: %d", __LINE__);
            return LE_FAULT;
        }
    }
    printf("Reset stats correctly.\n");


    //
    // Create sub-pool.
    //

    // Release some objs from the super-pool in a random manner.
    numRelease = 0;
    for (i = 0; i < COLOUR_POOL_SIZE; i++)
    {
        if (rand() < REMOVE_THRESHOLD)
        {
            le_mem_Release(coloursPtr[i]);
            coloursPtr[i] = NULL;
            numRelease++;
        }
    }


    // Create the sub-pool.
    le_mem_PoolRef_t colourSubPool1 = le_mem_CreateSubPool(colourPool, "Colour sub-pool", numRelease);


    //
    // Check sub-pools and super-pool.
    //
    if ( (le_mem_GetTotalNumObjs(colourSubPool1) != numRelease) ||
            (le_mem_GetTotalNumObjs(colourPool) != COLOUR_POOL_SIZE) )
    {
        printf("Sub-pool incorrect: %d", __LINE__);
        return LE_FAULT;
    }
    printf("Sub-pool created correctly.\n");


    //
    // Create second sub-pool.
    //

    // Release the rest of the objects from the super-pool.
    for (i = 0; i < COLOUR_POOL_SIZE; i++)
    {
        if (coloursPtr[i] != NULL)
        {
            le_mem_Release(coloursPtr[i]);
            coloursPtr[i] = NULL;
        }
    }

    // Create another sub-pool.
    le_mem_PoolRef_t colourSubPool2 = le_mem_CreateSubPool(colourPool, "Second sub-pool", COLOUR_POOL_SIZE - numRelease);
    printf("Created second sub-pool.\n");


    //
    // Expand the sub-pool causing the super-pool to expand.
    //
    le_mem_ExpandPool(colourSubPool2, NUM_EXPAND_SUB_POOL);


    //
    // Allocate from sub-pool.
    //
    for (i = 0; i < COLOUR_POOL_SIZE - numRelease; i++)
    {
        coloursPtr[i] = le_mem_TryAlloc(colourSubPool2);

        if (coloursPtr[i] == NULL)
        {
            printf("Error allocating from sub-pool: %d", __LINE__);
            return LE_FAULT;
        }
    }


    //
    // Check pools.
    //
    le_mem_GetStats(colourPool, &stats);
    if ( (le_mem_GetTotalNumObjs(colourPool) != COLOUR_POOL_SIZE + NUM_EXPAND_SUB_POOL) || (stats.numFree != 0) )
    {
        printf("Error in super-pool: %d", __LINE__);
        return LE_FAULT;
    }

    le_mem_GetStats(colourSubPool1, &stats);
    if ( (le_mem_GetTotalNumObjs(colourSubPool1) != numRelease) || (stats.numFree != numRelease) )
    {
        printf("Error in sub-pool: %d", __LINE__);
        return LE_FAULT;
    }

    le_mem_GetStats(colourSubPool2, &stats);
    if ( (le_mem_GetTotalNumObjs(colourSubPool2) != COLOUR_POOL_SIZE - numRelease + NUM_EXPAND_SUB_POOL) || (stats.numFree != NUM_EXPAND_SUB_POOL) )
    {
        printf("Error in sub-pool: %d", __LINE__);
        return LE_FAULT;
    }
    printf("Expanded sub-pool correctly.\n");
    printf("Allocated from sub-pools correctly.\n");


    // Try Allocating from empty super-pool.
    if (le_mem_TryAlloc(colourPool) != NULL)
    {
        printf("Error in super-pool: %d", __LINE__);
        return LE_FAULT;
    }

    //
    // Delete sub-pool.
    //
    le_mem_DeleteSubPool(colourSubPool1);

    // Allocate from the super-pool.
    for (i = 0; i < NUM_ALLOC_SUPER_POOL; i++)
    {
        coloursPtr[numRelease] = le_mem_AssertAlloc(colourPool);
    }


    //
    // Check pools.
    //
    le_mem_GetStats(colourPool, &stats);
    if ( (stats.numFree != numRelease - NUM_ALLOC_SUPER_POOL) )
    {
        printf("Error in super-pool: %d", __LINE__);
        return LE_FAULT;
    }

    le_mem_GetStats(colourSubPool2, &stats);
    if ( (le_mem_GetTotalNumObjs(colourSubPool2) != COLOUR_POOL_SIZE - numRelease + NUM_EXPAND_SUB_POOL) || (stats.numFree != NUM_EXPAND_SUB_POOL) )
    {
        printf("Error in sub-pool: %d", __LINE__);
        return LE_FAULT;
    }
    printf("Deleted sub-pool correctly.\n");


    //
    // Re-create sub-pool causing super pool to expand.
    //
    colourSubPool1 = le_mem_CreateSubPool(colourPool, "First sub-pool", numRelease + NUM_EXPAND_SUB_POOL);

    if ( (le_mem_GetTotalNumObjs(colourSubPool1) != numRelease + NUM_EXPAND_SUB_POOL) ||
            (le_mem_GetTotalNumObjs(colourPool) != COLOUR_POOL_SIZE + 2*NUM_EXPAND_SUB_POOL + NUM_ALLOC_SUPER_POOL) )
    {
        printf("Error re-creating sub-pool: %d", __LINE__);
        return LE_FAULT;
    }
    printf("Successfully recreated sub-pool.\n");


    //
    // Search for pools by name.
    //
    if ( (idPool != le_mem_FindPool("ID Pool")) ||
            (colourSubPool1 != le_mem_FindPool("First sub-pool")) )
    {
        printf("Error finding pools by name: %d", __LINE__);
        return LE_FAULT;
    }
    printf("Successfully searched for pools by name.\n");


    printf("*** Unit Test for le_mem module passed. ***\n");
    printf("\n");
    return LE_OK;
}
Ejemplo n.º 11
0
// -------------------------------------------------------------------------------------------------
static void SpawnChildren
(
    size_t depth,           // Indicates what nesting level the thread is at.
                            // 1 = children of the process main thread.

    void*  completionObjPtr // Ptr to the object whose ref count is used to terminate the test.
)
// -------------------------------------------------------------------------------------------------
{
    int i;
    char childName[32];
    le_thread_Ref_t children[FAN_OUT];

    // Create and start all the children.
    for (i = 0; i < FAN_OUT; i++)
    {
        le_thread_Ref_t threadRef;

        Context_t* contextPtr = le_mem_ForceAlloc(ContextPoolRef);
        contextPtr->depth = depth;
        contextPtr->completionObjPtr = completionObjPtr;
        le_mem_AddRef(completionObjPtr);

        snprintf(childName, sizeof(childName), "%s-%d", le_thread_GetMyName(), i + 1);

        LE_INFO("Spawning thread '%s'.", childName);

        threadRef = le_thread_Create(childName, ThreadMainFunction, contextPtr);

        LE_INFO("Thread '%s' created.", childName);

        // Create a thread destructor that will release the Context object and the
        // Test Completion Object that we are going to pass to the child.
        le_thread_AddChildDestructor(threadRef, ThreadDestructor, contextPtr);

        LE_INFO("Thread '%s' destructor added.", childName);

        // Make every third child thread non-joinable and the rest joinable.
        if (((i + 1) % 3) != 0)
        {
            le_thread_SetJoinable(threadRef);
        }

        LE_INFO("Thread '%s' joinability set.", childName);

        // Start the child thread.
        le_thread_Start(threadRef);

        LE_INFO("Thread '%s' started.", childName);

        // Remember the child's thread reference for later join attempt.
        children[i] = threadRef;
    }

    // Join with all the children.
    for (i = 0; i < FAN_OUT; i++)
    {
        void* threadReturnValue;

        snprintf(childName, sizeof(childName), "%s-%d", le_thread_GetMyName(), i + 1);
        LE_INFO("Joining with thread '%s'.", childName);

        le_result_t result = le_thread_Join(children[i], &threadReturnValue);

        if (result != LE_OK)
        {
            LE_INFO("Failed to join with thread '%s'.", childName);
            LE_FATAL_IF(((i + 1) % 3) != 0, "Failed to join with joinable thread '%s'!", childName);
        }
        else
        {
            LE_INFO("Successfully joined with thread '%s', which returned %p.",
                    childName,
                    threadReturnValue);
            LE_FATAL_IF(((i + 1) % 3) == 0, "Joined with non-joinable thread '%s'!", childName);
            LE_FATAL_IF(threadReturnValue != completionObjPtr,
                        "Thread returned strange value %p.  Expected %p.",
                        threadReturnValue,
                        completionObjPtr);
        }
    }
}
Ejemplo n.º 12
0
static void TestPools
(
    le_mem_PoolRef_t idPool,            ///< [IN] ID pool
    le_mem_PoolRef_t colourPool,        ///< [IN] Colour pool
    le_mem_PoolRef_t stringPool         ///< [IN] String pool
)
{
    idObj_t* idsPtr[ID_POOL_SIZE + NUM_EXTRA_ID] = {NULL};
    colourObj_t* coloursPtr[COLOUR_POOL_SIZE] = {NULL};
    char* stringsPtr[4*STRING_POOL_SIZE] = {NULL};
    unsigned int i = 0;
    unsigned int numRelease = 0;

    LE_TEST_BEGIN_SKIP(!LE_CONFIG_IS_ENABLED(LE_CONFIG_LINUX), 1);
#if LE_CONFIG_LINUX
    //
    // Spawn child process and perform Assert allocation until failure.
    //
    pid_t pID = fork();
    if (pID == 0)
    {
        // This is the child.

        // Allocate more than the available objects so the assert will kill the process.
        for (i = 0; i < ID_POOL_SIZE + 1; i++)
        {
            idsPtr[i] = le_mem_AssertAlloc(idPool);
        }

        exit(EXIT_SUCCESS);
    }
    else
    {
        int status;

        // wait for the child to terminate.
        wait(&status);

        LE_TEST_OK(WEXITSTATUS(status) == EXIT_FAILURE, "Assert allocation");
    }
#endif /* end LE_CONFIG_LINUX */
    LE_TEST_END_SKIP();

    //
    // Allocate all objects.
    //
    for (i = 0; i < ID_POOL_SIZE; i++)
    {
        idsPtr[i] = le_mem_TryAlloc(idPool);

        LE_TEST_OK(NULL != idsPtr[i], "Allocate id %d", i);
        if (NULL != idsPtr[i])
        {
            idsPtr[i]->id = i;
        }
    }

    for (i = 0; i < COLOUR_POOL_SIZE; i++)
    {
        coloursPtr[i] = le_mem_TryAlloc(colourPool);

        LE_TEST_OK(NULL != coloursPtr[i], "Allocate color %d", i);

        if (NULL != idsPtr[i])
        {
            coloursPtr[i]->r = i;
            coloursPtr[i]->g = i + 1;
            coloursPtr[i]->b = i + 2;
        }
    }

    //
    // Check objects
    //
    for (i = 0; i < ID_POOL_SIZE; i++)
    {
        LE_TEST_OK(idsPtr[i] && (idsPtr[i]->id == i), "Check id %d", i);
    }

    for (i = 0; i < COLOUR_POOL_SIZE; i++)
    {
        LE_TEST_OK(coloursPtr[i] &&
                   ((coloursPtr[i]->r == i) &&
                    (coloursPtr[i]->g == i+1) &&
                    (coloursPtr[i]->b == i+2)), "Check color %d", i);
    }

    //
    // Randomly release some objects.
    //
    {
        struct timespec ts;

        clock_gettime(CLOCK_MONOTONIC, &ts);
        //seed the random number generator with the clock
        srand((unsigned int)(ts.tv_nsec/1000)^ts.tv_sec);

        idObj_t* objPtr;
        unsigned int numNotReleased = 0;
        NumRelease = 0;
        for (i = 0; i < ID_POOL_SIZE; i++)
        {
            objPtr = idsPtr[i];

            if (rand() < REMOVE_THRESHOLD)
            {
                // Increase the ref number for these objects.
                le_mem_AddRef(objPtr);

                // These objects should not get freed.
                numNotReleased++;
            }
            else
            {
                idsPtr[i] = NULL;
            }

            // Release all objects but only objects that did not have their ref count increased will be released.
            le_mem_Release(objPtr);
        }

        LE_TEST_OK((NumRelease == ID_POOL_SIZE - numNotReleased),
                   "Released %u/%d objects (%u remaining)",
                   NumRelease, ID_POOL_SIZE, numNotReleased);

        // Release the rest of the objects.
        for (i = 0; i < ID_POOL_SIZE; i++)
        {
            if (idsPtr[i] != NULL)
            {
                le_mem_Release(idsPtr[i]);
                idsPtr[i] = NULL;
            }
        }

        // Check the number of free objects.
        LE_TEST_BEGIN_SKIP(TEST_MEM_VALGRIND || !LE_CONFIG_IS_ENABLED(LE_CONFIG_MEM_POOL_STATS), 1);
        le_mem_PoolStats_t stats;
        le_mem_GetStats(idPool, &stats);

        LE_TEST_OK((stats.numFree == ID_POOL_SIZE),
                   "Released all objects correctly");
        LE_TEST_END_SKIP();

        LE_TEST_BEGIN_SKIP(!LE_CONFIG_IS_ENABLED(LE_CONFIG_LINUX), 2);
#if LE_CONFIG_LINUX
        // Spawn child process and try to release an object that is already released.
        pid_t pID = fork();
        if (pID == 0)
        {
            // This is the child.
            // This allocation should fail and kill the process.
            le_mem_Release(objPtr);

            exit(EXIT_SUCCESS);
        }
        else
        {
            int status;

            // wait for the child to terminate.
            wait(&status);

            LE_TEST_OK(( WEXITSTATUS(status) == EXIT_FAILURE ),
                       "Double free terminates process"); // Child terminated with an error.
        }
#endif /* end LE_CONFIG_LINUX */
        LE_TEST_END_SKIP();
    }

    //
    // Try allocate until full.
    //
    for (i = 0; i < ID_POOL_SIZE; i++)
    {
        if (NULL == idsPtr[i])
        {
            idsPtr[i] = le_mem_TryAlloc(idPool);

            LE_TEST_OK(NULL != idsPtr[i], "Allocate id %d", i);
        }
    }

    // The pool should now be empty.
    LE_TEST_BEGIN_SKIP(TEST_MEM_VALGRIND, 1);
    LE_TEST_OK (le_mem_TryAlloc(idPool) == NULL,
                "Allocate from empty pool");
    LE_TEST_END_SKIP();

    //
    // Force allocate.
    //
    le_mem_SetNumObjsToForce(idPool, FORCE_SIZE);
    for (i = ID_POOL_SIZE; i < ID_POOL_SIZE + NUM_EXTRA_ID; i++)
    {
        idsPtr[i] = le_mem_ForceAlloc(idPool);

        LE_TEST_OK((NULL != idsPtr[i]), "Force alloc id %d", i);
    }

    //
    // Get stats.
    //
    le_mem_PoolStats_t stats;

    LE_TEST_BEGIN_SKIP(TEST_MEM_VALGRIND || !LE_CONFIG_IS_ENABLED(LE_CONFIG_MEM_POOL_STATS), 2);
    le_mem_GetStats(idPool, &stats);

    LE_TEST_OK(((stats.numAllocs == ID_POOL_SIZE + NUM_EXTRA_ID + NumRelease) &&
                (stats.numOverflows == (unsigned int)ceil(((1.0*NUM_EXTRA_ID / FORCE_SIZE)))) &&
                (stats.numFree == (stats.numOverflows*FORCE_SIZE) % NUM_EXTRA_ID)),
               "Check stats");

    //
    // Get pool size.
    //
    LE_TEST_OK((le_mem_GetObjectCount(idPool) == ID_POOL_SIZE + (stats.numOverflows * FORCE_SIZE)),
               "Check pool size");
    LE_TEST_END_SKIP();

    //
    // Get object size.
    //
    LE_TEST_OK((le_mem_GetObjectSize(idPool) == sizeof(idObj_t)),
               "Check object size");

    //
    // Reset stats.
    //
    LE_TEST_BEGIN_SKIP(TEST_MEM_VALGRIND || !LE_CONFIG_IS_ENABLED(LE_CONFIG_MEM_POOL_STATS), 1);
    {
        size_t numFree = stats.numFree;

        le_mem_ResetStats(idPool);
        le_mem_GetStats(idPool, &stats);

        LE_TEST_OK(((stats.numAllocs == 0) &&
                    (stats.numOverflows == 0) &&
                    (stats.numFree == numFree) ),
                   "Check reset stats");
    }
    LE_TEST_END_SKIP();

    //
    // Create sub-pool.
    //

    // Release some objs from the super-pool in a random manner.
    numRelease = 0;
    for (i = 0; i < COLOUR_POOL_SIZE; i++)
    {
        if (rand() < REMOVE_THRESHOLD)
        {
            le_mem_Release(coloursPtr[i]);
            coloursPtr[i] = NULL;
            numRelease++;
        }
    }

    // Create the sub-pool.
    le_mem_PoolRef_t colourSubPool1 = le_mem_CreateSubPool(colourPool, "Colour sub-pool", numRelease);

    //
    // Check sub-pools and super-pool.
    //
    LE_TEST_OK(NULL != colourSubPool1, "Create sub-pool");
    LE_TEST_BEGIN_SKIP(TEST_MEM_VALGRIND, 1);
    LE_TEST_OK(( (le_mem_GetObjectCount(colourSubPool1) == numRelease) &&
                 (le_mem_GetObjectCount(colourPool) == COLOUR_POOL_SIZE) ),
               "Check sub-pool size");
    LE_TEST_END_SKIP();

    //
    // Create second sub-pool.
    //

    // Release the rest of the objects from the super-pool.
    for (i = 0; i < COLOUR_POOL_SIZE; i++)
    {
        if (coloursPtr[i] != NULL)
        {
            le_mem_Release(coloursPtr[i]);
            coloursPtr[i] = NULL;
        }
    }

    // Create another sub-pool.
    le_mem_PoolRef_t colourSubPool2 =
        le_mem_CreateSubPool(colourPool, "Second sub-pool", COLOUR_POOL_SIZE - numRelease);
    LE_TEST_OK(NULL != colourSubPool2, "Create second sub-pool");

    //
    // Expand the sub-pool causing the super-pool to expand.
    //
    le_mem_ExpandPool(colourSubPool2, NUM_EXPAND_SUB_POOL);

    //
    // Allocate from sub-pool.
    //
    for (i = 0; i < COLOUR_POOL_SIZE - numRelease; i++)
    {
        coloursPtr[i] = le_mem_TryAlloc(colourSubPool2);

        LE_TEST_OK(NULL != coloursPtr[i], "Allocate color %d from sub-pool", i);
    }

    //
    // Check pools.
    //
    LE_TEST_BEGIN_SKIP(TEST_MEM_VALGRIND || !LE_CONFIG_IS_ENABLED(LE_CONFIG_MEM_POOL_STATS), 4);
    le_mem_GetStats(colourPool, &stats);
    LE_TEST_OK(( (le_mem_GetObjectCount(colourPool) == COLOUR_POOL_SIZE + NUM_EXPAND_SUB_POOL) &&
                 (stats.numFree == 0) ),
               "Check super-pool stats");

    le_mem_GetStats(colourSubPool1, &stats);
    LE_TEST_OK(( (le_mem_GetObjectCount(colourSubPool1) == numRelease) &&
                 (stats.numFree == numRelease) ),
               "Check sub-pool stats");

    le_mem_GetStats(colourSubPool2, &stats);
    LE_TEST_OK(( (le_mem_GetObjectCount(colourSubPool2) ==
                  COLOUR_POOL_SIZE - numRelease + NUM_EXPAND_SUB_POOL) &&
                 (stats.numFree == NUM_EXPAND_SUB_POOL) ),
               "Check second sub-pool stats");

    // Try Allocating from empty super-pool.
    LE_TEST_OK(le_mem_TryAlloc(colourPool) == NULL,
               "Allocate from empty super-pool");
    LE_TEST_END_SKIP();

    //
    // Delete sub-pool.
    //
    le_mem_DeleteSubPool(colourSubPool1);

    // Allocate from the super-pool.
    for (i = 0; i < NUM_ALLOC_SUPER_POOL; i++)
    {
        if (COLOUR_POOL_SIZE > numRelease)
        {
            coloursPtr[numRelease] = le_mem_TryAlloc(colourPool);
            LE_TEST_OK(NULL != coloursPtr[numRelease],
                       "Allocate item %d from super-pool", numRelease);
        }
    }

    //
    // Check pools.
    //
    LE_TEST_BEGIN_SKIP(TEST_MEM_VALGRIND || !LE_CONFIG_IS_ENABLED(LE_CONFIG_MEM_POOL_STATS), 3);
    le_mem_GetStats(colourPool, &stats);
    LE_TEST_OK((stats.numFree == numRelease - NUM_ALLOC_SUPER_POOL),
               "checking super-pool stats after releasing sub-pool");

    le_mem_GetStats(colourSubPool2, &stats);
    LE_TEST_OK(( (le_mem_GetObjectCount(colourSubPool2) ==
                  COLOUR_POOL_SIZE - numRelease + NUM_EXPAND_SUB_POOL) &&
                 (stats.numFree == NUM_EXPAND_SUB_POOL) ),
               "checking second sub-pool stats after releasing sub-pool");

    //
    // Re-create sub-pool causing super pool to expand.
    //
    colourSubPool1 = le_mem_CreateSubPool(colourPool, "First sub-pool", numRelease + NUM_EXPAND_SUB_POOL);

    LE_TEST_OK(((le_mem_GetObjectCount(colourSubPool1) == numRelease + NUM_EXPAND_SUB_POOL) &&
                (le_mem_GetObjectCount(colourPool) ==
                 COLOUR_POOL_SIZE + 2*NUM_EXPAND_SUB_POOL + NUM_ALLOC_SUPER_POOL)),
               "recreated sub-pool");
    LE_TEST_END_SKIP();

    // Create some reduced sub-pools
    le_mem_PoolRef_t tieredStrPoolMed = le_mem_CreateReducedPool(stringPool,
                                                                 "stringPoolMed",
                                                                 0, STRING_POOL_MED_BYTES);
    le_mem_PoolRef_t tieredStrPoolSmall = le_mem_CreateReducedPool(tieredStrPoolMed,
                                                                   "stringPoolSmall",
                                                                   4, STRING_POOL_SMALL_BYTES);

    size_t medObjectSize   = le_mem_GetObjectSize(tieredStrPoolMed);
    size_t smallObjectSize = le_mem_GetObjectSize(tieredStrPoolSmall);

    LE_TEST_OK(STRING_POOL_MED_BYTES <= medObjectSize && medObjectSize < STRING_POOL_BYTES/2,
               "Check medium pool size (%"PRIuS") is reasonable", medObjectSize);
    LE_TEST_OK(STRING_POOL_SMALL_BYTES <= smallObjectSize && smallObjectSize < medObjectSize/2,
               "Check small pool size (%"PRIuS") is reasonable", smallObjectSize);

    // Try allocating random sized strings
    int points = STRING_POOL_SIZE*4;
    for (i = 0; i < 4*STRING_POOL_SIZE && points >= 4; i++)
    {
        // Always allocate at least one byte
        size_t allocSize = (rand() % (STRING_POOL_BYTES-1)) + 1;
        stringsPtr[i] = le_mem_ForceVarAlloc(tieredStrPoolSmall, allocSize);
        LE_TEST_OK(stringsPtr[i], "allocate buffer %d (size %"PRIuS")", i, allocSize);
        memset(stringsPtr[i], 'a', allocSize);
        if (allocSize <= smallObjectSize)
        {
            points -= 1;
            LE_TEST_OK(le_mem_GetBlockSize(stringsPtr[i]) == smallObjectSize,
                       "got a small object");
        }
        else if (allocSize <= medObjectSize)
        {
            points -= 2;
            LE_TEST_OK(le_mem_GetBlockSize(stringsPtr[i]) == medObjectSize,
                       "got a medium object");
        }
        else
        {
            points -= 4;
            LE_TEST_OK(le_mem_GetBlockSize(stringsPtr[i]) == STRING_POOL_BYTES,
                       "got a large object");
        }
    }

    // Now try hibernating -- first disable interrupts
    LE_TEST_BEGIN_SKIP(!LE_CONFIG_IS_ENABLED(LE_CONFIG_RTOS), 3);
#if LE_CONFIG_RTOS
    taskENTER_CRITICAL();
    void *beginFree, *endFree;
    le_mem_Hibernate(&beginFree, &endFree);
    LE_TEST_OK(endFree - beginFree > 0,
               "Free %" PRIuS " bytes of memory by hibernating", endFree - beginFree);
    le_mem_Resume();
    taskEXIT_CRITICAL();
#endif /* end LE_CONFIG_RTOS */
    LE_TEST_END_SKIP();

    // Now finish up by allocating some small strings
    for(; i < 4*STRING_POOL_SIZE && points >= 0; ++i)
    {
        stringsPtr[i] = le_mem_ForceVarAlloc(tieredStrPoolSmall, 1);
        LE_TEST_OK(stringsPtr[i], "allocate buffer %d (size 1)", i);
        memset(stringsPtr[i], 'b', 1);
        LE_TEST_OK(le_mem_GetBlockSize(stringsPtr[i]) == smallObjectSize,
                   "got a small object");
        points -= 1;
    }

    LE_TEST_INFO("Releasing some buffers");
    for (i = 0; i < 4*STRING_POOL_SIZE && stringsPtr[i]; i++)
    {
        if (rand() < REMOVE_THRESHOLD)
        {
            le_mem_Release(stringsPtr[i]);
            stringsPtr[i] = NULL;
            numRelease++;
        }
    }

    LE_TEST_INFO("Re-allocate as small buffers");
    for (; i-- > 0; )
    {
        if (!stringsPtr[i])
        {
            stringsPtr[i] = le_mem_ForceVarAlloc(tieredStrPoolSmall, 1);
            LE_TEST_OK(stringsPtr[i], "allocated a small buffer");
            memset(stringsPtr[i], 'c', 1);
        }
    }

    LE_TEST_INFO("Free everything");
    for (i = 0; i < 4*STRING_POOL_SIZE && stringsPtr[i]; ++i)
    {
        le_mem_Release(stringsPtr[i]);
        stringsPtr[i] = NULL;
    }

    // And delete the sub-pools
    LE_TEST_INFO("Delete sub-pools");
    le_mem_DeleteSubPool(tieredStrPoolSmall);
    le_mem_DeleteSubPool(tieredStrPoolMed);
}