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>
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 *****************************************************************************/
33 #include <vlc_common.h>
42 #include <sys/types.h>
43 #ifdef HAVE_SYS_SOCKET_H
44 #include <sys/socket.h>
48 #include <sys/select.h>
50 #include <sys/builtin.h>
54 static vlc_threadvar_t thread_key
;
66 vlc_cleanup_t
*cleaners
;
68 void *(*entry
) (void *);
72 static void vlc_cancel_self (PVOID dummy
);
74 static ULONG
vlc_DosWaitEventSemEx( HEV hev
, ULONG ulTimeout
)
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
);
96 if( hev
!= NULLHANDLE
)
98 asr
[ n
].hsemCur
= ( HSEM
)hev
;
102 asr
[ n
].hsemCur
= ( HSEM
)th
->cancel_event
;
103 asr
[ n
].ulUser
= 0xFFFF;
106 DosCreateMuxWaitSem( NULL
, &hmux
, n
, asr
, DCMW_WAIT_ANY
);
107 rc
= DosWaitMuxWaitSem( hmux
, ulTimeout
, &ulUser
);
108 DosCloseMuxWaitSem( hmux
);
112 if( ulUser
== 0xFFFF )
114 vlc_cancel_self( th
);
115 return ERROR_INTERRUPT
;
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);
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
)
150 case 0 : /* Initialization */
151 if(_CRT_init() == -1)
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
);
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 ();
173 return 0; /* Failed */
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
);
217 DosRequestMutexSem(p_mutex
->hmtx
, SEM_INDEFINITE_WAIT
);
219 vlc_mutex_mark(p_mutex
);
222 int vlc_mutex_trylock (vlc_mutex_t
*p_mutex
)
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;
237 vlc_mutex_unlock (&super_mutex
);
240 ret
= DosRequestMutexSem( p_mutex
->hmtx
, 0 ) ? EBUSY
: 0;
243 vlc_mutex_mark(p_mutex
);
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
);
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
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
))
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
))
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))
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
,
369 assert(p_condvar
->hev
!= NULLHANDLE
);
375 __atomic_increment (&p_condvar
->waiters
);
377 vlc_mutex_unlock (p_mutex
);
381 rc
= vlc_WaitForSingleObject( p_condvar
->hev
, ulTimeout
);
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
,
410 vlc_tick_t total
= vlc_tick_now();
411 total
= (deadline
- total
) / 1000;
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
,
427 gettimeofday (&tv
, NULL
);
429 total
= vlc_tick_from_timeval( &tv
);
430 total
= (deadline
- total
) / 1000;
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))
443 /* load once->done */
444 __atomic_xchg( &done
, once
->done
);
446 /* not initialized ? */
449 vlc_mutex_lock( &once
->mutex
);
451 /* load once->done */
452 __atomic_xchg( &done
, once
->done
);
454 /* still not initialized ? */
459 /* set once->done to 1 */
460 __atomic_xchg( &once
->done
, 1 );
463 vlc_mutex_unlock( &once
->mutex
);
467 /*** Thread-specific variables (TLS) ***/
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 *))
480 struct vlc_threadvar
*var
= malloc (sizeof (*var
));
481 if (unlikely(var
== NULL
))
484 rc
= DosAllocThreadLocalMemory( 1, &var
->id
);
491 var
->destroy
= destr
;
495 vlc_mutex_lock (&super_mutex
);
496 var
->prev
= vlc_threadvar_last
;
498 var
->prev
->next
= var
;
500 vlc_threadvar_last
= var
;
501 vlc_mutex_unlock (&super_mutex
);
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
;
516 vlc_threadvar_last
= var
->prev
;
518 vlc_mutex_unlock (&super_mutex
);
520 DosFreeThreadLocalMemory( var
->id
);
524 int vlc_threadvar_set (vlc_threadvar_t key
, void *value
)
526 *key
->id
= ( ULONG
)value
;
530 void *vlc_threadvar_get (vlc_threadvar_t key
)
532 return ( void * )*key
->id
;
537 void vlc_threads_setup (libvlc_int_t
*p_libvlc
)
542 static void vlc_thread_cleanup (struct vlc_thread
*th
)
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
);
560 vlc_mutex_unlock (&super_mutex
);
564 DosCloseEventSem (th
->cancel_event
);
565 DosCloseEventSem (th
->done_event
);
567 soclose (th
->cancel_sock
);
573 static void vlc_entry( void *p
)
575 struct vlc_thread
*th
= p
;
577 vlc_threadvar_set (thread_key
, th
);
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
))
592 th
->detached
= detached
;
593 th
->killable
= false; /* not until vlc_entry() ! */
597 if( DosCreateEventSem (NULL
, &th
->cancel_event
, 0, FALSE
))
599 if( DosCreateEventSem (NULL
, &th
->done_event
, 0, FALSE
))
602 th
->cancel_sock
= socket (AF_LOCAL
, SOCK_STREAM
, 0);
603 if( th
->cancel_sock
< 0 )
606 th
->tid
= _beginthread (vlc_entry
, NULL
, 1024 * 1024, th
);
607 if((int)th
->tid
== -1)
610 if (p_handle
!= NULL
)
614 DosSetPriority(PRTYS_THREAD
,
622 soclose (th
->cancel_sock
);
623 DosCloseEventSem (th
->cancel_event
);
624 DosCloseEventSem (th
->done_event
);
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
)
643 rc
= vlc_WaitForSingleObject( th
->done_event
, SEM_INDEFINITE_WAIT
);
644 } while( rc
== ERROR_INTERRUPT
);
649 DosCloseEventSem( th
->cancel_event
);
650 DosCloseEventSem( th
->done_event
);
652 soclose( th
->cancel_sock
);
657 int vlc_clone_detach (vlc_thread_t
*p_handle
, void *(*entry
) (void *),
658 void *data
, int priority
)
661 if (p_handle
== NULL
)
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
,
677 vlc_thread_t
vlc_thread_self (void)
679 return vlc_threadvar_get (thread_key
);
682 unsigned long vlc_thread_id (void)
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
))
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)
708 struct vlc_thread
*th
= vlc_thread_self ();
710 return false; /* Main thread - cannot be cancelled anyway */
712 state
= th
->killable
;
713 th
->killable
= false;
717 void vlc_restorecancel (int state
)
719 struct vlc_thread
*th
= vlc_thread_self ();
720 assert (state
== false || state
== true);
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 ();
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
)
745 DosPostEventSem( th
->done_event
);
746 th
->data
= NULL
; /* TODO: special value? */
747 vlc_thread_cleanup (th
);
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. */
758 struct vlc_thread
*th
= vlc_thread_self ();
760 return; /* Main thread - cannot be cancelled anyway */
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
;
775 case VLC_CLEANUP_POP
:
777 th
->cleaners
= th
->cleaners
->next
;
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( );
793 FD_SET( th
->cancel_sock
, rdset
);
795 nfds
= MAX( nfds
, th
->cancel_sock
+ 1 );
798 rc
= select( nfds
, rdset
, wrset
, exset
, timeout
);
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
;
817 struct timeval tv
= { 0, 0 };
824 for( unsigned i
= 0; i
< nfds
; i
++ )
826 int fd
= fds
[ i
].fd
;
829 fds
[ i
].revents
= 0;
831 if( fstat( fd
, &stbuf
) == -1 ||
832 (errno
= 0, !S_ISSOCK( stbuf
.st_mode
)))
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
))
851 if(( unsigned )fd
>= FD_SETSIZE
)
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 ? */
871 struct timeval
*ptv
= NULL
;
875 div_t d
= div( timeout
, 1000 );
877 tv
.tv_usec
= d
.rem
* 1000;
882 if (vlc_select( val
+ 1, &rdset
, &wrset
, &exset
, ptv
) == -1)
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 )
905 #define Q2LL( q ) ( *( long long * )&( q ))
908 vlc_tick_t
vlc_tick_now (void)
910 /* We don't need the real date, just the value of a high precision timer */
913 if (DosTmrQueryTime(&counter
) || DosTmrQueryFreq(&freq
))
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
);
924 void vlc_tick_wait (vlc_tick_t deadline
)
929 while ((delay
= (deadline
- vlc_tick_now())) > 0)
932 if (unlikely(delay
> 0x7fffffff))
939 #undef vlc_tick_sleep
940 void vlc_tick_sleep (vlc_tick_t delay
)
942 vlc_tick_wait (vlc_tick_now () + delay
);
953 void (*func
) (void *);
957 static void vlc_timer_do (void *arg
)
959 struct vlc_timer
*timer
= arg
;
965 DosWaitEventSem (timer
->hev
, SEM_INDEFINITE_WAIT
);
966 DosResetEventSem (timer
->hev
, &count
);
971 timer
->func (timer
->data
);
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
));
988 DosCreateEventSem (NULL
, &timer
->hev
, DC_SEM_SHARED
, FALSE
);
989 timer
->htimer
= NULLHANDLE
;
992 timer
->tid
= _beginthread (vlc_timer_do
, NULL
, 1024 * 1024, timer
);
998 void vlc_timer_destroy (vlc_timer_t timer
)
1000 if (timer
->htimer
!= NULLHANDLE
)
1001 DosStopTimer (timer
->htimer
);
1004 DosPostEventSem (timer
->hev
);
1005 DosWaitThread (&timer
->tid
, DCWW_WAIT
);
1006 DosCloseEventSem (timer
->hev
);
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 */
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
))
1034 unsigned vlc_timer_getoverrun (vlc_timer_t timer
)
1041 unsigned vlc_GetCPUCount (void)
1045 DosQuerySysInfo(QSV_NUMPROCESSORS
, QSV_NUMPROCESSORS
,
1046 &numprocs
, sizeof(numprocs
));