Source

dark-hammer / src / core / thread.c

The branch 'v0.4' does not exist.
/***********************************************************************************
 * Copyright (c) 2012, Sepehr Taghdisian
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without modification, 
 * are permitted provided that the following conditions are met:
 *
 * - Redistributions of source code must retain the above copyright notice, 
 *   this list of conditions and the following disclaimer.
 * - Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation 
 *   and/or other materials provided with the distribution.
 *
 ***********************************************************************************/

#if defined(_WIN_)
#include "win.h"
#include <process.h>
#endif

#include <stdio.h>
#include "memory.h"
#include "thread.h"
#include "errors.h"

#if !defined(_WIN_)
void* thread_func(void* param);

/* */
struct thread* mt_createthread(pfn_thread_kernel kernel_fn,
                         pfn_thread_init init_fn,
                         pfn_thread_release release_fn, 
                         enum thread_level level, 
                         uint32 local_mem_sz,
                         void* param1, void* param2)
{
    result_t r;
    struct thread* thr = ALLOC(sizeof(struct thread), 0);
    memset(thr, 0x00, sizeof(struct thread));
    
    if (local_mem_sz > 0)   {
        r = mem_freelist_create(mem_heap(), &thr->local_mem, local_mem_sz, 0);
        if (IS_FAIL(r))
            return NULL;
        mem_freelist_bindalloc(&thr->local_mem, &thr->local_alloc);
    }
    
    thr->kernel_fn = kernel_fn;
    thr->init_fn = init_fn;
    thr->release_fn = release_fn;
    thr->level = level;
    thr->param1 = param1;
    thr->param2 = param2;
    
    /* create thread and it's conditiion/mutex variables */
    mt_createmutex(&thr->state_mutex);
    pthread_cond_init(&thr->state_event, NULL);
    
    pthread_attr_init(&thr->attr);
    pthread_attr_setdetachstate(&thr->attr, PTHREAD_CREATE_JOINABLE);
    int32 r2 = pthread_create(&thr->t, &thr->attr, thread_func, thr);
    if (r2 != 0)     {
        mt_destroythread(thr);
        return NULL;
    }    
    
    return thr;
}

void mt_destroythread(struct thread* thr)
{
    if (thr->t != THREAD_NULL)  {
        /* stop the thread */
        mt_lockmutex(&thr->state_mutex);
        thr->state = THREAD_STATE_STOP;
        mt_unlockmutex(&thr->state_mutex);
        
        /* wait for thread exit */
        pthread_join(thr->t, NULL);
    }
    
    pthread_attr_destroy(&thr->attr);
    mt_destroymutex(&thr->state_mutex);
    pthread_cond_destroy(&thr->state_event);
    
    mem_freelist_destroy(&thr->local_mem);
    FREE(thr);
}

void mt_pausethread(struct thread* thr)
{
    mt_lockmutex(&thr->state_mutex);
    thr->state = THREAD_STATE_PAUSE;
    mt_unlockmutex(&thr->state_mutex);
}

void mt_resumethread(struct thread* thr)
{
    mt_lockmutex(&thr->state_mutex);
    thr->state = THREAD_STATE_RUNNING;
    pthread_cond_signal(&thr->state_event);
    mt_unlockmutex(&thr->state_mutex);
}

void* thread_func(void* param)
{
    result_t r;
    struct thread* thr = param;
    
    ASSERT(thr->kernel_fn != NULL);
    
    /* init */
    if (thr->init_fn != NULL)   {
        r = thr->init_fn(thr);
        if (IS_FAIL(r))     {
            goto cleanup;
        }
    }
    
    /* kernel */
    while (TRUE)  {
        r = thr->kernel_fn(thr);
        if (r == RET_ABORT)  {
            goto cleanup;
        }
        
        mt_lockmutex(&thr->state_mutex);
        if (thr->state != THREAD_STATE_RUNNING)     {
            if (thr->state == THREAD_STATE_STOP)    {
                mt_unlockmutex(&thr->state_mutex);
                goto cleanup;
            }

            pthread_cond_wait(&thr->state_event, &thr->state_mutex);
        }
        mt_unlockmutex(&thr->state_mutex);
    }
    
cleanup:
    /* release */
    if (thr->release_fn != NULL)
        thr->release_fn(thr);
    pthread_exit(NULL);
}

#else
/* thread callback */
uint32 __stdcall thread_func(void* param);

#define STOP_EVENT      0
#define RESUME_EVENT    1

struct thread* mt_createthread(
    pfn_thread_kernel kernel_fn, pfn_thread_init init_fn, pfn_thread_release release_fn, 
    enum thread_level level, uint32 local_mem_sz, void* param1, void* param2)
{
    static uint32 count = 0;
    result_t r;
    struct thread* thr = ALLOC(sizeof(struct thread), 0);
    if (thr == NULL)    
        return NULL;
    memset(thr, 0x00, sizeof(struct thread));

    if (local_mem_sz > 0)   {
        r = mem_freelist_create(mem_heap(), &thr->local_mem, local_mem_sz, 0);
        if (IS_FAIL(r)) {
            FREE(thr);
            return NULL;
        }
        mem_freelist_bindalloc(&thr->local_mem, &thr->local_alloc);
    }

    thr->kernel_fn = kernel_fn;
    thr->init_fn = init_fn;
    thr->release_fn = release_fn;
    thr->param1 = param1;
    thr->param2 = param2;
    thr->level = level;

    char e1name[32];
    char e2name[32];
    sprintf(e1name, "stop:t(%d)", count);
    sprintf(e2name, "resume:t(%d)", count);
    count++;

    thr->events[STOP_EVENT] = CreateEvent(NULL, TRUE, FALSE, e1name);
    thr->events[RESUME_EVENT] = CreateEvent(NULL, TRUE, TRUE, e2name);

    if (thr->events[STOP_EVENT] == NULL || thr->events[RESUME_EVENT] == NULL)
        return NULL;

    uptr_t t = _beginthreadex(NULL, 0, thread_func, thr, 0, &thr->id);
    if (t == 0) {
        mt_destroythread(thr);
        return NULL;
    }

    thr->t = (thread_t)t;

    switch (level)   {
    case THREAD_LEVEL_NORMAL:    SetThreadPriority(thr->t, THREAD_PRIORITY_NORMAL);    break;
    case THREAD_LEVEL_HIGH:      SetThreadPriority(thr->t, THREAD_PRIORITY_HIGHEST);   break;
    case THREAD_LEVEL_LOW:       SetThreadPriority(thr->t, THREAD_PRIORITY_LOWEST);    break;
    }

    return thr;
}

void mt_destroythread(struct thread* thr)
{
   /* reset events */
   if (thr->events[RESUME_EVENT] != NULL)    {
       ResetEvent(thr->events[RESUME_EVENT]);
   }

   if (thr->events[STOP_EVENT] != NULL) {
       SetEvent(thr->events[STOP_EVENT]);
   }

   /* wait for thread to finish */
   if (thr->t != THREAD_NULL)  {
       WaitForSingleObject(thr->t, INFINITE);
       CloseHandle(thr->t);
   }

    if (thr->events[RESUME_EVENT] != NULL)  {
        CloseHandle(thr->events[RESUME_EVENT]);
    }

    if (thr->events[STOP_EVENT] != NULL)    {
        CloseHandle(thr->events[STOP_EVENT]);
    }

    mem_freelist_destroy(&thr->local_mem);
    FREE(thr);
}

void mt_pausethread(struct thread* thr)
{
    ResetEvent(thr->events[RESUME_EVENT]);
}

void mt_resumethread(struct thread* thr)
{
    SetEvent(thr->events[RESUME_EVENT]);
}

void mt_stopthread(struct thread* thr)
{
    SetEvent(thr->events[STOP_EVENT]);
}


uint32 __stdcall thread_func(void* param)
{
    result_t r;
    struct thread* thr = param;

    if (thr->init_fn != NULL)   {
        r = thr->init_fn(param);
        if (IS_FAIL(r)) {
            _endthreadex(-1);
            return -1;
        }
    }

    while (WaitForMultipleObjects(2, thr->events, FALSE, UINT32_MAX) != 
           (WAIT_OBJECT_0 + STOP_EVENT))    
    {
        r = thr->kernel_fn(param);
        if (IS_FAIL(r)) {
            goto cleanup;
        }
    }

cleanup:
    if (thr->release_fn != NULL)    {
        thr->release_fn(param);
    }

    _endthreadex(0);
    return 0;
}

#endif
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.