Fixed a crash caused by yadif deinterlacer on Windows XP
[vlc/solaris.git] / src / os2 / thread.c
blob3f0865828fa5bf8890b47b4c6d9cbd539a83a89f
1 /*****************************************************************************
2 * thread.c : OS/2 back-end for LibVLC
3 *****************************************************************************
4 * Copyright (C) 1999-2011 VLC authors and VideoLAN
6 * Authors: KO Myung-Hun <komh@chollian.net>
7 * Jean-Marc Dressler <polux@via.ecp.fr>
8 * Samuel Hocevar <sam@zoy.org>
9 * Gildas Bazin <gbazin@netcourrier.com>
10 * Clément Sténac
11 * Rémi Denis-Courmont
12 * Pierre Ynard
14 * This program is free software; you can redistribute it and/or modify it
15 * under the terms of the GNU Lesser General Public License as published by
16 * the Free Software Foundation; either version 2.1 of the License, or
17 * (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU Lesser General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public License
25 * along with this program; if not, write to the Free Software Foundation,
26 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
27 *****************************************************************************/
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
33 #include <vlc_common.h>
35 #include "libvlc.h"
36 #include <stdarg.h>
37 #include <assert.h>
38 #include <limits.h>
39 #include <errno.h>
40 #include <time.h>
42 static vlc_threadvar_t thread_key;
44 /**
45 * Per-thread data
47 struct vlc_thread
49 TID tid;
50 HEV cancel_event;
51 HEV done_event;
53 bool detached;
54 bool killable;
55 bool killed;
56 vlc_cleanup_t *cleaners;
58 void *(*entry) (void *);
59 void *data;
62 static void vlc_cancel_self (PVOID dummy);
64 static ULONG vlc_DosWaitEventSemEx( HEV hev, ULONG ulTimeout, BOOL fCancelable )
66 HMUX hmux;
67 SEMRECORD asr[ 2 ];
68 ULONG ulUser;
69 int n;
70 ULONG rc;
72 struct vlc_thread *th = vlc_threadvar_get( thread_key );
73 if( th == NULL || !fCancelable )
75 /* Main thread - cannot be cancelled anyway
76 * Alien thread - out of our control
78 if( hev != NULLHANDLE )
79 return DosWaitEventSem( hev, ulTimeout );
81 return DosSleep( ulTimeout );
84 n = 0;
85 if( hev != NULLHANDLE )
87 asr[ n ].hsemCur = ( HSEM )hev;
88 asr[ n ].ulUser = 0;
89 n++;
91 asr[ n ].hsemCur = ( HSEM )th->cancel_event;
92 asr[ n ].ulUser = 0xFFFF;
93 n++;
95 DosCreateMuxWaitSem( NULL, &hmux, n, asr, DCMW_WAIT_ANY );
96 rc = DosWaitMuxWaitSem( hmux, ulTimeout, &ulUser );
97 DosCloseMuxWaitSem( hmux );
98 if( rc )
99 return rc;
101 if( ulUser == 0xFFFF )
103 vlc_cancel_self( th );
104 return ERROR_INTERRUPT;
107 return NO_ERROR;
110 static ULONG vlc_WaitForSingleObject (HEV hev, ULONG ulTimeout)
112 return vlc_DosWaitEventSemEx( hev, ulTimeout, TRUE );
115 static ULONG vlc_Sleep (ULONG ulTimeout)
117 ULONG rc = vlc_DosWaitEventSemEx( NULLHANDLE, ulTimeout, TRUE );
119 return ( rc != ERROR_TIMEOUT ) ? rc : 0;
122 vlc_mutex_t super_mutex;
123 vlc_cond_t super_variable;
124 extern vlc_rwlock_t config_lock, msg_lock;
126 int _CRT_init(void);
127 void _CRT_term(void);
129 unsigned long _System _DLL_InitTerm(unsigned long, unsigned long);
131 unsigned long _System _DLL_InitTerm(unsigned long hmod, unsigned long flag)
133 VLC_UNUSED (hmod);
135 switch (flag)
137 case 0 : /* Initialization */
138 if(_CRT_init() == -1)
139 return 0;
141 vlc_mutex_init (&super_mutex);
142 vlc_cond_init (&super_variable);
143 vlc_threadvar_create (&thread_key, NULL);
144 vlc_rwlock_init (&config_lock);
145 vlc_rwlock_init (&msg_lock);
146 vlc_CPU_init ();
148 return 1;
150 case 1 : /* Termination */
151 vlc_rwlock_destroy (&msg_lock);
152 vlc_rwlock_destroy (&config_lock);
153 vlc_threadvar_delete (&thread_key);
154 vlc_cond_destroy (&super_variable);
155 vlc_mutex_destroy (&super_mutex);
157 _CRT_term();
159 return 1;
162 return 0; /* Failed */
165 /*** Mutexes ***/
166 void vlc_mutex_init( vlc_mutex_t *p_mutex )
168 /* This creates a recursive mutex. This is OK as fast mutexes have
169 * no defined behavior in case of recursive locking. */
170 DosCreateMutexSem( NULL, &p_mutex->hmtx, 0, FALSE );
171 p_mutex->dynamic = true;
174 void vlc_mutex_init_recursive( vlc_mutex_t *p_mutex )
176 DosCreateMutexSem( NULL, &p_mutex->hmtx, 0, FALSE );
177 p_mutex->dynamic = true;
181 void vlc_mutex_destroy (vlc_mutex_t *p_mutex)
183 assert (p_mutex->dynamic);
184 DosCloseMutexSem( p_mutex->hmtx );
187 void vlc_mutex_lock (vlc_mutex_t *p_mutex)
189 if (!p_mutex->dynamic)
190 { /* static mutexes */
191 int canc = vlc_savecancel ();
192 assert (p_mutex != &super_mutex); /* this one cannot be static */
194 vlc_mutex_lock (&super_mutex);
195 while (p_mutex->locked)
197 p_mutex->contention++;
198 vlc_cond_wait (&super_variable, &super_mutex);
199 p_mutex->contention--;
201 p_mutex->locked = true;
202 vlc_mutex_unlock (&super_mutex);
203 vlc_restorecancel (canc);
204 return;
207 DosRequestMutexSem(p_mutex->hmtx, SEM_INDEFINITE_WAIT);
210 int vlc_mutex_trylock (vlc_mutex_t *p_mutex)
212 if (!p_mutex->dynamic)
213 { /* static mutexes */
214 int ret = EBUSY;
216 assert (p_mutex != &super_mutex); /* this one cannot be static */
217 vlc_mutex_lock (&super_mutex);
218 if (!p_mutex->locked)
220 p_mutex->locked = true;
221 ret = 0;
223 vlc_mutex_unlock (&super_mutex);
224 return ret;
227 return DosRequestMutexSem( p_mutex->hmtx, 0 ) ? EBUSY : 0;
230 void vlc_mutex_unlock (vlc_mutex_t *p_mutex)
232 if (!p_mutex->dynamic)
233 { /* static mutexes */
234 assert (p_mutex != &super_mutex); /* this one cannot be static */
236 vlc_mutex_lock (&super_mutex);
237 assert (p_mutex->locked);
238 p_mutex->locked = false;
239 if (p_mutex->contention)
240 vlc_cond_broadcast (&super_variable);
241 vlc_mutex_unlock (&super_mutex);
242 return;
245 DosReleaseMutexSem( p_mutex->hmtx );
248 /*** Condition variables ***/
249 enum
251 CLOCK_REALTIME=0, /* must be zero for VLC_STATIC_COND */
252 CLOCK_MONOTONIC,
255 static void vlc_cond_init_common (vlc_cond_t *p_condvar, unsigned clock)
257 /* Create a manual-reset event (manual reset is needed for broadcast). */
258 if (DosCreateEventSem (NULL, &p_condvar->hev, 0, FALSE))
259 abort();
260 p_condvar->clock = clock;
263 void vlc_cond_init (vlc_cond_t *p_condvar)
265 vlc_cond_init_common (p_condvar, CLOCK_MONOTONIC);
268 void vlc_cond_init_daytime (vlc_cond_t *p_condvar)
270 vlc_cond_init_common (p_condvar, CLOCK_REALTIME);
273 void vlc_cond_destroy (vlc_cond_t *p_condvar)
275 DosCloseEventSem( p_condvar->hev );
278 void vlc_cond_signal (vlc_cond_t *p_condvar)
280 if (!p_condvar->hev)
281 return;
283 /* This is suboptimal but works. */
284 vlc_cond_broadcast (p_condvar);
287 void vlc_cond_broadcast (vlc_cond_t *p_condvar)
289 if (!p_condvar->hev)
290 return;
292 /* Wake all threads up (as the event HANDLE has manual reset) */
293 DosPostEventSem( p_condvar->hev );
296 void vlc_cond_wait (vlc_cond_t *p_condvar, vlc_mutex_t *p_mutex)
298 ULONG ulPost;
299 ULONG rc;
301 if (!p_condvar->hev)
302 { /* FIXME FIXME FIXME */
303 msleep (50000);
304 return;
309 vlc_testcancel();
311 vlc_mutex_unlock (p_mutex);
312 rc = vlc_WaitForSingleObject( p_condvar->hev, SEM_INDEFINITE_WAIT );
313 vlc_mutex_lock (p_mutex);
314 } while( rc == ERROR_INTERRUPT );
316 DosResetEventSem( p_condvar->hev, &ulPost );
319 int vlc_cond_timedwait (vlc_cond_t *p_condvar, vlc_mutex_t *p_mutex,
320 mtime_t deadline)
322 ULONG ulTimeout;
323 ULONG ulPost;
324 ULONG rc;
326 if (!p_condvar->hev)
327 { /* FIXME FIXME FIXME */
328 msleep (50000);
329 return;
334 vlc_testcancel();
336 mtime_t total;
337 switch (p_condvar->clock)
339 case CLOCK_REALTIME: /* FIXME? sub-second precision */
340 total = CLOCK_FREQ * time (NULL);
341 break;
342 default:
343 assert (p_condvar->clock == CLOCK_MONOTONIC);
344 total = mdate();
345 break;
347 total = (deadline - total) / 1000;
348 if( total < 0 )
349 total = 0;
351 ulTimeout = ( total > 0x7fffffff ) ? 0x7fffffff : total;
353 vlc_mutex_unlock (p_mutex);
354 rc = vlc_WaitForSingleObject( p_condvar->hev, ulTimeout );
355 vlc_mutex_lock (p_mutex);
356 } while( rc == ERROR_INTERRUPT );
358 DosResetEventSem( p_condvar->hev, &ulPost );
360 return rc ? ETIMEDOUT : 0;
363 /*** Semaphore ***/
364 void vlc_sem_init (vlc_sem_t *sem, unsigned value)
366 if (DosCreateEventSem(NULL, &sem->hev, 0, value > 0 ? TRUE : FALSE))
367 abort ();
369 if (DosCreateMutexSem(NULL, &sem->wait_mutex, 0, FALSE))
370 abort ();
372 if (DosCreateMutexSem(NULL, &sem->count_mutex, 0, FALSE))
373 abort ();
375 sem->count = value;
378 void vlc_sem_destroy (vlc_sem_t *sem)
380 DosCloseEventSem (sem->hev);
381 DosCloseMutexSem (sem->wait_mutex);
382 DosCloseMutexSem (sem->count_mutex);
385 int vlc_sem_post (vlc_sem_t *sem)
387 DosRequestMutexSem(sem->count_mutex, SEM_INDEFINITE_WAIT);
389 if (sem->count < 0x7FFFFFFF)
391 sem->count++;
392 DosPostEventSem(sem->hev);
395 DosReleaseMutexSem(sem->count_mutex);
397 return 0; /* FIXME */
400 void vlc_sem_wait (vlc_sem_t *sem)
402 ULONG rc;
406 vlc_testcancel ();
408 DosRequestMutexSem(sem->wait_mutex, SEM_INDEFINITE_WAIT);
410 rc = vlc_WaitForSingleObject (sem->hev, SEM_INDEFINITE_WAIT );
412 if (!rc)
414 DosRequestMutexSem(sem->count_mutex, SEM_INDEFINITE_WAIT);
416 sem->count--;
417 if (sem->count == 0)
419 ULONG ulPost;
421 DosResetEventSem(sem->hev, &ulPost);
424 DosReleaseMutexSem(sem->count_mutex);
427 DosReleaseMutexSem(sem->wait_mutex);
428 } while (rc == ERROR_INTERRUPT);
431 /*** Read/write locks */
432 void vlc_rwlock_init (vlc_rwlock_t *lock)
434 vlc_mutex_init (&lock->mutex);
435 vlc_cond_init (&lock->wait);
436 lock->readers = 0; /* active readers */
437 lock->writers = 0; /* waiting or active writers */
438 lock->writer = 0; /* ID of active writer */
441 void vlc_rwlock_destroy (vlc_rwlock_t *lock)
443 vlc_cond_destroy (&lock->wait);
444 vlc_mutex_destroy (&lock->mutex);
447 void vlc_rwlock_rdlock (vlc_rwlock_t *lock)
449 vlc_mutex_lock (&lock->mutex);
450 /* Recursive read-locking is allowed. With the infos available:
451 * - the loosest possible condition (no active writer) is:
452 * (lock->writer != 0)
453 * - the strictest possible condition is:
454 * (lock->writer != 0 || (lock->readers == 0 && lock->writers > 0))
455 * or (lock->readers == 0 && (lock->writer != 0 || lock->writers > 0))
457 while (lock->writer != 0)
459 assert (lock->readers == 0);
460 vlc_cond_wait (&lock->wait, &lock->mutex);
462 if (unlikely(lock->readers == ULONG_MAX))
463 abort ();
464 lock->readers++;
465 vlc_mutex_unlock (&lock->mutex);
468 static void vlc_rwlock_rdunlock (vlc_rwlock_t *lock)
470 vlc_mutex_lock (&lock->mutex);
471 assert (lock->readers > 0);
473 /* If there are no readers left, wake up a writer. */
474 if (--lock->readers == 0 && lock->writers > 0)
475 vlc_cond_signal (&lock->wait);
476 vlc_mutex_unlock (&lock->mutex);
479 void vlc_rwlock_wrlock (vlc_rwlock_t *lock)
481 vlc_mutex_lock (&lock->mutex);
482 if (unlikely(lock->writers == ULONG_MAX))
483 abort ();
484 lock->writers++;
485 /* Wait until nobody owns the lock in either way. */
486 while ((lock->readers > 0) || (lock->writer != 0))
487 vlc_cond_wait (&lock->wait, &lock->mutex);
488 lock->writers--;
489 assert (lock->writer == 0);
490 lock->writer = _gettid ();
491 vlc_mutex_unlock (&lock->mutex);
494 static void vlc_rwlock_wrunlock (vlc_rwlock_t *lock)
496 vlc_mutex_lock (&lock->mutex);
497 assert (lock->writer == _gettid ());
498 assert (lock->readers == 0);
499 lock->writer = 0; /* Write unlock */
501 /* Let reader and writer compete. Scheduler decides who wins. */
502 vlc_cond_broadcast (&lock->wait);
503 vlc_mutex_unlock (&lock->mutex);
506 void vlc_rwlock_unlock (vlc_rwlock_t *lock)
508 /* Note: If the lock is held for reading, lock->writer is nul.
509 * If the lock is held for writing, only this thread can store a value to
510 * lock->writer. Either way, lock->writer is safe to fetch here. */
511 if (lock->writer != 0)
512 vlc_rwlock_wrunlock (lock);
513 else
514 vlc_rwlock_rdunlock (lock);
517 /*** Thread-specific variables (TLS) ***/
518 struct vlc_threadvar
520 PULONG id;
521 void (*destroy) (void *);
522 struct vlc_threadvar *prev;
523 struct vlc_threadvar *next;
524 } *vlc_threadvar_last = NULL;
526 int vlc_threadvar_create (vlc_threadvar_t *p_tls, void (*destr) (void *))
528 ULONG rc;
530 struct vlc_threadvar *var = malloc (sizeof (*var));
531 if (unlikely(var == NULL))
532 return errno;
534 rc = DosAllocThreadLocalMemory( 1, &var->id );
535 if( rc )
537 free (var);
538 return ENOMEM;
541 var->destroy = destr;
542 var->next = NULL;
543 *p_tls = var;
545 vlc_mutex_lock (&super_mutex);
546 var->prev = vlc_threadvar_last;
547 vlc_threadvar_last = var;
548 vlc_mutex_unlock (&super_mutex);
549 return 0;
552 void vlc_threadvar_delete (vlc_threadvar_t *p_tls)
554 struct vlc_threadvar *var = *p_tls;
556 vlc_mutex_lock (&super_mutex);
557 if (var->prev != NULL)
558 var->prev->next = var->next;
559 else
560 vlc_threadvar_last = var->next;
561 if (var->next != NULL)
562 var->next->prev = var->prev;
563 vlc_mutex_unlock (&super_mutex);
565 DosFreeThreadLocalMemory( var->id );
566 free (var);
569 int vlc_threadvar_set (vlc_threadvar_t key, void *value)
571 *key->id = ( ULONG )value;
572 return 0;
575 void *vlc_threadvar_get (vlc_threadvar_t key)
577 return ( void * )*key->id;
581 /*** Threads ***/
582 void vlc_threads_setup (libvlc_int_t *p_libvlc)
584 (void) p_libvlc;
587 static void vlc_thread_cleanup (struct vlc_thread *th)
589 vlc_threadvar_t key;
591 retry:
592 /* TODO: use RW lock or something similar */
593 vlc_mutex_lock (&super_mutex);
594 for (key = vlc_threadvar_last; key != NULL; key = key->prev)
596 void *value = vlc_threadvar_get (key);
597 if (value != NULL && key->destroy != NULL)
599 vlc_mutex_unlock (&super_mutex);
600 vlc_threadvar_set (key, NULL);
601 key->destroy (value);
602 goto retry;
605 vlc_mutex_unlock (&super_mutex);
607 if (th->detached)
609 DosCloseEventSem (th->cancel_event);
610 DosCloseEventSem (th->done_event );
611 free (th);
615 static void vlc_entry( void *p )
617 struct vlc_thread *th = p;
619 vlc_threadvar_set (thread_key, th);
620 th->killable = true;
621 th->data = th->entry (th->data);
622 DosPostEventSem( th->done_event );
623 vlc_thread_cleanup (th);
626 static int vlc_clone_attr (vlc_thread_t *p_handle, bool detached,
627 void *(*entry) (void *), void *data, int priority)
629 struct vlc_thread *th = malloc (sizeof (*th));
630 if (unlikely(th == NULL))
631 return ENOMEM;
632 th->entry = entry;
633 th->data = data;
634 th->detached = detached;
635 th->killable = false; /* not until vlc_entry() ! */
636 th->killed = false;
637 th->cleaners = NULL;
639 if( DosCreateEventSem (NULL, &th->cancel_event, 0, FALSE))
640 goto error;
641 if( DosCreateEventSem (NULL, &th->done_event, 0, FALSE))
642 goto error;
644 th->tid = _beginthread (vlc_entry, NULL, 1024 * 1024, th);
645 if((int)th->tid == -1)
646 goto error;
648 if (p_handle != NULL)
649 *p_handle = th;
651 if (priority)
652 DosSetPriority(PRTYS_THREAD,
653 HIBYTE(priority),
654 LOBYTE(priority),
655 th->tid);
657 return 0;
659 error:
660 DosCloseEventSem (th->cancel_event);
661 DosCloseEventSem (th->done_event);
662 free (th);
664 return ENOMEM;
667 int vlc_clone (vlc_thread_t *p_handle, void *(*entry) (void *),
668 void *data, int priority)
670 return vlc_clone_attr (p_handle, false, entry, data, priority);
673 void vlc_join (vlc_thread_t th, void **result)
675 ULONG rc;
679 vlc_testcancel();
680 rc = vlc_WaitForSingleObject( th->done_event, SEM_INDEFINITE_WAIT );
681 } while( rc == ERROR_INTERRUPT );
683 if (result != NULL)
684 *result = th->data;
686 DosCloseEventSem( th->cancel_event );
687 DosCloseEventSem( th->done_event );
689 free( th );
692 int vlc_clone_detach (vlc_thread_t *p_handle, void *(*entry) (void *),
693 void *data, int priority)
695 vlc_thread_t th;
696 if (p_handle == NULL)
697 p_handle = &th;
699 return vlc_clone_attr (p_handle, true, entry, data, priority);
702 int vlc_set_priority (vlc_thread_t th, int priority)
704 if (DosSetPriority(PRTYS_THREAD,
705 HIBYTE(priority),
706 LOBYTE(priority),
707 th->tid))
708 return VLC_EGENERIC;
709 return VLC_SUCCESS;
712 /*** Thread cancellation ***/
714 /* APC procedure for thread cancellation */
715 static void vlc_cancel_self (PVOID self)
717 struct vlc_thread *th = self;
719 if (likely(th != NULL))
720 th->killed = true;
723 void vlc_cancel (vlc_thread_t thread_id)
725 DosPostEventSem( thread_id->cancel_event );
728 int vlc_savecancel (void)
730 int state;
732 struct vlc_thread *th = vlc_threadvar_get (thread_key);
733 if (th == NULL)
734 return false; /* Main thread - cannot be cancelled anyway */
736 state = th->killable;
737 th->killable = false;
738 return state;
741 void vlc_restorecancel (int state)
743 struct vlc_thread *th = vlc_threadvar_get (thread_key);
744 assert (state == false || state == true);
746 if (th == NULL)
747 return; /* Main thread - cannot be cancelled anyway */
749 assert (!th->killable);
750 th->killable = state != 0;
753 void vlc_testcancel (void)
755 struct vlc_thread *th = vlc_threadvar_get (thread_key);
756 if (th == NULL)
757 return; /* Main thread - cannot be cancelled anyway */
759 /* This check is needed for the case that vlc_cancel() is followed by
760 * vlc_testcancel() without any cancellation point */
761 if( DosWaitEventSem( th->cancel_event, 0 ) == NO_ERROR )
762 vlc_cancel_self( NULL );
764 if (th->killable && th->killed)
766 for (vlc_cleanup_t *p = th->cleaners; p != NULL; p = p->next)
767 p->proc (p->data);
769 DosPostEventSem( th->done_event );
770 th->data = NULL; /* TODO: special value? */
771 vlc_thread_cleanup (th);
772 _endthread();
776 void vlc_control_cancel (int cmd, ...)
778 /* NOTE: This function only modifies thread-specific data, so there is no
779 * need to lock anything. */
780 va_list ap;
782 struct vlc_thread *th = vlc_threadvar_get (thread_key);
783 if (th == NULL)
784 return; /* Main thread - cannot be cancelled anyway */
786 va_start (ap, cmd);
787 switch (cmd)
789 case VLC_CLEANUP_PUSH:
791 /* cleaner is a pointer to the caller stack, no need to allocate
792 * and copy anything. As a nice side effect, this cannot fail. */
793 vlc_cleanup_t *cleaner = va_arg (ap, vlc_cleanup_t *);
794 cleaner->next = th->cleaners;
795 th->cleaners = cleaner;
796 break;
799 case VLC_CLEANUP_POP:
801 th->cleaners = th->cleaners->next;
802 break;
805 va_end (ap);
808 #define Q2LL( q ) ( *( long long * )&( q ))
810 /*** Clock ***/
811 mtime_t mdate (void)
813 /* We don't need the real date, just the value of a high precision timer */
814 QWORD counter;
815 ULONG freq;
816 if (DosTmrQueryTime(&counter) || DosTmrQueryFreq(&freq))
817 abort();
819 /* Convert to from (1/freq) to microsecond resolution */
820 /* We need to split the division to avoid 63-bits overflow */
821 lldiv_t d = lldiv (Q2LL(counter), freq);
823 return (d.quot * 1000000) + ((d.rem * 1000000) / freq);
826 #undef mwait
827 void mwait (mtime_t deadline)
829 mtime_t delay;
831 vlc_testcancel();
832 while ((delay = (deadline - mdate())) > 0)
834 delay /= 1000;
835 if (unlikely(delay > 0x7fffffff))
836 delay = 0x7fffffff;
837 vlc_Sleep (delay);
838 vlc_testcancel();
842 #undef msleep
843 void msleep (mtime_t delay)
845 mwait (mdate () + delay);
848 /*** Timers ***/
849 struct vlc_timer
851 TID tid;
852 HEV hev;
853 HTIMER htimer;
854 ULONG interval;
855 bool quit;
856 void (*func) (void *);
857 void *data;
860 static void vlc_timer_do (void *arg)
862 struct vlc_timer *timer = arg;
864 while (1)
866 ULONG count;
868 DosWaitEventSem (timer->hev, SEM_INDEFINITE_WAIT);
869 DosResetEventSem (timer->hev, &count);
871 if (timer->quit)
872 break;
874 timer->func (timer->data);
876 if (timer->interval)
877 DosAsyncTimer (timer->interval, (HSEM)timer->hev, &timer->htimer);
881 int vlc_timer_create (vlc_timer_t *id, void (*func) (void *), void *data)
883 struct vlc_timer *timer = malloc (sizeof (*timer));
885 if (timer == NULL)
886 return ENOMEM;
888 timer->func = func;
889 timer->data = data;
891 DosCreateEventSem (NULL, &timer->hev, DC_SEM_SHARED, FALSE);
892 timer->htimer = NULLHANDLE;
893 timer->interval = 0;
894 timer->quit = false;
895 timer->tid = _beginthread (vlc_timer_do, NULL, 1024 * 1024, timer);
897 *id = timer;
898 return 0;
901 void vlc_timer_destroy (vlc_timer_t timer)
903 if (timer->htimer != NULLHANDLE)
904 DosStopTimer (timer->htimer);
906 timer->quit = true;
907 DosPostEventSem (timer->hev);
908 DosWaitThread (&timer->tid, DCWW_WAIT);
909 DosCloseEventSem (timer->hev);
911 free (timer);
914 void vlc_timer_schedule (vlc_timer_t timer, bool absolute,
915 mtime_t value, mtime_t interval)
917 if (timer->htimer != NULLHANDLE)
919 DosStopTimer (timer->htimer);
920 timer->htimer = NULLHANDLE;
921 timer->interval = 0;
924 if (value == 0)
925 return; /* Disarm */
927 if (absolute)
928 value -= mdate ();
929 value = (value + 999) / 1000;
930 interval = (interval + 999) / 1000;
932 timer->interval = interval;
933 if (DosAsyncTimer (value, (HSEM)timer->hev, &timer->htimer))
934 abort ();
937 unsigned vlc_timer_getoverrun (vlc_timer_t timer)
939 (void)timer;
940 return 0;
943 /*** CPU ***/
944 unsigned vlc_GetCPUCount (void)
946 ULONG numprocs = 1;
948 DosQuerySysInfo(QSV_NUMPROCESSORS, QSV_NUMPROCESSORS,
949 &numprocs, sizeof(numprocs));
951 return numprocs;