History

player: add threaded decoder WIP

lieff committed 8 years ago

Commit 29f6dca1 parent f3efc076 files · +717 −2Browse files

Showing the changes to player/system.cpp (1 of 6 files). Show all

Unified · Split

player/system.cpp+473−0
@@ -0,0 +1,473 @@
1#include "system.h"
2
3#ifndef _WIN32
4
5#include <stdlib.h>
6#include <time.h>
7#include <errno.h>
8#include <unistd.h>
9#if defined(__linux) || defined(__linux__)
10#include <sys/prctl.h>
11#endif
12
13#define nullptr 0
14
15struct Event
16{
17 Event * volatile pMultipleCond;
18 pthread_mutex_t mutex;
19 pthread_cond_t cond;
20 volatile bool signaled;
21 bool manual_reset;
22};
23
24static bool InitEvent(Event *e)
25{
26#if (defined(ANDROID) && !defined(__LP64__)) || defined(__APPLE__)
27 if (pthread_cond_init(&e->cond, NULL))
28 return false;
29#else
30 pthread_condattr_t attr;
31 if (pthread_condattr_init(&attr))
32 return false;
33 if (pthread_condattr_setclock(&attr, CLOCK_MONOTONIC))
34 {
35 pthread_condattr_destroy(&attr);
36 return false;
37 }
38 if (pthread_cond_init(&e->cond, &attr))
39 {
40 pthread_condattr_destroy(&attr);
41 return false;
42 }
43 pthread_condattr_destroy(&attr);
44#endif
45 if (pthread_mutex_init(&e->mutex, NULL))
46 {
47 pthread_cond_destroy(&e->cond);
48 return false;
49 }
50 e->pMultipleCond = NULL;
51 return true;
52}
53
54#ifdef __APPLE__
55#include <mach/mach_time.h>
56static inline uint64_t GetAbsTimeInNanoseconds()
57{
58 static mach_timebase_info_data_t g_timebase_info;
59 if (g_timebase_info.denom == 0)
60 mach_timebase_info(&g_timebase_info);
61 return mach_absolute_time()*g_timebase_info.numer/g_timebase_info.denom;
62}
63#endif
64
65static inline void GetAbsTime(timespec *ts, uint32_t timeout)
66{
67#if defined(__APPLE__)
68 uint64_t cur_time = GetAbsTimeInNanoseconds();
69 ts->tv_sec = cur_time/1000000000u + timeout/1000u;
70 ts->tv_nsec = (cur_time % 1000000000u) + (timeout % 1000u)*1000000u;
71#else
72 clock_gettime(CLOCK_MONOTONIC, ts);
73 ts->tv_sec += timeout/1000u;
74 ts->tv_nsec += (timeout % 1000u)*1000000u;
75#endif
76 if (ts->tv_nsec >= 1000000000)
77 {
78 ts->tv_nsec -= 1000000000;
79 ts->tv_sec++;
80 }
81}
82
83static inline int CondTimedWait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime)
84{
85#if defined(ANDROID) && !defined(__LP64__)
86 return pthread_cond_timedwait_monotonic_np(cond, mutex, abstime);
87#elif defined(__APPLE__)
88 timespec reltime;
89 uint64_t cur_time = GetAbsTimeInNanoseconds();
90 reltime.tv_sec = abstime->tv_sec - cur_time/1000000000u;
91 reltime.tv_nsec = abstime->tv_nsec - (cur_time % 1000000000u);
92 if (reltime.tv_nsec < 0)
93 {
94 reltime.tv_nsec += 1000000000;
95 reltime.tv_sec--;
96 }
97 if ((reltime.tv_sec < 0) || ((reltime.tv_sec == 0) && (reltime.tv_nsec == 0)))
98 return ETIMEDOUT;
99 return pthread_cond_timedwait_relative_np(cond, mutex, &reltime);
100#else
101 return pthread_cond_timedwait(cond, mutex, abstime);
102#endif
103}
104
105static bool WaitForEvent(Event *e, uint32_t timeout, bool *signaled)
106{
107 if (pthread_mutex_lock(&e->mutex))
108 return false;
109
110 if (timeout == INFINITE)
111 {
112 while (!e->signaled)
113 pthread_cond_wait(&e->cond, &e->mutex);
114 } else if (timeout != 0)
115 {
116 timespec t;
117 GetAbsTime(&t, timeout);
118 while (!e->signaled)
119 {
120 if (CondTimedWait(&e->cond, &e->mutex, &t))
121 break;
122 }
123 }
124 *signaled = e->signaled;
125 if (!e->manual_reset)
126 e->signaled = false;
127
128 if (pthread_mutex_unlock(&e->mutex))
129 return false;
130 return true;
131}
132
133static bool WaitForMultipleEvents(Event **e, uint32_t count, uint32_t timeout, bool waitAll, int *signaled_num)
134{
135 uint32_t i;
136#define PTHR(func, num) for (i = num; i < count; i++)\
137 if (func(&e[i]->mutex))\
138 return false;
139 PTHR(pthread_mutex_lock, 0);
140
141 int sig_num = -1;
142 if (timeout == 0)
143 {
144#define CHECK_SIGNALED \
145 if (waitAll)\
146 {\
147 for (i = 0; i < count; i++)\
148 if (!e[i]->signaled)\
149 break;\
150 if (i == count)\
151 for (i = 0; i < count; i++)\
152 {\
153 if (sig_num < 0 && e[i]->signaled)\
154 sig_num = (int)i;\
155 if (!e[i]->manual_reset)\
156 e[i]->signaled = false;\
157 }\
158 } else\
159 {\
160 for (i = 0; i < count; i++)\
161 if (e[i]->signaled)\
162 {\
163 sig_num = (int)i;\
164 if (!e[i]->manual_reset)\
165 e[i]->signaled = false;\
166 break;\
167 }\
168 }
169 CHECK_SIGNALED;
170 } else
171 if (timeout == INFINITE)
172 {
173#define SET_MULTIPLE(val) for (i = 1; i < count; i++)\
174 e[i]->pMultipleCond = val;
175 SET_MULTIPLE(e[0]);
176 for (;;)
177 {
178 CHECK_SIGNALED;
179 if (sig_num >= 0)
180 break;
181 PTHR(pthread_mutex_unlock, 1);
182 pthread_cond_wait(&e[0]->cond, &e[0]->mutex);
183 PTHR(pthread_mutex_lock, 1);
184 }
185 SET_MULTIPLE(0);
186 } else
187 {
188 SET_MULTIPLE(e[0]);
189 timespec t;
190 GetAbsTime(&t, timeout);
191 for (;;)
192 {
193 CHECK_SIGNALED;
194 if (sig_num >= 0)
195 break;
196 PTHR(pthread_mutex_unlock, 1);
197 int res = CondTimedWait(&e[0]->cond, &e[0]->mutex, &t);
198 PTHR(pthread_mutex_lock, 1);
199 if (res)
200 break;
201 }
202 SET_MULTIPLE(0);
203 }
204 PTHR(pthread_mutex_unlock, 0);
205 *signaled_num = sig_num;
206 return true;
207}
208
209static bool SignalEvent(Event *e)
210{
211 if (pthread_mutex_lock(&e->mutex))
212 return false;
213
214 Event *pMultipleCond = e->pMultipleCond;
215 e->signaled = true;
216 if (pthread_cond_signal(&e->cond))
217 return false;
218
219 if (pthread_mutex_unlock(&e->mutex))
220 return false;
221
222 if (pMultipleCond && pMultipleCond != e)
223 {
224 if (pthread_mutex_lock(&pMultipleCond->mutex))
225 return false;
226 if (pthread_cond_signal(&pMultipleCond->cond))
227 return false;
228 if (pthread_mutex_unlock(&pMultipleCond->mutex))
229 return false;
230 }
231 return true;
232}
233
234static bool ResetEvent(Event *e)
235{
236 if (pthread_mutex_lock(&e->mutex))
237 return false;
238 e->signaled = false;
239 if (pthread_mutex_unlock(&e->mutex))
240 return false;
241 return true;
242}
243
244HANDLE event_create(bool manualReset, bool initialState)
245{
246 Event *e = (Event *)malloc(sizeof(*e));
247 if (!e)
248 return NULL;
249 if (!InitEvent(e))
250 {
251 free(e);
252 return NULL;
253 }
254 e->manual_reset = manualReset;
255 e->signaled = initialState;
256 return (HANDLE)e;
257}
258
259bool event_destroy(HANDLE event)
260{
261 Event *e = (Event *)event;
262 if (!e)
263 return false;
264 if (pthread_cond_destroy(&e->cond))
265 return false;
266 if (pthread_mutex_destroy(&e->mutex))
267 return false;
268 free((void *)e);
269 return true;
270}
271
272bool event_set(HANDLE event)
273{
274 return SignalEvent((Event *)event);
275}
276
277bool event_reset(HANDLE event)
278{
279 return ResetEvent((Event *)event);
280}
281
282int event_wait(HANDLE event, uint32_t milliseconds)
283{
284 bool signaled;
285 if (!WaitForEvent((Event *)event, milliseconds, &signaled))
286 return WAIT_FAILED;
287 return signaled ? WAIT_OBJECT : WAIT_TIMEOUT;
288}
289
290int event_wait_multiple(uint32_t count, const HANDLE *events, bool waitAll, uint32_t milliseconds)
291{
292 if (count == 1)
293 return event_wait(events[0], milliseconds);
294 int signaled_num = -1;
295 if (!WaitForMultipleEvents((Event **)events, count, milliseconds, waitAll, &signaled_num))
296 return WAIT_FAILED;
297 return (signaled_num < 0) ? WAIT_TIMEOUT : (WAIT_OBJECT_0 + signaled_num);
298}
299
300bool InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection)
301{
302 pthread_mutexattr_t ma;
303 if (pthread_mutexattr_init(&ma))
304 return false;
305 if (pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_RECURSIVE))
306 {
307 pthread_mutexattr_destroy(&ma);
308 return false;
309 }
310 if (pthread_mutex_init((pthread_mutex_t *)lpCriticalSection, &ma))
311 {
312 pthread_mutexattr_destroy(&ma);
313 return false;
314 }
315 if (pthread_mutexattr_destroy(&ma))
316 return false;
317 return true;
318}
319
320bool DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection)
321{
322 if (pthread_mutex_destroy((pthread_mutex_t *)lpCriticalSection))
323 return false;
324 return true;
325}
326
327bool EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection)
328{
329 if (pthread_mutex_lock((pthread_mutex_t *)lpCriticalSection))
330 return false;
331 return true;
332}
333
334bool LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection)
335{
336 if (pthread_mutex_unlock((pthread_mutex_t *)lpCriticalSection))
337 return false;
338 return true;
339}
340
341HANDLE thread_create(LPTHREAD_START_ROUTINE lpStartAddress, void *lpParameter)
342{
343 pthread_t *t = (pthread_t *)malloc(sizeof(*t));
344 if (!t)
345 return nullptr;
346 if (pthread_create(t, 0, lpStartAddress, lpParameter))
347 {
348 free(t);
349 return nullptr;
350 }
351 //if (lpThreadId)
352 // *lpThreadId = (uint32_t)*t;
353 return (HANDLE)t;
354}
355
356bool thread_close(HANDLE thread)
357{
358 if (!thread)
359 return false;
360 pthread_t *t = (pthread_t *)thread;
361 if (*t)
362 pthread_detach(*t);
363 free(t);
364 return true;
365}
366
367void *thread_wait(HANDLE thread)
368{
369 if (!thread)
370 return (void*)-1;
371 void *ret = 0;
372 pthread_t *t = (pthread_t *)thread;
373 if (!*t)
374 return ret;
375 int res = pthread_join(*t, &ret);
376 if (res)
377 return (void*)-1;
378#if 0
379 if (timeout == 0)
380 {
381 int res = pthread_tryjoin_np(*t, &ret);
382 if (res)
383 return false;
384 } else
385 if (timeout == INFINITE)
386 {
387 int res = pthread_join(*t, &ret);
388 if (res)
389 return false;
390 } else
391 {
392 timespec ts;
393 GetAbsTime(&ts, timeout);
394 int res = pthread_timedjoin_np(*t, &ret, &ts);
395 if (res)
396 return false;
397 }
398#endif
399 *t = 0; // thread joined - no need to detach
400 return ret;
401}
402
403#else //_WIN32
404
405bool event_destroy(HANDLE event)
406{
407 CloseHandle(event);
408 return true;
409}
410
411bool thread_close(HANDLE thread)
412{
413 CloseHandle(thread);
414 return true;
415}
416
417bool thread_wait(HANDLE thread)
418{
419 return WaitForSingleObject(thread, INFINITE) == WAIT_OBJECT_0;
420}
421
422#endif //_WIN32
423
424bool thread_name(const char *name)
425{
426#ifdef _WIN32
427 struct tagTHREADNAME_INFO
428 {
429 DWORD dwType;
430 LPCSTR szName;
431 DWORD dwThreadID;
432 DWORD dwFlags;
433 } info = { 0x1000, name, (DWORD)-1, 0 };
434 __try
435 {
436 RaiseException(0x406D1388, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info);
437 }
438 __except(EXCEPTION_EXECUTE_HANDLER)
439 {
440 }
441 return true;
442#elif defined(__linux) || defined(__linux__)
443 return (0 == prctl(PR_SET_NAME, name, 0, 0, 0));
444 //return (0 == pthread_setname_np(pthread_self(), name));
445#else // macos, ios
446 return (0 == pthread_setname_np(name));
447#endif
448}
449
450bool thread_sleep(uint32_t milliseconds)
451{
452#ifdef _WIN32
453 Sleep(milliseconds);
454#else
455 usleep((useconds_t)milliseconds*1000);
456#endif
457}
458
459uint64_t GetTime()
460{
461 uint64_t time;
462#ifdef _WIN32
463 QueryPerformanceCounter((LARGE_INTEGER*)&time);
464#elif defined(__APPLE__)
465 time = GetAbsTimeInNanoseconds() / 1000u;
466#else
467 timespec ts;
468 // CLOCK_PROCESS_CPUTIME_ID CLOCK_THREAD_CPUTIME_ID
469 clock_gettime(CLOCK_MONOTONIC, &ts);
470 time = (uint64_t)ts.tv_sec * 1000000u + ts.tv_nsec / 1000u;
471#endif
472 return time;
473}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t