summaryrefslogtreecommitdiffstats
path: root/libdash/source/portable/MultiThreading.cpp
blob: 5d1fe9c0498106d1904c29ad3e374001806c6d84 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
#include "MultiThreading.h"

THREAD_HANDLE   CreateThreadPortable    (void *(*start_routine) (void *), void *arg)
{
    #if defined _WIN32 || defined _WIN64
        return CreateThread (0, 0, (LPTHREAD_START_ROUTINE)start_routine, (LPVOID)arg, 0, 0);
    #else
        THREAD_HANDLE th = (THREAD_HANDLE)malloc(sizeof(pthread_t));

        if (!th)
        {
            std::cerr << "Error allocating thread." << std::endl;
            return NULL;
        }

        pthread_attr_t attr;
        pthread_attr_init(&attr);
        pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

        if(int err = pthread_create(th, &attr, start_routine, arg))
        {
            std::cerr << strerror(err) << std::endl;
            return NULL;
        }
        return th;
    #endif
}
void            DestroyThreadPortable   (THREAD_HANDLE th)
{
    #if !defined _WIN32 && !defined _WIN64
        if(th)
            free(th);
    #endif
}

/****************************************************************************
* Condition variables for Windows XP and older windows sytems
*****************************************************************************/
#if defined WINXPOROLDER
    void InitCondition       (condition_variable_t *cv)
    {
        InitializeCriticalSection(&cv->waitersCountLock);

        cv->waitersCount        = 0;
        cv->waitGenerationCount = 0;
        cv->releaseCount        = 0;

        cv->waitingEvent = CreateEvent (NULL,  // no security
                                        TRUE,  // manual-reset
                                        FALSE, // non-signaled initially
                                        NULL); // unnamed
    }
    void WaitCondition       (condition_variable_t *cv, CRITICAL_SECTION *externalMutex)
    {
        EnterCriticalSection(&cv->waitersCountLock);

        cv->waitersCount++;

        int currentGenerationCount = cv->waitGenerationCount;

        LeaveCriticalSection(&cv->waitersCountLock);
        LeaveCriticalSection(externalMutex);

        bool isWaitDone = false;
        while(!isWaitDone)
        {
            WaitForSingleObject (cv->waitingEvent, INFINITE);
            EnterCriticalSection (&cv->waitersCountLock);

            isWaitDone = (cv->releaseCount > 0 && cv->waitGenerationCount != currentGenerationCount);
            LeaveCriticalSection (&cv->waitersCountLock);
        }

        EnterCriticalSection(externalMutex);
        EnterCriticalSection(&cv->waitersCountLock);

        cv->waitersCount--;
        cv->releaseCount--;
        bool isLastWaiter = (cv->releaseCount == 0);

        LeaveCriticalSection(&cv->waitersCountLock);

        if(isLastWaiter)
            ResetEvent(cv->waitingEvent);
    }
    void SignalCondition     (condition_variable_t *cv)
    {
        EnterCriticalSection(&cv->waitersCountLock);

        if(cv->waitersCount > cv->releaseCount) 
        {
            SetEvent(cv->waitingEvent);
            cv->releaseCount++;
            cv->waitGenerationCount++;
        }

        LeaveCriticalSection(&cv->waitersCountLock);
    }
    void BroadcastCondition  (condition_variable_t *cv)
    {
        EnterCriticalSection(&cv->waitersCountLock);

        if(cv->waitersCount > 0) 
        {
            SetEvent(cv->waitingEvent);
            cv->releaseCount = cv->waitersCount;
            cv->waitGenerationCount++;
        }

        LeaveCriticalSection(&cv->waitersCountLock);
}
#endif