gui: macos: use float for rate
[vlc.git] / src / os2 / thread.c
blob98a72984afca61b89d4a506dd492f50f24b75101
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 #ifdef HAVE_SYS_SOCKET_H
44 #include <sys/socket.h>
45 #endif
47 #include <sys/time.h>
48 #include <sys/select.h>
50 #include <sys/builtin.h>
52 #include <sys/stat.h>
54 static vlc_threadvar_t thread_key;
56 struct vlc_thread
58 TID tid;
59 HEV cancel_event;
60 HEV done_event;
61 int cancel_sock;
63 bool detached;
64 bool killable;
65 bool killed;
66 vlc_cleanup_t *cleaners;
68 void *(*entry) (void *);
69 void *data;
72 static void vlc_cancel_self (PVOID dummy);
74 static ULONG vlc_DosWaitEventSemEx( HEV hev, ULONG ulTimeout )
76 HMUX hmux;
77 SEMRECORD asr[ 2 ];
78 ULONG ulUser;
79 int n;
80 ULONG rc;
82 struct vlc_thread *th = vlc_thread_self ();
83 if( th == NULL || !th->killable )
85 /* Main thread - cannot be cancelled anyway
86 * Alien thread - out of our control
87 * Cancel disabled thread - ignore cancel
89 if( hev != NULLHANDLE )
90 return DosWaitEventSem( hev, ulTimeout );
92 return DosSleep( ulTimeout );
95 n = 0;
96 if( hev != NULLHANDLE )
98 asr[ n ].hsemCur = ( HSEM )hev;
99 asr[ n ].ulUser = 0;
100 n++;
102 asr[ n ].hsemCur = ( HSEM )th->cancel_event;
103 asr[ n ].ulUser = 0xFFFF;
104 n++;
106 DosCreateMuxWaitSem( NULL, &hmux, n, asr, DCMW_WAIT_ANY );
107 rc = DosWaitMuxWaitSem( hmux, ulTimeout, &ulUser );
108 DosCloseMuxWaitSem( hmux );
109 if( rc )
110 return rc;
112 if( ulUser == 0xFFFF )
114 vlc_cancel_self( th );
115 return ERROR_INTERRUPT;
118 return NO_ERROR;
121 static ULONG vlc_WaitForSingleObject (HEV hev, ULONG ulTimeout)
123 return vlc_DosWaitEventSemEx( hev, ulTimeout );
126 static ULONG vlc_Sleep (ULONG ulTimeout)
128 ULONG rc = vlc_DosWaitEventSemEx( NULLHANDLE, ulTimeout );
130 return ( rc != ERROR_TIMEOUT ) ? rc : 0;
133 static vlc_mutex_t super_mutex;
134 static vlc_cond_t super_variable;
135 extern vlc_rwlock_t config_lock;
137 static void vlc_static_cond_destroy_all(void);
139 int _CRT_init(void);
140 void _CRT_term(void);
142 unsigned long _System _DLL_InitTerm(unsigned long, unsigned long);
144 unsigned long _System _DLL_InitTerm(unsigned long hmod, unsigned long flag)
146 VLC_UNUSED (hmod);
148 switch (flag)
150 case 0 : /* Initialization */
151 if(_CRT_init() == -1)
152 return 0;
154 vlc_mutex_init (&super_mutex);
155 vlc_cond_init (&super_variable);
156 vlc_threadvar_create (&thread_key, NULL);
157 vlc_rwlock_init (&config_lock);
159 return 1;
161 case 1 : /* Termination */
162 vlc_rwlock_destroy (&config_lock);
163 vlc_threadvar_delete (&thread_key);
164 vlc_cond_destroy (&super_variable);
165 vlc_mutex_destroy (&super_mutex);
166 vlc_static_cond_destroy_all ();
168 _CRT_term();
170 return 1;
173 return 0; /* Failed */
176 /*** Mutexes ***/
177 void vlc_mutex_init( vlc_mutex_t *p_mutex )
179 /* This creates a recursive mutex. This is OK as fast mutexes have
180 * no defined behavior in case of recursive locking. */
181 DosCreateMutexSem( NULL, &p_mutex->hmtx, 0, FALSE );
182 p_mutex->dynamic = true;
185 void vlc_mutex_init_recursive( vlc_mutex_t *p_mutex )
187 DosCreateMutexSem( NULL, &p_mutex->hmtx, 0, FALSE );
188 p_mutex->dynamic = true;
192 void vlc_mutex_destroy (vlc_mutex_t *p_mutex)
194 assert (p_mutex->dynamic);
195 DosCloseMutexSem( p_mutex->hmtx );
198 void vlc_mutex_lock (vlc_mutex_t *p_mutex)
200 if (!p_mutex->dynamic)
201 { /* static mutexes */
202 int canc = vlc_savecancel ();
203 assert (p_mutex != &super_mutex); /* this one cannot be static */
205 vlc_mutex_lock (&super_mutex);
206 while (p_mutex->locked)
208 p_mutex->contention++;
209 vlc_cond_wait (&super_variable, &super_mutex);
210 p_mutex->contention--;
212 p_mutex->locked = true;
213 vlc_mutex_unlock (&super_mutex);
214 vlc_restorecancel (canc);
216 else
217 DosRequestMutexSem(p_mutex->hmtx, SEM_INDEFINITE_WAIT);
219 vlc_mutex_mark(p_mutex);
222 int vlc_mutex_trylock (vlc_mutex_t *p_mutex)
224 int ret;
226 if (!p_mutex->dynamic)
227 { /* static mutexes */
228 assert (p_mutex != &super_mutex); /* this one cannot be static */
229 vlc_mutex_lock (&super_mutex);
230 if (!p_mutex->locked)
232 p_mutex->locked = true;
233 ret = 0;
235 else
236 ret = EBUSY;
237 vlc_mutex_unlock (&super_mutex);
239 else
240 ret = DosRequestMutexSem( p_mutex->hmtx, 0 ) ? EBUSY : 0;
242 if (ret == 0)
243 vlc_mutex_mark(p_mutex);
245 return ret;
248 void vlc_mutex_unlock (vlc_mutex_t *p_mutex)
250 if (!p_mutex->dynamic)
251 { /* static mutexes */
252 assert (p_mutex != &super_mutex); /* this one cannot be static */
254 vlc_mutex_lock (&super_mutex);
255 assert (p_mutex->locked);
256 p_mutex->locked = false;
257 if (p_mutex->contention)
258 vlc_cond_broadcast (&super_variable);
259 vlc_mutex_unlock (&super_mutex);
261 else
262 DosReleaseMutexSem( p_mutex->hmtx );
264 vlc_mutex_unmark(p_mutex);
267 /*** Condition variables ***/
268 typedef struct vlc_static_cond_t vlc_static_cond_t;
270 struct vlc_static_cond_t
272 vlc_cond_t condvar;
273 vlc_static_cond_t *next;
276 static vlc_static_cond_t *static_condvar_start = NULL;
278 static void vlc_static_cond_init (vlc_cond_t *p_condvar)
280 vlc_mutex_lock (&super_mutex);
282 if (p_condvar->hev == NULLHANDLE)
284 vlc_cond_init (p_condvar);
286 vlc_static_cond_t *new_static_condvar;
288 new_static_condvar = malloc (sizeof (*new_static_condvar));
289 if (unlikely (!new_static_condvar))
290 abort();
292 memcpy (&new_static_condvar->condvar, p_condvar, sizeof (*p_condvar));
293 new_static_condvar->next = static_condvar_start;
294 static_condvar_start = new_static_condvar;
297 vlc_mutex_unlock (&super_mutex);
300 static void vlc_static_cond_destroy_all (void)
302 vlc_static_cond_t *static_condvar;
303 vlc_static_cond_t *static_condvar_next;
306 for (static_condvar = static_condvar_start; static_condvar;
307 static_condvar = static_condvar_next)
309 static_condvar_next = static_condvar->next;
311 vlc_cond_destroy (&static_condvar->condvar);
312 free (static_condvar);
316 void vlc_cond_init (vlc_cond_t *p_condvar)
318 if (DosCreateEventSem (NULL, &p_condvar->hev, 0, FALSE) ||
319 DosCreateEventSem (NULL, &p_condvar->hevAck, 0, FALSE))
320 abort();
322 p_condvar->waiters = 0;
323 p_condvar->signaled = 0;
326 void vlc_cond_init_daytime (vlc_cond_t *p_condvar)
328 vlc_cond_init (p_condvar);
331 void vlc_cond_destroy (vlc_cond_t *p_condvar)
333 DosCloseEventSem( p_condvar->hev );
334 DosCloseEventSem( p_condvar->hevAck );
337 void vlc_cond_signal (vlc_cond_t *p_condvar)
339 if (p_condvar->hev == NULLHANDLE)
340 vlc_static_cond_init (p_condvar);
342 if (!__atomic_cmpxchg32 (&p_condvar->waiters, 0, 0))
344 ULONG ulPost;
346 __atomic_xchg (&p_condvar->signaled, 1);
347 DosPostEventSem (p_condvar->hev);
349 DosWaitEventSem (p_condvar->hevAck, SEM_INDEFINITE_WAIT);
350 DosResetEventSem (p_condvar->hevAck, &ulPost);
354 void vlc_cond_broadcast (vlc_cond_t *p_condvar)
356 if (p_condvar->hev == NULLHANDLE)
357 vlc_static_cond_init (p_condvar);
359 while (!__atomic_cmpxchg32 (&p_condvar->waiters, 0, 0))
360 vlc_cond_signal (p_condvar);
363 static int vlc_cond_wait_common (vlc_cond_t *p_condvar, vlc_mutex_t *p_mutex,
364 ULONG ulTimeout)
366 ULONG ulPost;
367 ULONG rc;
369 assert(p_condvar->hev != NULLHANDLE);
373 vlc_testcancel();
375 __atomic_increment (&p_condvar->waiters);
377 vlc_mutex_unlock (p_mutex);
381 rc = vlc_WaitForSingleObject( p_condvar->hev, ulTimeout );
382 if (rc == NO_ERROR)
383 DosResetEventSem (p_condvar->hev, &ulPost);
384 } while (rc == NO_ERROR &&
385 __atomic_cmpxchg32 (&p_condvar->signaled, 0, 1) == 0);
387 __atomic_decrement (&p_condvar->waiters);
389 DosPostEventSem (p_condvar->hevAck);
391 vlc_mutex_lock (p_mutex);
392 } while( rc == ERROR_INTERRUPT );
394 return rc ? ETIMEDOUT : 0;
397 void vlc_cond_wait (vlc_cond_t *p_condvar, vlc_mutex_t *p_mutex)
399 if (p_condvar->hev == NULLHANDLE)
400 vlc_static_cond_init (p_condvar);
402 vlc_cond_wait_common (p_condvar, p_mutex, SEM_INDEFINITE_WAIT);
405 int vlc_cond_timedwait (vlc_cond_t *p_condvar, vlc_mutex_t *p_mutex,
406 vlc_tick_t deadline)
408 ULONG ulTimeout;
410 vlc_tick_t total = vlc_tick_now();
411 total = (deadline - total) / 1000;
412 if( total < 0 )
413 total = 0;
415 ulTimeout = ( total > 0x7fffffff ) ? 0x7fffffff : total;
417 return vlc_cond_wait_common (p_condvar, p_mutex, ulTimeout);
420 int vlc_cond_timedwait_daytime (vlc_cond_t *p_condvar, vlc_mutex_t *p_mutex,
421 time_t deadline)
423 ULONG ulTimeout;
424 vlc_tick_t total;
425 struct timeval tv;
427 gettimeofday (&tv, NULL);
429 total = vlc_tick_from_timeval( &tv );
430 total = (deadline - total) / 1000;
431 if( total < 0 )
432 total = 0;
434 ulTimeout = ( total > 0x7fffffff ) ? 0x7fffffff : total;
436 return vlc_cond_wait_common (p_condvar, p_mutex, ulTimeout);
439 void vlc_once(vlc_once_t *once, void (*cb)(void))
441 unsigned done;
443 /* load once->done */
444 __atomic_xchg( &done, once->done );
446 /* not initialized ? */
447 if( done == 0 )
449 vlc_mutex_lock( &once->mutex );
451 /* load once->done */
452 __atomic_xchg( &done, once->done );
454 /* still not initialized ? */
455 if( done == 0 )
457 cb();
459 /* set once->done to 1 */
460 __atomic_xchg( &once->done, 1 );
463 vlc_mutex_unlock( &once->mutex );
467 /*** Thread-specific variables (TLS) ***/
468 struct vlc_threadvar
470 PULONG id;
471 void (*destroy) (void *);
472 struct vlc_threadvar *prev;
473 struct vlc_threadvar *next;
474 } *vlc_threadvar_last = NULL;
476 int vlc_threadvar_create (vlc_threadvar_t *p_tls, void (*destr) (void *))
478 ULONG rc;
480 struct vlc_threadvar *var = malloc (sizeof (*var));
481 if (unlikely(var == NULL))
482 return errno;
484 rc = DosAllocThreadLocalMemory( 1, &var->id );
485 if( rc )
487 free (var);
488 return EAGAIN;
491 var->destroy = destr;
492 var->next = NULL;
493 *p_tls = var;
495 vlc_mutex_lock (&super_mutex);
496 var->prev = vlc_threadvar_last;
497 if (var->prev)
498 var->prev->next = var;
500 vlc_threadvar_last = var;
501 vlc_mutex_unlock (&super_mutex);
502 return 0;
505 void vlc_threadvar_delete (vlc_threadvar_t *p_tls)
507 struct vlc_threadvar *var = *p_tls;
509 vlc_mutex_lock (&super_mutex);
510 if (var->prev != NULL)
511 var->prev->next = var->next;
513 if (var->next != NULL)
514 var->next->prev = var->prev;
515 else
516 vlc_threadvar_last = var->prev;
518 vlc_mutex_unlock (&super_mutex);
520 DosFreeThreadLocalMemory( var->id );
521 free (var);
524 int vlc_threadvar_set (vlc_threadvar_t key, void *value)
526 *key->id = ( ULONG )value;
527 return 0;
530 void *vlc_threadvar_get (vlc_threadvar_t key)
532 return ( void * )*key->id;
536 /*** Threads ***/
537 void vlc_threads_setup (libvlc_int_t *p_libvlc)
539 (void) p_libvlc;
542 static void vlc_thread_cleanup (struct vlc_thread *th)
544 vlc_threadvar_t key;
546 retry:
547 /* TODO: use RW lock or something similar */
548 vlc_mutex_lock (&super_mutex);
549 for (key = vlc_threadvar_last; key != NULL; key = key->prev)
551 void *value = vlc_threadvar_get (key);
552 if (value != NULL && key->destroy != NULL)
554 vlc_mutex_unlock (&super_mutex);
555 vlc_threadvar_set (key, NULL);
556 key->destroy (value);
557 goto retry;
560 vlc_mutex_unlock (&super_mutex);
562 if (th->detached)
564 DosCloseEventSem (th->cancel_event);
565 DosCloseEventSem (th->done_event );
567 soclose (th->cancel_sock);
569 free (th);
573 static void vlc_entry( void *p )
575 struct vlc_thread *th = p;
577 vlc_threadvar_set (thread_key, th);
578 th->killable = true;
579 th->data = th->entry (th->data);
580 DosPostEventSem( th->done_event );
581 vlc_thread_cleanup (th);
584 static int vlc_clone_attr (vlc_thread_t *p_handle, bool detached,
585 void *(*entry) (void *), void *data, int priority)
587 struct vlc_thread *th = malloc (sizeof (*th));
588 if (unlikely(th == NULL))
589 return ENOMEM;
590 th->entry = entry;
591 th->data = data;
592 th->detached = detached;
593 th->killable = false; /* not until vlc_entry() ! */
594 th->killed = false;
595 th->cleaners = NULL;
597 if( DosCreateEventSem (NULL, &th->cancel_event, 0, FALSE))
598 goto error;
599 if( DosCreateEventSem (NULL, &th->done_event, 0, FALSE))
600 goto error;
602 th->cancel_sock = socket (AF_LOCAL, SOCK_STREAM, 0);
603 if( th->cancel_sock < 0 )
604 goto error;
606 th->tid = _beginthread (vlc_entry, NULL, 1024 * 1024, th);
607 if((int)th->tid == -1)
608 goto error;
610 if (p_handle != NULL)
611 *p_handle = th;
613 if (priority)
614 DosSetPriority(PRTYS_THREAD,
615 HIBYTE(priority),
616 LOBYTE(priority),
617 th->tid);
619 return 0;
621 error:
622 soclose (th->cancel_sock);
623 DosCloseEventSem (th->cancel_event);
624 DosCloseEventSem (th->done_event);
625 free (th);
627 return ENOMEM;
630 int vlc_clone (vlc_thread_t *p_handle, void *(*entry) (void *),
631 void *data, int priority)
633 return vlc_clone_attr (p_handle, false, entry, data, priority);
636 void vlc_join (vlc_thread_t th, void **result)
638 ULONG rc;
642 vlc_testcancel();
643 rc = vlc_WaitForSingleObject( th->done_event, SEM_INDEFINITE_WAIT );
644 } while( rc == ERROR_INTERRUPT );
646 if (result != NULL)
647 *result = th->data;
649 DosCloseEventSem( th->cancel_event );
650 DosCloseEventSem( th->done_event );
652 soclose( th->cancel_sock );
654 free( th );
657 int vlc_clone_detach (vlc_thread_t *p_handle, void *(*entry) (void *),
658 void *data, int priority)
660 vlc_thread_t th;
661 if (p_handle == NULL)
662 p_handle = &th;
664 return vlc_clone_attr (p_handle, true, entry, data, priority);
667 int vlc_set_priority (vlc_thread_t th, int priority)
669 if (DosSetPriority(PRTYS_THREAD,
670 HIBYTE(priority),
671 LOBYTE(priority),
672 th->tid))
673 return VLC_EGENERIC;
674 return VLC_SUCCESS;
677 vlc_thread_t vlc_thread_self (void)
679 return vlc_threadvar_get (thread_key);
682 unsigned long vlc_thread_id (void)
684 return _gettid();
687 /*** Thread cancellation ***/
689 /* APC procedure for thread cancellation */
690 static void vlc_cancel_self (PVOID self)
692 struct vlc_thread *th = self;
694 if (likely(th != NULL))
695 th->killed = true;
698 void vlc_cancel (vlc_thread_t thread_id)
700 DosPostEventSem( thread_id->cancel_event );
701 so_cancel( thread_id->cancel_sock );
704 int vlc_savecancel (void)
706 int state;
708 struct vlc_thread *th = vlc_thread_self ();
709 if (th == NULL)
710 return false; /* Main thread - cannot be cancelled anyway */
712 state = th->killable;
713 th->killable = false;
714 return state;
717 void vlc_restorecancel (int state)
719 struct vlc_thread *th = vlc_thread_self ();
720 assert (state == false || state == true);
722 if (th == NULL)
723 return; /* Main thread - cannot be cancelled anyway */
725 assert (!th->killable);
726 th->killable = state != 0;
729 void vlc_testcancel (void)
731 struct vlc_thread *th = vlc_thread_self ();
732 if (th == NULL)
733 return; /* Main thread - cannot be cancelled anyway */
735 /* This check is needed for the case that vlc_cancel() is followed by
736 * vlc_testcancel() without any cancellation point */
737 if( DosWaitEventSem( th->cancel_event, 0 ) == NO_ERROR )
738 vlc_cancel_self( th );
740 if (th->killable && th->killed)
742 for (vlc_cleanup_t *p = th->cleaners; p != NULL; p = p->next)
743 p->proc (p->data);
745 DosPostEventSem( th->done_event );
746 th->data = NULL; /* TODO: special value? */
747 vlc_thread_cleanup (th);
748 _endthread();
752 void vlc_control_cancel (int cmd, ...)
754 /* NOTE: This function only modifies thread-specific data, so there is no
755 * need to lock anything. */
756 va_list ap;
758 struct vlc_thread *th = vlc_thread_self ();
759 if (th == NULL)
760 return; /* Main thread - cannot be cancelled anyway */
762 va_start (ap, cmd);
763 switch (cmd)
765 case VLC_CLEANUP_PUSH:
767 /* cleaner is a pointer to the caller stack, no need to allocate
768 * and copy anything. As a nice side effect, this cannot fail. */
769 vlc_cleanup_t *cleaner = va_arg (ap, vlc_cleanup_t *);
770 cleaner->next = th->cleaners;
771 th->cleaners = cleaner;
772 break;
775 case VLC_CLEANUP_POP:
777 th->cleaners = th->cleaners->next;
778 break;
781 va_end (ap);
784 static int vlc_select( int nfds, fd_set *rdset, fd_set *wrset, fd_set *exset,
785 struct timeval *timeout )
787 struct vlc_thread *th = vlc_thread_self( );
789 int rc;
791 if( th )
793 FD_SET( th->cancel_sock, rdset );
795 nfds = MAX( nfds, th->cancel_sock + 1 );
798 rc = select( nfds, rdset, wrset, exset, timeout );
800 vlc_testcancel();
802 return rc;
806 /* Export vlc_poll_os2 directly regardless of EXPORTS of .def */
807 __declspec(dllexport)
808 int vlc_poll_os2( struct pollfd *fds, unsigned nfds, int timeout );
810 __declspec(dllexport)
811 int vlc_poll_os2( struct pollfd *fds, unsigned nfds, int timeout )
813 fd_set rdset, wrset, exset;
815 int non_sockets = 0;
817 struct timeval tv = { 0, 0 };
819 int val = -1;
821 FD_ZERO( &rdset );
822 FD_ZERO( &wrset );
823 FD_ZERO( &exset );
824 for( unsigned i = 0; i < nfds; i++ )
826 int fd = fds[ i ].fd;
827 struct stat stbuf;
829 fds[ i ].revents = 0;
831 if( fstat( fd, &stbuf ) == -1 ||
832 (errno = 0, !S_ISSOCK( stbuf.st_mode )))
834 if( fd >= 0 )
836 /* If regular files, assume readiness for requested modes */
837 fds[ i ].revents = ( !errno && S_ISREG( stbuf.st_mode ))
838 ? ( fds[ i ].events &
839 ( POLLIN | POLLOUT | POLLPRI ))
840 : POLLNVAL;
842 non_sockets++;
845 continue;
848 if( val < fd )
849 val = fd;
851 if(( unsigned )fd >= FD_SETSIZE )
853 errno = EINVAL;
854 return -1;
857 if( fds[ i ].events & POLLIN )
858 FD_SET( fd, &rdset );
859 if( fds[ i ].events & POLLOUT )
860 FD_SET( fd, &wrset );
861 if( fds[ i ].events & POLLPRI )
862 FD_SET( fd, &exset );
865 if( non_sockets > 0 )
866 timeout = 0; /* Just check pending sockets */
868 /* Sockets included ? */
869 if( val != -1)
871 struct timeval *ptv = NULL;
873 if( timeout >= 0 )
875 div_t d = div( timeout, 1000 );
876 tv.tv_sec = d.quot;
877 tv.tv_usec = d.rem * 1000;
879 ptv = &tv;
882 if (vlc_select( val + 1, &rdset, &wrset, &exset, ptv ) == -1)
883 return -1;
886 val = 0;
887 for( unsigned i = 0; i < nfds; i++ )
889 int fd = fds[ i ].fd;
891 if( fd >= 0 && fds[ i ].revents == 0 )
893 fds[ i ].revents = ( FD_ISSET( fd, &rdset ) ? POLLIN : 0 )
894 | ( FD_ISSET( fd, &wrset ) ? POLLOUT : 0 )
895 | ( FD_ISSET( fd, &exset ) ? POLLPRI : 0 );
898 if( fds[ i ].revents != 0 )
899 val++;
902 return val;
905 #define Q2LL( q ) ( *( long long * )&( q ))
907 /*** Clock ***/
908 vlc_tick_t vlc_tick_now (void)
910 /* We don't need the real date, just the value of a high precision timer */
911 QWORD counter;
912 ULONG freq;
913 if (DosTmrQueryTime(&counter) || DosTmrQueryFreq(&freq))
914 abort();
916 /* Convert to from (1/freq) to microsecond resolution */
917 /* We need to split the division to avoid 63-bits overflow */
918 lldiv_t d = lldiv (Q2LL(counter), freq);
920 return vlc_tick_from_sec( d.quot ) + vlc_tick_from_samples(d.rem, freq);
923 #undef vlc_tick_wait
924 void vlc_tick_wait (vlc_tick_t deadline)
926 vlc_tick_t delay;
928 vlc_testcancel();
929 while ((delay = (deadline - vlc_tick_now())) > 0)
931 delay /= 1000;
932 if (unlikely(delay > 0x7fffffff))
933 delay = 0x7fffffff;
934 vlc_Sleep (delay);
935 vlc_testcancel();
939 #undef vlc_tick_sleep
940 void vlc_tick_sleep (vlc_tick_t delay)
942 vlc_tick_wait (vlc_tick_now () + delay);
945 /*** Timers ***/
946 struct vlc_timer
948 TID tid;
949 HEV hev;
950 HTIMER htimer;
951 ULONG interval;
952 bool quit;
953 void (*func) (void *);
954 void *data;
957 static void vlc_timer_do (void *arg)
959 struct vlc_timer *timer = arg;
961 while (1)
963 ULONG count;
965 DosWaitEventSem (timer->hev, SEM_INDEFINITE_WAIT);
966 DosResetEventSem (timer->hev, &count);
968 if (timer->quit)
969 break;
971 timer->func (timer->data);
973 if (timer->interval)
974 DosAsyncTimer (timer->interval, (HSEM)timer->hev, &timer->htimer);
978 int vlc_timer_create (vlc_timer_t *id, void (*func) (void *), void *data)
980 struct vlc_timer *timer = malloc (sizeof (*timer));
982 if (timer == NULL)
983 return ENOMEM;
985 timer->func = func;
986 timer->data = data;
988 DosCreateEventSem (NULL, &timer->hev, DC_SEM_SHARED, FALSE);
989 timer->htimer = NULLHANDLE;
990 timer->interval = 0;
991 timer->quit = false;
992 timer->tid = _beginthread (vlc_timer_do, NULL, 1024 * 1024, timer);
994 *id = timer;
995 return 0;
998 void vlc_timer_destroy (vlc_timer_t timer)
1000 if (timer->htimer != NULLHANDLE)
1001 DosStopTimer (timer->htimer);
1003 timer->quit = true;
1004 DosPostEventSem (timer->hev);
1005 DosWaitThread (&timer->tid, DCWW_WAIT);
1006 DosCloseEventSem (timer->hev);
1008 free (timer);
1011 void vlc_timer_schedule (vlc_timer_t timer, bool absolute,
1012 vlc_tick_t value, vlc_tick_t interval)
1014 if (timer->htimer != NULLHANDLE)
1016 DosStopTimer (timer->htimer);
1017 timer->htimer = NULLHANDLE;
1018 timer->interval = 0;
1021 if (value == VLC_TIMER_DISARM)
1022 return; /* Disarm */
1024 if (absolute)
1025 value -= vlc_tick_now ();
1026 value = (value + 999) / 1000;
1027 interval = (interval + 999) / 1000;
1029 timer->interval = MS_FROM_VLC_TICK(interval);
1030 if (DosAsyncTimer (MS_FROM_VLC_TICK(value), (HSEM)timer->hev, &timer->htimer))
1031 abort ();
1034 unsigned vlc_timer_getoverrun (vlc_timer_t timer)
1036 (void)timer;
1037 return 0;
1040 /*** CPU ***/
1041 unsigned vlc_GetCPUCount (void)
1043 ULONG numprocs = 1;
1045 DosQuerySysInfo(QSV_NUMPROCESSORS, QSV_NUMPROCESSORS,
1046 &numprocs, sizeof(numprocs));
1048 return numprocs;