VT: only use hw decoding unless explicitely requested
[vlc.git] / src / os2 / thread.c
blob20f7ccd79c279d9f48e67a49a0dea41ab306b974
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 #include <sys/types.h>
43 #include <sys/socket.h>
45 #include <sys/time.h>
46 #include <sys/select.h>
48 #include <sys/builtin.h>
50 #include <sys/stat.h>
52 static vlc_threadvar_t thread_key;
54 struct vlc_thread
56 TID tid;
57 HEV cancel_event;
58 HEV done_event;
59 int cancel_sock;
61 bool detached;
62 bool killable;
63 bool killed;
64 vlc_cleanup_t *cleaners;
66 void *(*entry) (void *);
67 void *data;
70 static void vlc_cancel_self (PVOID dummy);
72 static ULONG vlc_DosWaitEventSemEx( HEV hev, ULONG ulTimeout )
74 HMUX hmux;
75 SEMRECORD asr[ 2 ];
76 ULONG ulUser;
77 int n;
78 ULONG rc;
80 struct vlc_thread *th = vlc_thread_self ();
81 if( th == NULL || !th->killable )
83 /* Main thread - cannot be cancelled anyway
84 * Alien thread - out of our control
85 * Cancel disabled thread - ignore cancel
87 if( hev != NULLHANDLE )
88 return DosWaitEventSem( hev, ulTimeout );
90 return DosSleep( ulTimeout );
93 n = 0;
94 if( hev != NULLHANDLE )
96 asr[ n ].hsemCur = ( HSEM )hev;
97 asr[ n ].ulUser = 0;
98 n++;
100 asr[ n ].hsemCur = ( HSEM )th->cancel_event;
101 asr[ n ].ulUser = 0xFFFF;
102 n++;
104 DosCreateMuxWaitSem( NULL, &hmux, n, asr, DCMW_WAIT_ANY );
105 rc = DosWaitMuxWaitSem( hmux, ulTimeout, &ulUser );
106 DosCloseMuxWaitSem( hmux );
107 if( rc )
108 return rc;
110 if( ulUser == 0xFFFF )
112 vlc_cancel_self( th );
113 return ERROR_INTERRUPT;
116 return NO_ERROR;
119 static ULONG vlc_WaitForSingleObject (HEV hev, ULONG ulTimeout)
121 return vlc_DosWaitEventSemEx( hev, ulTimeout );
124 static ULONG vlc_Sleep (ULONG ulTimeout)
126 ULONG rc = vlc_DosWaitEventSemEx( NULLHANDLE, ulTimeout );
128 return ( rc != ERROR_TIMEOUT ) ? rc : 0;
131 static vlc_mutex_t super_mutex;
132 static vlc_cond_t super_variable;
133 extern vlc_rwlock_t config_lock;
135 static void vlc_static_cond_destroy_all(void);
137 int _CRT_init(void);
138 void _CRT_term(void);
140 unsigned long _System _DLL_InitTerm(unsigned long, unsigned long);
142 unsigned long _System _DLL_InitTerm(unsigned long hmod, unsigned long flag)
144 VLC_UNUSED (hmod);
146 switch (flag)
148 case 0 : /* Initialization */
149 if(_CRT_init() == -1)
150 return 0;
152 vlc_mutex_init (&super_mutex);
153 vlc_cond_init (&super_variable);
154 vlc_threadvar_create (&thread_key, NULL);
155 vlc_rwlock_init (&config_lock);
156 vlc_CPU_init ();
158 return 1;
160 case 1 : /* Termination */
161 vlc_rwlock_destroy (&config_lock);
162 vlc_threadvar_delete (&thread_key);
163 vlc_cond_destroy (&super_variable);
164 vlc_mutex_destroy (&super_mutex);
165 vlc_static_cond_destroy_all ();
167 _CRT_term();
169 return 1;
172 return 0; /* Failed */
175 /*** Mutexes ***/
176 void vlc_mutex_init( vlc_mutex_t *p_mutex )
178 /* This creates a recursive mutex. This is OK as fast mutexes have
179 * no defined behavior in case of recursive locking. */
180 DosCreateMutexSem( NULL, &p_mutex->hmtx, 0, FALSE );
181 p_mutex->dynamic = true;
184 void vlc_mutex_init_recursive( vlc_mutex_t *p_mutex )
186 DosCreateMutexSem( NULL, &p_mutex->hmtx, 0, FALSE );
187 p_mutex->dynamic = true;
191 void vlc_mutex_destroy (vlc_mutex_t *p_mutex)
193 assert (p_mutex->dynamic);
194 DosCloseMutexSem( p_mutex->hmtx );
197 void vlc_mutex_lock (vlc_mutex_t *p_mutex)
199 if (!p_mutex->dynamic)
200 { /* static mutexes */
201 int canc = vlc_savecancel ();
202 assert (p_mutex != &super_mutex); /* this one cannot be static */
204 vlc_mutex_lock (&super_mutex);
205 while (p_mutex->locked)
207 p_mutex->contention++;
208 vlc_cond_wait (&super_variable, &super_mutex);
209 p_mutex->contention--;
211 p_mutex->locked = true;
212 vlc_mutex_unlock (&super_mutex);
213 vlc_restorecancel (canc);
214 return;
217 DosRequestMutexSem(p_mutex->hmtx, SEM_INDEFINITE_WAIT);
220 int vlc_mutex_trylock (vlc_mutex_t *p_mutex)
222 if (!p_mutex->dynamic)
223 { /* static mutexes */
224 int ret = EBUSY;
226 assert (p_mutex != &super_mutex); /* this one cannot be static */
227 vlc_mutex_lock (&super_mutex);
228 if (!p_mutex->locked)
230 p_mutex->locked = true;
231 ret = 0;
233 vlc_mutex_unlock (&super_mutex);
234 return ret;
237 return DosRequestMutexSem( p_mutex->hmtx, 0 ) ? EBUSY : 0;
240 void vlc_mutex_unlock (vlc_mutex_t *p_mutex)
242 if (!p_mutex->dynamic)
243 { /* static mutexes */
244 assert (p_mutex != &super_mutex); /* this one cannot be static */
246 vlc_mutex_lock (&super_mutex);
247 assert (p_mutex->locked);
248 p_mutex->locked = false;
249 if (p_mutex->contention)
250 vlc_cond_broadcast (&super_variable);
251 vlc_mutex_unlock (&super_mutex);
252 return;
255 DosReleaseMutexSem( p_mutex->hmtx );
258 /*** Condition variables ***/
259 typedef struct vlc_static_cond_t vlc_static_cond_t;
261 struct vlc_static_cond_t
263 vlc_cond_t condvar;
264 vlc_static_cond_t *next;
267 static vlc_static_cond_t *static_condvar_start = NULL;
269 static void vlc_static_cond_init (vlc_cond_t *p_condvar)
271 vlc_mutex_lock (&super_mutex);
273 if (p_condvar->hev == NULLHANDLE)
275 vlc_cond_init (p_condvar);
277 vlc_static_cond_t *new_static_condvar;
279 new_static_condvar = malloc (sizeof (*new_static_condvar));
280 if (unlikely (!new_static_condvar))
281 abort();
283 memcpy (&new_static_condvar->condvar, p_condvar, sizeof (*p_condvar));
284 new_static_condvar->next = static_condvar_start;
285 static_condvar_start = new_static_condvar;
288 vlc_mutex_unlock (&super_mutex);
291 static void vlc_static_cond_destroy_all (void)
293 vlc_static_cond_t *static_condvar;
294 vlc_static_cond_t *static_condvar_next;
297 for (static_condvar = static_condvar_start; static_condvar;
298 static_condvar = static_condvar_next)
300 static_condvar_next = static_condvar->next;
302 vlc_cond_destroy (&static_condvar->condvar);
303 free (static_condvar);
307 void vlc_cond_init (vlc_cond_t *p_condvar)
309 if (DosCreateEventSem (NULL, &p_condvar->hev, 0, FALSE) ||
310 DosCreateEventSem (NULL, &p_condvar->hevAck, 0, FALSE))
311 abort();
313 p_condvar->waiters = 0;
314 p_condvar->signaled = 0;
317 void vlc_cond_init_daytime (vlc_cond_t *p_condvar)
319 vlc_cond_init (p_condvar);
322 void vlc_cond_destroy (vlc_cond_t *p_condvar)
324 DosCloseEventSem( p_condvar->hev );
325 DosCloseEventSem( p_condvar->hevAck );
328 void vlc_cond_signal (vlc_cond_t *p_condvar)
330 if (p_condvar->hev == NULLHANDLE)
331 vlc_static_cond_init (p_condvar);
333 if (!__atomic_cmpxchg32 (&p_condvar->waiters, 0, 0))
335 ULONG ulPost;
337 __atomic_xchg (&p_condvar->signaled, 1);
338 DosPostEventSem (p_condvar->hev);
340 DosWaitEventSem (p_condvar->hevAck, SEM_INDEFINITE_WAIT);
341 DosResetEventSem (p_condvar->hevAck, &ulPost);
345 void vlc_cond_broadcast (vlc_cond_t *p_condvar)
347 if (p_condvar->hev == NULLHANDLE)
348 vlc_static_cond_init (p_condvar);
350 while (!__atomic_cmpxchg32 (&p_condvar->waiters, 0, 0))
351 vlc_cond_signal (p_condvar);
354 static int vlc_cond_wait_common (vlc_cond_t *p_condvar, vlc_mutex_t *p_mutex,
355 ULONG ulTimeout)
357 ULONG ulPost;
358 ULONG rc;
360 assert(p_condvar->hev != NULLHANDLE);
364 vlc_testcancel();
366 __atomic_increment (&p_condvar->waiters);
368 vlc_mutex_unlock (p_mutex);
372 rc = vlc_WaitForSingleObject( p_condvar->hev, ulTimeout );
373 if (rc == NO_ERROR)
374 DosResetEventSem (p_condvar->hev, &ulPost);
375 } while (rc == NO_ERROR &&
376 __atomic_cmpxchg32 (&p_condvar->signaled, 0, 1) == 0);
378 __atomic_decrement (&p_condvar->waiters);
380 DosPostEventSem (p_condvar->hevAck);
382 vlc_mutex_lock (p_mutex);
383 } while( rc == ERROR_INTERRUPT );
385 return rc ? ETIMEDOUT : 0;
388 void vlc_cond_wait (vlc_cond_t *p_condvar, vlc_mutex_t *p_mutex)
390 if (p_condvar->hev == NULLHANDLE)
391 vlc_static_cond_init (p_condvar);
393 vlc_cond_wait_common (p_condvar, p_mutex, SEM_INDEFINITE_WAIT);
396 int vlc_cond_timedwait (vlc_cond_t *p_condvar, vlc_mutex_t *p_mutex,
397 mtime_t deadline)
399 ULONG ulTimeout;
401 mtime_t total = mdate();
402 total = (deadline - total) / 1000;
403 if( total < 0 )
404 total = 0;
406 ulTimeout = ( total > 0x7fffffff ) ? 0x7fffffff : total;
408 return vlc_cond_wait_common (p_condvar, p_mutex, ulTimeout);
411 int vlc_cond_timedwait_daytime (vlc_cond_t *p_condvar, vlc_mutex_t *p_mutex,
412 time_t deadline)
414 ULONG ulTimeout;
415 mtime_t total;
416 struct timeval tv;
418 gettimeofday (&tv, NULL);
420 total = CLOCK_FREQ * tv.tv_sec +
421 CLOCK_FREQ * tv.tv_usec / 1000000L;
422 total = (deadline - total) / 1000;
423 if( total < 0 )
424 total = 0;
426 ulTimeout = ( total > 0x7fffffff ) ? 0x7fffffff : total;
428 return vlc_cond_wait_common (p_condvar, p_mutex, ulTimeout);
431 /*** Thread-specific variables (TLS) ***/
432 struct vlc_threadvar
434 PULONG id;
435 void (*destroy) (void *);
436 struct vlc_threadvar *prev;
437 struct vlc_threadvar *next;
438 } *vlc_threadvar_last = NULL;
440 int vlc_threadvar_create (vlc_threadvar_t *p_tls, void (*destr) (void *))
442 ULONG rc;
444 struct vlc_threadvar *var = malloc (sizeof (*var));
445 if (unlikely(var == NULL))
446 return errno;
448 rc = DosAllocThreadLocalMemory( 1, &var->id );
449 if( rc )
451 free (var);
452 return EAGAIN;
455 var->destroy = destr;
456 var->next = NULL;
457 *p_tls = var;
459 vlc_mutex_lock (&super_mutex);
460 var->prev = vlc_threadvar_last;
461 if (var->prev)
462 var->prev->next = var;
464 vlc_threadvar_last = var;
465 vlc_mutex_unlock (&super_mutex);
466 return 0;
469 void vlc_threadvar_delete (vlc_threadvar_t *p_tls)
471 struct vlc_threadvar *var = *p_tls;
473 vlc_mutex_lock (&super_mutex);
474 if (var->prev != NULL)
475 var->prev->next = var->next;
477 if (var->next != NULL)
478 var->next->prev = var->prev;
479 else
480 vlc_threadvar_last = var->prev;
482 vlc_mutex_unlock (&super_mutex);
484 DosFreeThreadLocalMemory( var->id );
485 free (var);
488 int vlc_threadvar_set (vlc_threadvar_t key, void *value)
490 *key->id = ( ULONG )value;
491 return 0;
494 void *vlc_threadvar_get (vlc_threadvar_t key)
496 return ( void * )*key->id;
500 /*** Threads ***/
501 void vlc_threads_setup (libvlc_int_t *p_libvlc)
503 (void) p_libvlc;
506 static void vlc_thread_cleanup (struct vlc_thread *th)
508 vlc_threadvar_t key;
510 retry:
511 /* TODO: use RW lock or something similar */
512 vlc_mutex_lock (&super_mutex);
513 for (key = vlc_threadvar_last; key != NULL; key = key->prev)
515 void *value = vlc_threadvar_get (key);
516 if (value != NULL && key->destroy != NULL)
518 vlc_mutex_unlock (&super_mutex);
519 vlc_threadvar_set (key, NULL);
520 key->destroy (value);
521 goto retry;
524 vlc_mutex_unlock (&super_mutex);
526 if (th->detached)
528 DosCloseEventSem (th->cancel_event);
529 DosCloseEventSem (th->done_event );
531 soclose (th->cancel_sock);
533 free (th);
537 static void vlc_entry( void *p )
539 struct vlc_thread *th = p;
541 vlc_threadvar_set (thread_key, th);
542 th->killable = true;
543 th->data = th->entry (th->data);
544 DosPostEventSem( th->done_event );
545 vlc_thread_cleanup (th);
548 static int vlc_clone_attr (vlc_thread_t *p_handle, bool detached,
549 void *(*entry) (void *), void *data, int priority)
551 struct vlc_thread *th = malloc (sizeof (*th));
552 if (unlikely(th == NULL))
553 return ENOMEM;
554 th->entry = entry;
555 th->data = data;
556 th->detached = detached;
557 th->killable = false; /* not until vlc_entry() ! */
558 th->killed = false;
559 th->cleaners = NULL;
561 if( DosCreateEventSem (NULL, &th->cancel_event, 0, FALSE))
562 goto error;
563 if( DosCreateEventSem (NULL, &th->done_event, 0, FALSE))
564 goto error;
566 th->cancel_sock = socket (AF_LOCAL, SOCK_STREAM, 0);
567 if( th->cancel_sock < 0 )
568 goto error;
570 th->tid = _beginthread (vlc_entry, NULL, 1024 * 1024, th);
571 if((int)th->tid == -1)
572 goto error;
574 if (p_handle != NULL)
575 *p_handle = th;
577 if (priority)
578 DosSetPriority(PRTYS_THREAD,
579 HIBYTE(priority),
580 LOBYTE(priority),
581 th->tid);
583 return 0;
585 error:
586 soclose (th->cancel_sock);
587 DosCloseEventSem (th->cancel_event);
588 DosCloseEventSem (th->done_event);
589 free (th);
591 return ENOMEM;
594 int vlc_clone (vlc_thread_t *p_handle, void *(*entry) (void *),
595 void *data, int priority)
597 return vlc_clone_attr (p_handle, false, entry, data, priority);
600 void vlc_join (vlc_thread_t th, void **result)
602 ULONG rc;
606 vlc_testcancel();
607 rc = vlc_WaitForSingleObject( th->done_event, SEM_INDEFINITE_WAIT );
608 } while( rc == ERROR_INTERRUPT );
610 if (result != NULL)
611 *result = th->data;
613 DosCloseEventSem( th->cancel_event );
614 DosCloseEventSem( th->done_event );
616 soclose( th->cancel_sock );
618 free( th );
621 int vlc_clone_detach (vlc_thread_t *p_handle, void *(*entry) (void *),
622 void *data, int priority)
624 vlc_thread_t th;
625 if (p_handle == NULL)
626 p_handle = &th;
628 return vlc_clone_attr (p_handle, true, entry, data, priority);
631 int vlc_set_priority (vlc_thread_t th, int priority)
633 if (DosSetPriority(PRTYS_THREAD,
634 HIBYTE(priority),
635 LOBYTE(priority),
636 th->tid))
637 return VLC_EGENERIC;
638 return VLC_SUCCESS;
641 vlc_thread_t vlc_thread_self (void)
643 return vlc_threadvar_get (thread_key);
646 unsigned long vlc_thread_id (void)
648 return _gettid();
651 /*** Thread cancellation ***/
653 /* APC procedure for thread cancellation */
654 static void vlc_cancel_self (PVOID self)
656 struct vlc_thread *th = self;
658 if (likely(th != NULL))
659 th->killed = true;
662 void vlc_cancel (vlc_thread_t thread_id)
664 DosPostEventSem( thread_id->cancel_event );
665 so_cancel( thread_id->cancel_sock );
668 int vlc_savecancel (void)
670 int state;
672 struct vlc_thread *th = vlc_thread_self ();
673 if (th == NULL)
674 return false; /* Main thread - cannot be cancelled anyway */
676 state = th->killable;
677 th->killable = false;
678 return state;
681 void vlc_restorecancel (int state)
683 struct vlc_thread *th = vlc_thread_self ();
684 assert (state == false || state == true);
686 if (th == NULL)
687 return; /* Main thread - cannot be cancelled anyway */
689 assert (!th->killable);
690 th->killable = state != 0;
693 void vlc_testcancel (void)
695 struct vlc_thread *th = vlc_thread_self ();
696 if (th == NULL)
697 return; /* Main thread - cannot be cancelled anyway */
699 /* This check is needed for the case that vlc_cancel() is followed by
700 * vlc_testcancel() without any cancellation point */
701 if( DosWaitEventSem( th->cancel_event, 0 ) == NO_ERROR )
702 vlc_cancel_self( th );
704 if (th->killable && th->killed)
706 for (vlc_cleanup_t *p = th->cleaners; p != NULL; p = p->next)
707 p->proc (p->data);
709 DosPostEventSem( th->done_event );
710 th->data = NULL; /* TODO: special value? */
711 vlc_thread_cleanup (th);
712 _endthread();
716 void vlc_control_cancel (int cmd, ...)
718 /* NOTE: This function only modifies thread-specific data, so there is no
719 * need to lock anything. */
720 va_list ap;
722 struct vlc_thread *th = vlc_thread_self ();
723 if (th == NULL)
724 return; /* Main thread - cannot be cancelled anyway */
726 va_start (ap, cmd);
727 switch (cmd)
729 case VLC_CLEANUP_PUSH:
731 /* cleaner is a pointer to the caller stack, no need to allocate
732 * and copy anything. As a nice side effect, this cannot fail. */
733 vlc_cleanup_t *cleaner = va_arg (ap, vlc_cleanup_t *);
734 cleaner->next = th->cleaners;
735 th->cleaners = cleaner;
736 break;
739 case VLC_CLEANUP_POP:
741 th->cleaners = th->cleaners->next;
742 break;
745 va_end (ap);
748 static int vlc_select( int nfds, fd_set *rdset, fd_set *wrset, fd_set *exset,
749 struct timeval *timeout )
751 struct vlc_thread *th = vlc_thread_self( );
753 int rc;
755 if( th )
757 FD_SET( th->cancel_sock, rdset );
759 nfds = MAX( nfds, th->cancel_sock + 1 );
762 rc = select( nfds, rdset, wrset, exset, timeout );
764 vlc_testcancel();
766 return rc;
770 /* Export vlc_poll_os2 directly regardless of EXPORTS of .def */
771 __declspec(dllexport)
772 int vlc_poll_os2( struct pollfd *fds, unsigned nfds, int timeout );
774 __declspec(dllexport)
775 int vlc_poll_os2( struct pollfd *fds, unsigned nfds, int timeout )
777 fd_set rdset, wrset, exset;
779 int non_sockets = 0;
781 struct timeval tv = { 0, 0 };
783 int val = -1;
785 FD_ZERO( &rdset );
786 FD_ZERO( &wrset );
787 FD_ZERO( &exset );
788 for( unsigned i = 0; i < nfds; i++ )
790 int fd = fds[ i ].fd;
791 struct stat stbuf;
793 fds[ i ].revents = 0;
795 if( fstat( fd, &stbuf ) == -1 ||
796 (errno = 0, !S_ISSOCK( stbuf.st_mode )))
798 if( fd >= 0 )
800 /* If regular files, assume readiness for requested modes */
801 fds[ i ].revents = ( !errno && S_ISREG( stbuf.st_mode ))
802 ? ( fds[ i ].events &
803 ( POLLIN | POLLOUT | POLLPRI ))
804 : POLLNVAL;
806 non_sockets++;
809 continue;
812 if( val < fd )
813 val = fd;
815 if(( unsigned )fd >= FD_SETSIZE )
817 errno = EINVAL;
818 return -1;
821 if( fds[ i ].events & POLLIN )
822 FD_SET( fd, &rdset );
823 if( fds[ i ].events & POLLOUT )
824 FD_SET( fd, &wrset );
825 if( fds[ i ].events & POLLPRI )
826 FD_SET( fd, &exset );
829 if( non_sockets > 0 )
830 timeout = 0; /* Just check pending sockets */
832 /* Sockets included ? */
833 if( val != -1)
835 struct timeval *ptv = NULL;
837 if( timeout >= 0 )
839 div_t d = div( timeout, 1000 );
840 tv.tv_sec = d.quot;
841 tv.tv_usec = d.rem * 1000;
843 ptv = &tv;
846 if (vlc_select( val + 1, &rdset, &wrset, &exset, ptv ) == -1)
847 return -1;
850 val = 0;
851 for( unsigned i = 0; i < nfds; i++ )
853 int fd = fds[ i ].fd;
855 if( fd >= 0 && fds[ i ].revents == 0 )
857 fds[ i ].revents = ( FD_ISSET( fd, &rdset ) ? POLLIN : 0 )
858 | ( FD_ISSET( fd, &wrset ) ? POLLOUT : 0 )
859 | ( FD_ISSET( fd, &exset ) ? POLLPRI : 0 );
862 if( fds[ i ].revents != 0 )
863 val++;
866 return val;
869 #define Q2LL( q ) ( *( long long * )&( q ))
871 /*** Clock ***/
872 mtime_t mdate (void)
874 /* We don't need the real date, just the value of a high precision timer */
875 QWORD counter;
876 ULONG freq;
877 if (DosTmrQueryTime(&counter) || DosTmrQueryFreq(&freq))
878 abort();
880 /* Convert to from (1/freq) to microsecond resolution */
881 /* We need to split the division to avoid 63-bits overflow */
882 lldiv_t d = lldiv (Q2LL(counter), freq);
884 return (d.quot * 1000000) + ((d.rem * 1000000) / freq);
887 #undef mwait
888 void mwait (mtime_t deadline)
890 mtime_t delay;
892 vlc_testcancel();
893 while ((delay = (deadline - mdate())) > 0)
895 delay /= 1000;
896 if (unlikely(delay > 0x7fffffff))
897 delay = 0x7fffffff;
898 vlc_Sleep (delay);
899 vlc_testcancel();
903 #undef msleep
904 void msleep (mtime_t delay)
906 mwait (mdate () + delay);
909 /*** Timers ***/
910 struct vlc_timer
912 TID tid;
913 HEV hev;
914 HTIMER htimer;
915 ULONG interval;
916 bool quit;
917 void (*func) (void *);
918 void *data;
921 static void vlc_timer_do (void *arg)
923 struct vlc_timer *timer = arg;
925 while (1)
927 ULONG count;
929 DosWaitEventSem (timer->hev, SEM_INDEFINITE_WAIT);
930 DosResetEventSem (timer->hev, &count);
932 if (timer->quit)
933 break;
935 timer->func (timer->data);
937 if (timer->interval)
938 DosAsyncTimer (timer->interval, (HSEM)timer->hev, &timer->htimer);
942 int vlc_timer_create (vlc_timer_t *id, void (*func) (void *), void *data)
944 struct vlc_timer *timer = malloc (sizeof (*timer));
946 if (timer == NULL)
947 return ENOMEM;
949 timer->func = func;
950 timer->data = data;
952 DosCreateEventSem (NULL, &timer->hev, DC_SEM_SHARED, FALSE);
953 timer->htimer = NULLHANDLE;
954 timer->interval = 0;
955 timer->quit = false;
956 timer->tid = _beginthread (vlc_timer_do, NULL, 1024 * 1024, timer);
958 *id = timer;
959 return 0;
962 void vlc_timer_destroy (vlc_timer_t timer)
964 if (timer->htimer != NULLHANDLE)
965 DosStopTimer (timer->htimer);
967 timer->quit = true;
968 DosPostEventSem (timer->hev);
969 DosWaitThread (&timer->tid, DCWW_WAIT);
970 DosCloseEventSem (timer->hev);
972 free (timer);
975 void vlc_timer_schedule (vlc_timer_t timer, bool absolute,
976 mtime_t value, mtime_t interval)
978 if (timer->htimer != NULLHANDLE)
980 DosStopTimer (timer->htimer);
981 timer->htimer = NULLHANDLE;
982 timer->interval = 0;
985 if (value == 0)
986 return; /* Disarm */
988 if (absolute)
989 value -= mdate ();
990 value = (value + 999) / 1000;
991 interval = (interval + 999) / 1000;
993 timer->interval = interval;
994 if (DosAsyncTimer (value, (HSEM)timer->hev, &timer->htimer))
995 abort ();
998 unsigned vlc_timer_getoverrun (vlc_timer_t timer)
1000 (void)timer;
1001 return 0;
1004 /*** CPU ***/
1005 unsigned vlc_GetCPUCount (void)
1007 ULONG numprocs = 1;
1009 DosQuerySysInfo(QSV_NUMPROCESSORS, QSV_NUMPROCESSORS,
1010 &numprocs, sizeof(numprocs));
1012 return numprocs;