Fixed a crash caused by yadif deinterlacer on Windows XP
[vlc/solaris.git] / src / win32 / thread.c
blob90a80a304bb8aed1922a0e322b1308f170c5a48b
1 /*****************************************************************************
2 * thread.c : Win32 back-end for LibVLC
3 *****************************************************************************
4 * Copyright (C) 1999-2009 VLC authors and VideoLAN
6 * Authors: Jean-Marc Dressler <polux@via.ecp.fr>
7 * Samuel Hocevar <sam@zoy.org>
8 * Gildas Bazin <gbazin@netcourrier.com>
9 * Clément Sténac
10 * Rémi Denis-Courmont
11 * Pierre Ynard
13 * This program is free software; you can redistribute it and/or modify it
14 * under the terms of the GNU Lesser General Public License as published by
15 * the Free Software Foundation; either version 2.1 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public License
24 * along with this program; if not, write to the Free Software Foundation,
25 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
26 *****************************************************************************/
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
32 #include <vlc_common.h>
34 #include "libvlc.h"
35 #include <stdarg.h>
36 #include <assert.h>
37 #include <limits.h>
38 #include <errno.h>
39 #ifdef UNDER_CE
40 # include <mmsystem.h>
41 #endif
43 static vlc_threadvar_t thread_key;
45 /**
46 * Per-thread data
48 struct vlc_thread
50 HANDLE id;
51 #ifdef UNDER_CE
52 HANDLE cancel_event;
53 #endif
55 bool detached;
56 bool killable;
57 bool killed;
58 vlc_cleanup_t *cleaners;
60 void *(*entry) (void *);
61 void *data;
64 static vlc_mutex_t super_mutex;
65 static vlc_cond_t super_variable;
66 extern vlc_rwlock_t config_lock, msg_lock;
68 BOOL WINAPI DllMain (HINSTANCE, DWORD, LPVOID);
70 BOOL WINAPI DllMain (HINSTANCE hinstDll, DWORD fdwReason, LPVOID lpvReserved)
72 (void) hinstDll;
73 (void) lpvReserved;
75 switch (fdwReason)
77 case DLL_PROCESS_ATTACH:
78 vlc_mutex_init (&super_mutex);
79 vlc_cond_init (&super_variable);
80 vlc_threadvar_create (&thread_key, NULL);
81 vlc_rwlock_init (&config_lock);
82 vlc_rwlock_init (&msg_lock);
83 vlc_CPU_init ();
84 break;
86 case DLL_PROCESS_DETACH:
87 vlc_rwlock_destroy (&msg_lock);
88 vlc_rwlock_destroy (&config_lock);
89 vlc_threadvar_delete (&thread_key);
90 vlc_cond_destroy (&super_variable);
91 vlc_mutex_destroy (&super_mutex);
92 break;
94 return TRUE;
97 static void CALLBACK vlc_cancel_self (ULONG_PTR);
99 static DWORD vlc_WaitForMultipleObjects (DWORD count, const HANDLE *handles,
100 DWORD delay)
102 DWORD ret;
103 #ifdef UNDER_CE
104 HANDLE buf[count + 1];
106 struct vlc_thread *th = vlc_threadvar_get (thread_key);
107 if (th != NULL)
109 memcpy (buf, handles, count * sizeof(HANDLE));
110 buf[count++] = th->cancel_event;
111 handles = buf;
114 if (count == 0)
116 Sleep (delay);
117 ret = WAIT_TIMEOUT;
119 else
120 ret = WaitForMultipleObjects (count, handles, FALSE, delay);
122 if ((th != NULL) && (ret == WAIT_OBJECT_0 + count - 1))
124 vlc_cancel_self ((uintptr_t)th);
125 ret = WAIT_IO_COMPLETION;
127 #else
128 if (count == 0)
130 ret = SleepEx (delay, TRUE);
131 if (ret == 0)
132 ret = WAIT_TIMEOUT;
134 else
135 ret = WaitForMultipleObjectsEx (count, handles, FALSE, delay, TRUE);
136 #endif
137 /* We do not abandon objects... this would be a bug */
138 assert (ret < WAIT_ABANDONED_0 || WAIT_ABANDONED_0 + count - 1 < ret);
140 if (unlikely(ret == WAIT_FAILED))
141 abort (); /* We are screwed! */
142 return ret;
145 static DWORD vlc_WaitForSingleObject (HANDLE handle, DWORD delay)
147 return vlc_WaitForMultipleObjects (1, &handle, delay);
150 static DWORD vlc_Sleep (DWORD delay)
152 DWORD ret = vlc_WaitForMultipleObjects (0, NULL, delay);
153 return (ret != WAIT_TIMEOUT) ? ret : 0;
157 /*** Mutexes ***/
158 void vlc_mutex_init( vlc_mutex_t *p_mutex )
160 /* This creates a recursive mutex. This is OK as fast mutexes have
161 * no defined behavior in case of recursive locking. */
162 InitializeCriticalSection (&p_mutex->mutex);
163 p_mutex->dynamic = true;
166 void vlc_mutex_init_recursive( vlc_mutex_t *p_mutex )
168 InitializeCriticalSection( &p_mutex->mutex );
169 p_mutex->dynamic = true;
173 void vlc_mutex_destroy (vlc_mutex_t *p_mutex)
175 assert (p_mutex->dynamic);
176 DeleteCriticalSection (&p_mutex->mutex);
179 void vlc_mutex_lock (vlc_mutex_t *p_mutex)
181 if (!p_mutex->dynamic)
182 { /* static mutexes */
183 int canc = vlc_savecancel ();
184 assert (p_mutex != &super_mutex); /* this one cannot be static */
186 vlc_mutex_lock (&super_mutex);
187 while (p_mutex->locked)
189 p_mutex->contention++;
190 vlc_cond_wait (&super_variable, &super_mutex);
191 p_mutex->contention--;
193 p_mutex->locked = true;
194 vlc_mutex_unlock (&super_mutex);
195 vlc_restorecancel (canc);
196 return;
199 EnterCriticalSection (&p_mutex->mutex);
202 int vlc_mutex_trylock (vlc_mutex_t *p_mutex)
204 if (!p_mutex->dynamic)
205 { /* static mutexes */
206 int ret = EBUSY;
208 assert (p_mutex != &super_mutex); /* this one cannot be static */
209 vlc_mutex_lock (&super_mutex);
210 if (!p_mutex->locked)
212 p_mutex->locked = true;
213 ret = 0;
215 vlc_mutex_unlock (&super_mutex);
216 return ret;
219 return TryEnterCriticalSection (&p_mutex->mutex) ? 0 : EBUSY;
222 void vlc_mutex_unlock (vlc_mutex_t *p_mutex)
224 if (!p_mutex->dynamic)
225 { /* static mutexes */
226 assert (p_mutex != &super_mutex); /* this one cannot be static */
228 vlc_mutex_lock (&super_mutex);
229 assert (p_mutex->locked);
230 p_mutex->locked = false;
231 if (p_mutex->contention)
232 vlc_cond_broadcast (&super_variable);
233 vlc_mutex_unlock (&super_mutex);
234 return;
237 LeaveCriticalSection (&p_mutex->mutex);
240 /*** Condition variables ***/
241 enum
243 CLOCK_REALTIME=0, /* must be zero for VLC_STATIC_COND */
244 CLOCK_MONOTONIC,
247 static void vlc_cond_init_common (vlc_cond_t *p_condvar, unsigned clock)
249 /* Create a manual-reset event (manual reset is needed for broadcast). */
250 p_condvar->handle = CreateEvent (NULL, TRUE, FALSE, NULL);
251 if (!p_condvar->handle)
252 abort();
253 p_condvar->clock = clock;
256 void vlc_cond_init (vlc_cond_t *p_condvar)
258 vlc_cond_init_common (p_condvar, CLOCK_MONOTONIC);
261 void vlc_cond_init_daytime (vlc_cond_t *p_condvar)
263 vlc_cond_init_common (p_condvar, CLOCK_REALTIME);
266 void vlc_cond_destroy (vlc_cond_t *p_condvar)
268 CloseHandle (p_condvar->handle);
271 void vlc_cond_signal (vlc_cond_t *p_condvar)
273 if (!p_condvar->handle)
274 return;
276 /* This is suboptimal but works. */
277 vlc_cond_broadcast (p_condvar);
280 void vlc_cond_broadcast (vlc_cond_t *p_condvar)
282 if (!p_condvar->handle)
283 return;
285 /* Wake all threads up (as the event HANDLE has manual reset) */
286 SetEvent (p_condvar->handle);
289 void vlc_cond_wait (vlc_cond_t *p_condvar, vlc_mutex_t *p_mutex)
291 DWORD result;
293 if (!p_condvar->handle)
294 { /* FIXME FIXME FIXME */
295 msleep (50000);
296 return;
301 vlc_testcancel ();
302 vlc_mutex_unlock (p_mutex);
303 result = vlc_WaitForSingleObject (p_condvar->handle, INFINITE);
304 vlc_mutex_lock (p_mutex);
306 while (result == WAIT_IO_COMPLETION);
308 ResetEvent (p_condvar->handle);
311 int vlc_cond_timedwait (vlc_cond_t *p_condvar, vlc_mutex_t *p_mutex,
312 mtime_t deadline)
314 DWORD result;
316 if (!p_condvar->handle)
317 { /* FIXME FIXME FIXME */
318 msleep (50000);
319 return 0;
324 vlc_testcancel ();
326 mtime_t total;
327 switch (p_condvar->clock)
329 case CLOCK_REALTIME: /* FIXME? sub-second precision */
330 total = CLOCK_FREQ * time (NULL);
331 break;
332 default:
333 assert (p_condvar->clock == CLOCK_MONOTONIC);
334 total = mdate();
335 break;
337 total = (deadline - total) / 1000;
338 if( total < 0 )
339 total = 0;
341 DWORD delay = (total > 0x7fffffff) ? 0x7fffffff : total;
342 vlc_mutex_unlock (p_mutex);
343 result = vlc_WaitForSingleObject (p_condvar->handle, delay);
344 vlc_mutex_lock (p_mutex);
346 while (result == WAIT_IO_COMPLETION);
348 ResetEvent (p_condvar->handle);
350 return (result == WAIT_OBJECT_0) ? 0 : ETIMEDOUT;
353 /*** Semaphore ***/
354 void vlc_sem_init (vlc_sem_t *sem, unsigned value)
356 *sem = CreateSemaphore (NULL, value, 0x7fffffff, NULL);
357 if (*sem == NULL)
358 abort ();
361 void vlc_sem_destroy (vlc_sem_t *sem)
363 CloseHandle (*sem);
366 int vlc_sem_post (vlc_sem_t *sem)
368 ReleaseSemaphore (*sem, 1, NULL);
369 return 0; /* FIXME */
372 void vlc_sem_wait (vlc_sem_t *sem)
374 DWORD result;
378 vlc_testcancel ();
379 result = vlc_WaitForSingleObject (*sem, INFINITE);
381 while (result == WAIT_IO_COMPLETION);
384 /*** Read/write locks */
385 /* SRW (Slim Read Write) locks are available in Vista+ only */
386 void vlc_rwlock_init (vlc_rwlock_t *lock)
388 vlc_mutex_init (&lock->mutex);
389 vlc_cond_init (&lock->wait);
390 lock->readers = 0; /* active readers */
391 lock->writers = 0; /* waiting writers */
392 lock->writer = 0; /* ID of active writer */
395 void vlc_rwlock_destroy (vlc_rwlock_t *lock)
397 vlc_cond_destroy (&lock->wait);
398 vlc_mutex_destroy (&lock->mutex);
401 void vlc_rwlock_rdlock (vlc_rwlock_t *lock)
403 vlc_mutex_lock (&lock->mutex);
404 /* Recursive read-locking is allowed. With the infos available:
405 * - the loosest possible condition (no active writer) is:
406 * (lock->writer != 0)
407 * - the strictest possible condition is:
408 * (lock->writer != 0 || (lock->readers == 0 && lock->writers > 0))
409 * or (lock->readers == 0 && (lock->writer != 0 || lock->writers > 0))
411 while (lock->writer != 0)
413 assert (lock->readers == 0);
414 vlc_cond_wait (&lock->wait, &lock->mutex);
416 if (unlikely(lock->readers == ULONG_MAX))
417 abort ();
418 lock->readers++;
419 vlc_mutex_unlock (&lock->mutex);
422 static void vlc_rwlock_rdunlock (vlc_rwlock_t *lock)
424 vlc_mutex_lock (&lock->mutex);
425 assert (lock->readers > 0);
427 /* If there are no readers left, wake up a writer. */
428 if (--lock->readers == 0 && lock->writers > 0)
429 vlc_cond_signal (&lock->wait);
430 vlc_mutex_unlock (&lock->mutex);
433 void vlc_rwlock_wrlock (vlc_rwlock_t *lock)
435 vlc_mutex_lock (&lock->mutex);
436 if (unlikely(lock->writers == ULONG_MAX))
437 abort ();
438 lock->writers++;
439 /* Wait until nobody owns the lock in either way. */
440 while ((lock->readers > 0) || (lock->writer != 0))
441 vlc_cond_wait (&lock->wait, &lock->mutex);
442 lock->writers--;
443 assert (lock->writer == 0);
444 lock->writer = GetCurrentThreadId ();
445 vlc_mutex_unlock (&lock->mutex);
448 static void vlc_rwlock_wrunlock (vlc_rwlock_t *lock)
450 vlc_mutex_lock (&lock->mutex);
451 assert (lock->writer == GetCurrentThreadId ());
452 assert (lock->readers == 0);
453 lock->writer = 0; /* Write unlock */
455 /* Let reader and writer compete. Scheduler decides who wins. */
456 vlc_cond_broadcast (&lock->wait);
457 vlc_mutex_unlock (&lock->mutex);
460 void vlc_rwlock_unlock (vlc_rwlock_t *lock)
462 /* Note: If the lock is held for reading, lock->writer is nul.
463 * If the lock is held for writing, only this thread can store a value to
464 * lock->writer. Either way, lock->writer is safe to fetch here. */
465 if (lock->writer != 0)
466 vlc_rwlock_wrunlock (lock);
467 else
468 vlc_rwlock_rdunlock (lock);
471 /*** Thread-specific variables (TLS) ***/
472 struct vlc_threadvar
474 DWORD id;
475 void (*destroy) (void *);
476 struct vlc_threadvar *prev;
477 struct vlc_threadvar *next;
478 } *vlc_threadvar_last = NULL;
480 int vlc_threadvar_create (vlc_threadvar_t *p_tls, void (*destr) (void *))
482 struct vlc_threadvar *var = malloc (sizeof (*var));
483 if (unlikely(var == NULL))
484 return errno;
486 var->id = TlsAlloc();
487 if (var->id == TLS_OUT_OF_INDEXES)
489 free (var);
490 return EAGAIN;
492 var->destroy = destr;
493 var->next = NULL;
494 *p_tls = var;
496 vlc_mutex_lock (&super_mutex);
497 var->prev = vlc_threadvar_last;
498 if (var->prev)
499 var->prev->next = var;
501 vlc_threadvar_last = var;
502 vlc_mutex_unlock (&super_mutex);
503 return 0;
506 void vlc_threadvar_delete (vlc_threadvar_t *p_tls)
508 struct vlc_threadvar *var = *p_tls;
510 vlc_mutex_lock (&super_mutex);
511 if (var->prev != NULL)
512 var->prev->next = var->next;
514 if (var->next != NULL)
515 var->next->prev = var->prev;
516 else
517 vlc_threadvar_last = var->prev;
519 vlc_mutex_unlock (&super_mutex);
521 TlsFree (var->id);
522 free (var);
525 int vlc_threadvar_set (vlc_threadvar_t key, void *value)
527 return TlsSetValue (key->id, value) ? ENOMEM : 0;
530 void *vlc_threadvar_get (vlc_threadvar_t key)
532 return TlsGetValue (key->id);
535 /*** Threads ***/
536 void vlc_threads_setup (libvlc_int_t *p_libvlc)
538 (void) p_libvlc;
541 static void vlc_thread_cleanup (struct vlc_thread *th)
543 vlc_threadvar_t key;
545 retry:
546 /* TODO: use RW lock or something similar */
547 vlc_mutex_lock (&super_mutex);
548 for (key = vlc_threadvar_last; key != NULL; key = key->prev)
550 void *value = vlc_threadvar_get (key);
551 if (value != NULL && key->destroy != NULL)
553 vlc_mutex_unlock (&super_mutex);
554 vlc_threadvar_set (key, NULL);
555 key->destroy (value);
556 goto retry;
559 vlc_mutex_unlock (&super_mutex);
561 if (th->detached)
563 CloseHandle (th->id);
564 #ifdef UNDER_CE
565 CloseHandle (th->cancel_event);
566 #endif
567 free (th);
571 static unsigned __stdcall vlc_entry (void *p)
573 struct vlc_thread *th = p;
575 vlc_threadvar_set (thread_key, th);
576 th->killable = true;
577 th->data = th->entry (th->data);
578 vlc_thread_cleanup (th);
579 return 0;
582 static int vlc_clone_attr (vlc_thread_t *p_handle, bool detached,
583 void *(*entry) (void *), void *data, int priority)
585 struct vlc_thread *th = malloc (sizeof (*th));
586 if (unlikely(th == NULL))
587 return ENOMEM;
588 th->entry = entry;
589 th->data = data;
590 th->detached = detached;
591 th->killable = false; /* not until vlc_entry() ! */
592 th->killed = false;
593 th->cleaners = NULL;
595 HANDLE hThread;
596 #ifndef UNDER_CE
597 /* When using the MSVCRT C library you have to use the _beginthreadex
598 * function instead of CreateThread, otherwise you'll end up with
599 * memory leaks and the signal functions not working (see Microsoft
600 * Knowledge Base, article 104641) */
601 uintptr_t h;
603 h = _beginthreadex (NULL, 0, vlc_entry, th, CREATE_SUSPENDED, NULL);
604 if (h == 0)
606 int err = errno;
607 free (th);
608 return err;
610 hThread = (HANDLE)h;
612 #else
613 th->cancel_event = CreateEvent (NULL, FALSE, FALSE, NULL);
614 if (th->cancel_event == NULL)
616 free (th);
617 return ENOMEM;
620 /* Not sure if CREATE_SUSPENDED + ResumeThread() is any useful on WinCE.
621 * Thread handles act up, too. */
622 hThread = CreateThread (NULL, 128*1024, vlc_entry, th,
623 CREATE_SUSPENDED, NULL);
624 if (hThread == NULL)
626 CloseHandle (th->cancel_event);
627 free (th);
628 return ENOMEM;
631 #endif
632 /* Thread is suspended, so we can safely set th->id */
633 th->id = hThread;
634 if (p_handle != NULL)
635 *p_handle = th;
637 if (priority)
638 SetThreadPriority (hThread, priority);
640 ResumeThread (hThread);
642 return 0;
645 int vlc_clone (vlc_thread_t *p_handle, void *(*entry) (void *),
646 void *data, int priority)
648 return vlc_clone_attr (p_handle, false, entry, data, priority);
651 void vlc_join (vlc_thread_t th, void **result)
654 vlc_testcancel ();
655 while (vlc_WaitForSingleObject (th->id, INFINITE)
656 == WAIT_IO_COMPLETION);
658 if (result != NULL)
659 *result = th->data;
660 CloseHandle (th->id);
661 #ifdef UNDER_CE
662 CloseHandle (th->cancel_event);
663 #endif
664 free (th);
667 int vlc_clone_detach (vlc_thread_t *p_handle, void *(*entry) (void *),
668 void *data, int priority)
670 vlc_thread_t th;
671 if (p_handle == NULL)
672 p_handle = &th;
674 return vlc_clone_attr (p_handle, true, entry, data, priority);
677 int vlc_set_priority (vlc_thread_t th, int priority)
679 if (!SetThreadPriority (th->id, priority))
680 return VLC_EGENERIC;
681 return VLC_SUCCESS;
684 /*** Thread cancellation ***/
686 /* APC procedure for thread cancellation */
687 static void CALLBACK vlc_cancel_self (ULONG_PTR self)
689 struct vlc_thread *th = (void *)self;
691 if (likely(th != NULL))
692 th->killed = true;
695 void vlc_cancel (vlc_thread_t th)
697 #ifndef UNDER_CE
698 QueueUserAPC (vlc_cancel_self, th->id, (uintptr_t)th);
699 #else
700 SetEvent (th->cancel_event);
701 #endif
704 int vlc_savecancel (void)
706 struct vlc_thread *th = vlc_threadvar_get (thread_key);
707 if (th == NULL)
708 return false; /* Main thread - cannot be cancelled anyway */
710 int state = th->killable;
711 th->killable = false;
712 return state;
715 void vlc_restorecancel (int state)
717 struct vlc_thread *th = vlc_threadvar_get (thread_key);
718 assert (state == false || state == true);
720 if (th == NULL)
721 return; /* Main thread - cannot be cancelled anyway */
723 assert (!th->killable);
724 th->killable = state != 0;
727 void vlc_testcancel (void)
729 struct vlc_thread *th = vlc_threadvar_get (thread_key);
730 if (th == NULL)
731 return; /* Main thread - cannot be cancelled anyway */
733 if (th->killable && th->killed)
735 for (vlc_cleanup_t *p = th->cleaners; p != NULL; p = p->next)
736 p->proc (p->data);
738 th->data = NULL; /* TODO: special value? */
739 vlc_thread_cleanup (th);
740 #ifndef UNDER_CE
741 _endthreadex(0);
742 #else
743 ExitThread(0);
744 #endif
748 void vlc_control_cancel (int cmd, ...)
750 /* NOTE: This function only modifies thread-specific data, so there is no
751 * need to lock anything. */
752 va_list ap;
754 struct vlc_thread *th = vlc_threadvar_get (thread_key);
755 if (th == NULL)
756 return; /* Main thread - cannot be cancelled anyway */
758 va_start (ap, cmd);
759 switch (cmd)
761 case VLC_CLEANUP_PUSH:
763 /* cleaner is a pointer to the caller stack, no need to allocate
764 * and copy anything. As a nice side effect, this cannot fail. */
765 vlc_cleanup_t *cleaner = va_arg (ap, vlc_cleanup_t *);
766 cleaner->next = th->cleaners;
767 th->cleaners = cleaner;
768 break;
771 case VLC_CLEANUP_POP:
773 th->cleaners = th->cleaners->next;
774 break;
777 va_end (ap);
781 /*** Clock ***/
782 mtime_t mdate (void)
784 /* We don't need the real date, just the value of a high precision timer */
785 LARGE_INTEGER counter, freq;
786 if (!QueryPerformanceCounter (&counter)
787 || !QueryPerformanceFrequency (&freq))
788 abort();
790 /* Convert to from (1/freq) to microsecond resolution */
791 /* We need to split the division to avoid 63-bits overflow */
792 lldiv_t d = lldiv (counter.QuadPart, freq.QuadPart);
794 return (d.quot * 1000000) + ((d.rem * 1000000) / freq.QuadPart);
797 #undef mwait
798 void mwait (mtime_t deadline)
800 mtime_t delay;
802 vlc_testcancel();
803 while ((delay = (deadline - mdate())) > 0)
805 delay /= 1000;
806 if (unlikely(delay > 0x7fffffff))
807 delay = 0x7fffffff;
808 vlc_Sleep (delay);
809 vlc_testcancel();
813 #undef msleep
814 void msleep (mtime_t delay)
816 mwait (mdate () + delay);
820 /*** Timers ***/
821 struct vlc_timer
823 #ifndef UNDER_CE
824 HANDLE handle;
825 #else
826 unsigned id;
827 unsigned interval;
828 #endif
829 void (*func) (void *);
830 void *data;
833 #ifndef UNDER_CE
834 static void CALLBACK vlc_timer_do (void *val, BOOLEAN timeout)
836 struct vlc_timer *timer = val;
838 assert (timeout);
839 timer->func (timer->data);
841 #else
842 static void CALLBACK vlc_timer_do (unsigned timer_id, unsigned msg,
843 DWORD_PTR user, DWORD_PTR unused1,
844 DWORD_PTR unused2)
846 struct vlc_timer *timer = (struct vlc_timer *) user;
847 assert (timer_id == timer->id);
848 (void) msg;
849 (void) unused1;
850 (void) unused2;
852 timer->func (timer->data);
854 if (timer->interval)
856 mtime_t interval = timer->interval * 1000;
857 vlc_timer_schedule (timer, false, interval, interval);
860 #endif
862 int vlc_timer_create (vlc_timer_t *id, void (*func) (void *), void *data)
864 struct vlc_timer *timer = malloc (sizeof (*timer));
866 if (timer == NULL)
867 return ENOMEM;
868 timer->func = func;
869 timer->data = data;
870 #ifndef UNDER_CE
871 timer->handle = INVALID_HANDLE_VALUE;
872 #else
873 timer->id = 0;
874 timer->interval = 0;
875 #endif
876 *id = timer;
877 return 0;
880 void vlc_timer_destroy (vlc_timer_t timer)
882 #ifndef UNDER_CE
883 if (timer->handle != INVALID_HANDLE_VALUE)
884 DeleteTimerQueueTimer (NULL, timer->handle, INVALID_HANDLE_VALUE);
885 #else
886 if (timer->id)
887 timeKillEvent (timer->id);
888 /* FIXME: timers that have not yet completed will trigger use-after-free */
889 #endif
890 free (timer);
893 void vlc_timer_schedule (vlc_timer_t timer, bool absolute,
894 mtime_t value, mtime_t interval)
896 #ifndef UNDER_CE
897 if (timer->handle != INVALID_HANDLE_VALUE)
899 DeleteTimerQueueTimer (NULL, timer->handle, NULL);
900 timer->handle = INVALID_HANDLE_VALUE;
902 #else
903 if (timer->id)
905 timeKillEvent (timer->id);
906 timer->id = 0;
907 timer->interval = 0;
909 #endif
910 if (value == 0)
911 return; /* Disarm */
913 if (absolute)
914 value -= mdate ();
915 value = (value + 999) / 1000;
916 interval = (interval + 999) / 1000;
918 #ifndef UNDER_CE
919 if (!CreateTimerQueueTimer (&timer->handle, NULL, vlc_timer_do, timer,
920 value, interval, WT_EXECUTEDEFAULT))
921 #else
922 TIMECAPS caps;
923 timeGetDevCaps (&caps, sizeof(caps));
925 unsigned delay = value;
926 delay = __MAX(delay, caps.wPeriodMin);
927 delay = __MIN(delay, caps.wPeriodMax);
929 unsigned event = TIME_ONESHOT;
931 if (interval == delay)
932 event = TIME_PERIODIC;
933 else if (interval)
934 timer->interval = interval;
936 timer->id = timeSetEvent (delay, delay / 20, vlc_timer_do, (DWORD) timer,
937 event);
938 if (!timer->id)
939 #endif
940 abort ();
943 unsigned vlc_timer_getoverrun (vlc_timer_t timer)
945 (void)timer;
946 return 0;
950 /*** CPU ***/
951 unsigned vlc_GetCPUCount (void)
953 #ifndef UNDER_CE
954 DWORD_PTR process;
955 DWORD_PTR system;
957 if (GetProcessAffinityMask (GetCurrentProcess(), &process, &system))
958 return popcount (system);
959 #endif
960 return 1;