source: trunk/src/sys/threadbase.h @ 2238

Last change on this file since 2238 was 2238, checked in by sam, 7 years ago

sys: move thread.h to the sys/ directory.

  • Property svn:keywords set to Id
File size: 5.4 KB
Line 
1//
2// Lol Engine
3//
4// Copyright: (c) 2010-2013 Sam Hocevar <sam@hocevar.net>
5//   This program is free software; you can redistribute it and/or
6//   modify it under the terms of the Do What The Fuck You Want To
7//   Public License, Version 2, as published by Sam Hocevar. See
8//   http://www.wtfpl.net/ for more details.
9//
10
11//
12// The ThreadBase class
13// --------------------
14//
15
16#if !defined __LOL_THREADBASE_H__
17#define __LOL_THREADBASE_H__
18
19#if defined HAVE_PTHREAD_H
20#   include <pthread.h>
21#elif defined _XBOX
22#   include <xtl.h>
23#   undef near /* Fuck Microsoft */
24#   undef far /* Fuck Microsoft again */
25#elif defined _WIN32
26#   include <windows.h>
27#   undef near /* Fuck Microsoft */
28#   undef far /* Fuck Microsoft again */
29#else
30#   error No threading support yet :(
31#endif
32
33namespace lol
34{
35
36class MutexBase
37{
38public:
39    MutexBase()
40    {
41#if defined HAVE_PTHREAD_H
42        pthread_mutex_init(&m_mutex, NULL);
43#elif defined _WIN32
44        InitializeCriticalSection(&m_mutex);
45#endif
46    }
47
48    ~MutexBase()
49    {
50#if defined HAVE_PTHREAD_H
51        pthread_mutex_destroy(&m_mutex);
52#elif defined _WIN32
53        DeleteCriticalSection(&m_mutex);
54#endif
55    }
56
57    void Lock()
58    {
59#if defined HAVE_PTHREAD_H
60        pthread_mutex_lock(&m_mutex);
61#elif defined _WIN32
62        EnterCriticalSection(&m_mutex);
63#endif
64    }
65
66    void Unlock()
67    {
68#if defined HAVE_PTHREAD_H
69        pthread_mutex_unlock(&m_mutex);
70#elif defined _WIN32
71        LeaveCriticalSection(&m_mutex);
72#endif
73    }
74
75private:
76#if defined HAVE_PTHREAD_H
77    pthread_mutex_t m_mutex;
78#elif defined _WIN32
79    CRITICAL_SECTION m_mutex;
80#endif
81};
82
83template<typename T, int N> class QueueBase
84{
85public:
86    QueueBase()
87    {
88        m_start = m_count = 0;
89#if defined HAVE_PTHREAD_H
90        m_poppers = m_pushers = 0;
91        pthread_mutex_init(&m_mutex, NULL);
92        pthread_cond_init(&m_empty_cond, NULL);
93        pthread_cond_init(&m_full_cond, NULL);
94#elif defined _WIN32
95        m_empty_sem = CreateSemaphore(NULL, CAPACITY, CAPACITY, NULL);
96        m_full_sem = CreateSemaphore(NULL, 0, CAPACITY, NULL);
97        InitializeCriticalSection(&m_mutex);
98#endif
99    }
100
101    ~QueueBase()
102    {
103#if defined HAVE_PTHREAD_H
104        pthread_cond_destroy(&m_empty_cond);
105        pthread_cond_destroy(&m_full_cond);
106        pthread_mutex_destroy(&m_mutex);
107#elif defined _WIN32
108        CloseHandle(m_empty_sem);
109        CloseHandle(m_full_sem);
110        DeleteCriticalSection(&m_mutex);
111#endif
112    }
113
114    void Push(T value)
115    {
116#if defined HAVE_PTHREAD_H
117        pthread_mutex_lock(&m_mutex);
118        /* If queue is full, wait on the "full" cond var. */
119        m_pushers++;
120        while (m_count == CAPACITY)
121            pthread_cond_wait(&m_full_cond, &m_mutex);
122        m_pushers--;
123#elif defined _WIN32
124        WaitForSingleObject(m_empty_sem, INFINITE);
125        EnterCriticalSection(&m_mutex);
126#endif
127
128        /* Push value */
129        m_values[(m_start + m_count) % CAPACITY] = value;
130        m_count++;
131
132#if defined HAVE_PTHREAD_H
133        /* If there were poppers waiting, signal the "empty" cond var. */
134        if (m_poppers)
135            pthread_cond_signal(&m_empty_cond);
136        pthread_mutex_unlock(&m_mutex);
137#elif defined _WIN32
138        LeaveCriticalSection(&m_mutex);
139        ReleaseSemaphore(m_full_sem, 1, NULL);
140#endif
141    }
142
143    T Pop()
144    {
145#if defined HAVE_PTHREAD_H
146        pthread_mutex_lock(&m_mutex);
147        /* Wait until there is something in the queue. Be careful, we
148         * could get woken up but another thread may have eaten the
149         * message in the meantime. */
150        m_poppers++;
151        while (m_count == 0)
152            pthread_cond_wait(&m_empty_cond, &m_mutex);
153        m_poppers--;
154#elif defined _WIN32
155        WaitForSingleObject(m_full_sem, INFINITE);
156        EnterCriticalSection(&m_mutex);
157#endif
158
159        /* Pop value */
160        T ret = m_values[m_start];
161        m_start = (m_start + 1) % CAPACITY;
162        m_count--;
163
164#if defined HAVE_PTHREAD_H
165        /* If there were pushers waiting, signal the "full" cond var. */
166        if (m_pushers)
167            pthread_cond_signal(&m_full_cond);
168        pthread_mutex_unlock(&m_mutex);
169#else
170        LeaveCriticalSection(&m_mutex);
171        ReleaseSemaphore(m_empty_sem, 1, NULL);
172#endif
173
174        return ret;
175    }
176
177private:
178    static size_t const CAPACITY = N;
179    T m_values[CAPACITY];
180    size_t m_start, m_count;
181#if defined HAVE_PTHREAD_H
182    size_t m_poppers, m_pushers;
183    pthread_mutex_t m_mutex;
184    pthread_cond_t m_empty_cond, m_full_cond;
185#elif defined _WIN32
186    HANDLE m_empty_sem, m_full_sem;
187    CRITICAL_SECTION m_mutex;
188#endif
189};
190
191class ThreadBase
192{
193public:
194    ThreadBase(void *(*fn)(void *), void *data)
195    {
196#if defined HAVE_PTHREAD_H
197        /* Set the joinable attribute for systems who don't play nice */
198        pthread_attr_t attr;
199        pthread_attr_init(&attr);
200        pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
201        pthread_create(&m_thread, &attr, fn, data);
202#elif defined _WIN32
203        m_thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)fn,
204                                data, 0, &m_tid);
205#endif
206    }
207
208    virtual ~ThreadBase()
209    {
210#if defined HAVE_PTHREAD_H
211        pthread_join(m_thread, NULL);
212#elif defined _WIN32
213        WaitForSingleObject(m_thread, INFINITE);
214#endif
215    }
216
217private:
218#if defined HAVE_PTHREAD_H
219    pthread_t m_thread;
220#elif defined _WIN32
221    HANDLE m_thread;
222    DWORD m_tid;
223#endif
224};
225
226} /* namespace lol */
227
228#endif // __LOL_THREADBASE_H__
229
Note: See TracBrowser for help on using the repository browser.