Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
V
vlc
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Redmine
Redmine
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
videolan
vlc
Commits
86df8c04
Commit
86df8c04
authored
Oct 11, 2011
by
KO Myung-Hun
Committed by
Rémi Denis-Courmont
Oct 14, 2011
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Implement thread support for OS/2
Signed-off-by:
Rémi Denis-Courmont
<
remi@remlab.net
>
parent
de6f5699
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
1030 additions
and
0 deletions
+1030
-0
include/vlc_common.h
include/vlc_common.h
+7
-0
include/vlc_threads.h
include/vlc_threads.h
+63
-0
src/Makefile.am
src/Makefile.am
+13
-0
src/os2/thread.c
src/os2/thread.c
+947
-0
No files found.
include/vlc_common.h
View file @
86df8c04
...
@@ -476,6 +476,13 @@ typedef int ( * vlc_callback_t ) ( vlc_object_t *, /* variable's object */
...
@@ -476,6 +476,13 @@ typedef int ( * vlc_callback_t ) ( vlc_object_t *, /* variable's object */
# include <windows.h>
# include <windows.h>
#endif
#endif
#ifdef __OS2__
# define OS2EMX_PLAIN_CHAR
# define INCL_BASE
# define INCL_PM
# include <os2.h>
#endif
#include "vlc_mtime.h"
#include "vlc_mtime.h"
#include "vlc_threads.h"
#include "vlc_threads.h"
...
...
include/vlc_threads.h
View file @
86df8c04
...
@@ -38,6 +38,11 @@
...
@@ -38,6 +38,11 @@
#elif defined( WIN32 )
#elif defined( WIN32 )
# include <process.h>
/* Win32 API */
# include <process.h>
/* Win32 API */
#elif defined( __OS2__ )
/* OS/2 API */
# include <errno.h>
# define pthread_sigmask sigprocmask
#else
/* pthreads (like Linux & BSD) */
#else
/* pthreads (like Linux & BSD) */
# define LIBVLC_USE_PTHREAD 1
# define LIBVLC_USE_PTHREAD 1
# define LIBVLC_USE_PTHREAD_CANCEL 1
# define LIBVLC_USE_PTHREAD_CANCEL 1
...
@@ -90,6 +95,14 @@
...
@@ -90,6 +95,14 @@
# define VLC_THREAD_PRIORITY_HIGHEST \
# define VLC_THREAD_PRIORITY_HIGHEST \
THREAD_PRIORITY_TIME_CRITICAL
THREAD_PRIORITY_TIME_CRITICAL
#elif defined(__OS2__)
# define VLC_THREAD_PRIORITY_LOW 0
# define VLC_THREAD_PRIORITY_INPUT MAKESHORT( PRTYD_MAXIMUM / 2, PRTYC_REGULAR )
# define VLC_THREAD_PRIORITY_AUDIO MAKESHORT( PRTYD_MAXIMUM, PRTYC_REGULAR )
# define VLC_THREAD_PRIORITY_VIDEO 0
# define VLC_THREAD_PRIORITY_OUTPUT MAKESHORT( PRTYD_MAXIMUM / 2, PRTYC_REGULAR )
# define VLC_THREAD_PRIORITY_HIGHEST MAKESHORT( 0, PRTYC_TIMECRITICAL )
#else
#else
# define VLC_THREAD_PRIORITY_LOW 0
# define VLC_THREAD_PRIORITY_LOW 0
# define VLC_THREAD_PRIORITY_INPUT 0
# define VLC_THREAD_PRIORITY_INPUT 0
...
@@ -161,6 +174,56 @@ typedef struct
...
@@ -161,6 +174,56 @@ typedef struct
typedef
struct
vlc_threadvar
*
vlc_threadvar_t
;
typedef
struct
vlc_threadvar
*
vlc_threadvar_t
;
typedef
struct
vlc_timer
*
vlc_timer_t
;
typedef
struct
vlc_timer
*
vlc_timer_t
;
#elif defined( __OS2__ )
typedef
struct
vlc_thread
*
vlc_thread_t
;
typedef
struct
{
bool
dynamic
;
union
{
struct
{
bool
locked
;
unsigned
long
contention
;
};
HMTX
hmtx
;
}
;
}
vlc_mutex_t
;
#define VLC_STATIC_MUTEX { false, { { false, 0 } } }
typedef
struct
{
HEV
hev
;
unsigned
clock
;
}
vlc_cond_t
;
#define VLC_STATIC_COND { 0, 0 }
typedef
struct
{
HEV
hev
;
HMTX
wait_mutex
;
HMTX
count_mutex
;
int
count
;
}
vlc_sem_t
;
typedef
struct
{
vlc_mutex_t
mutex
;
vlc_cond_t
wait
;
unsigned
long
readers
;
unsigned
long
writers
;
int
writer
;
}
vlc_rwlock_t
;
#define VLC_STATIC_RWLOCK \
{ VLC_STATIC_MUTEX, VLC_STATIC_COND, 0, 0, 0 }
typedef
struct
vlc_threadvar
*
vlc_threadvar_t
;
typedef
struct
vlc_timer
*
vlc_timer_t
;
#endif
#endif
#if defined( WIN32 ) && !defined ETIMEDOUT
#if defined( WIN32 ) && !defined ETIMEDOUT
...
...
src/Makefile.am
View file @
86df8c04
...
@@ -197,6 +197,7 @@ EXTRA_libvlccore_la_SOURCES = \
...
@@ -197,6 +197,7 @@ EXTRA_libvlccore_la_SOURCES = \
$(SOURCES_libvlc_darwin)
\
$(SOURCES_libvlc_darwin)
\
$(SOURCES_libvlc_linux)
\
$(SOURCES_libvlc_linux)
\
$(SOURCES_libvlc_win32)
\
$(SOURCES_libvlc_win32)
\
$(SOURCES_libvlc_os2)
\
$(SOURCES_libvlc_other)
\
$(SOURCES_libvlc_other)
\
$(SOURCES_libvlc_httpd)
\
$(SOURCES_libvlc_httpd)
\
$(SOURCES_libvlc_sout)
\
$(SOURCES_libvlc_sout)
\
...
@@ -217,12 +218,16 @@ else
...
@@ -217,12 +218,16 @@ else
if
HAVE_SYMBIAN
if
HAVE_SYMBIAN
#libvlccore_la_SOURCES += $(SOURCES_libvlc_symbian)
#libvlccore_la_SOURCES += $(SOURCES_libvlc_symbian)
else
else
if
HAVE_OS2
libvlccore_la_SOURCES
+=
$(SOURCES_libvlc_os2)
else
libvlccore_la_SOURCES
+=
$(SOURCES_libvlc_other)
libvlccore_la_SOURCES
+=
$(SOURCES_libvlc_other)
endif
endif
endif
endif
endif
endif
endif
endif
endif
endif
endif
if
BUILD_HTTPD
if
BUILD_HTTPD
libvlccore_la_SOURCES
+=
$(SOURCES_libvlc_httpd)
libvlccore_la_SOURCES
+=
$(SOURCES_libvlc_httpd)
endif
endif
...
@@ -271,6 +276,14 @@ SOURCES_libvlc_symbian = \
...
@@ -271,6 +276,14 @@ SOURCES_libvlc_symbian = \
win32/plugin.c
\
win32/plugin.c
\
$(NULL)
$(NULL)
SOURCES_libvlc_os2
=
\
posix/dirs.c
\
misc/atomic.c
\
posix/filesystem.c
\
os2/thread.c
\
posix/specific.c
\
$(NULL)
SOURCES_libvlc_other
=
\
SOURCES_libvlc_other
=
\
posix/dirs.c
\
posix/dirs.c
\
misc/atomic.c
\
misc/atomic.c
\
...
...
src/os2/thread.c
0 → 100644
View file @
86df8c04
/*****************************************************************************
* thread.c : OS/2 back-end for LibVLC
*****************************************************************************
* Copyright (C) 1999-2011 the VideoLAN team
*
* Authors: KO Myung-Hun <komh@chollian.net>
* Jean-Marc Dressler <polux@via.ecp.fr>
* Samuel Hocevar <sam@zoy.org>
* Gildas Bazin <gbazin@netcourrier.com>
* Clément Sténac
* Rémi Denis-Courmont
* Pierre Ynard
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <vlc_common.h>
#include "libvlc.h"
#include <stdarg.h>
#include <assert.h>
#include <limits.h>
#include <errno.h>
#include <time.h>
static
vlc_threadvar_t
thread_key
;
/**
* Per-thread data
*/
struct
vlc_thread
{
TID
tid
;
HEV
cancel_event
;
HEV
done_event
;
bool
detached
;
bool
killable
;
bool
killed
;
vlc_cleanup_t
*
cleaners
;
void
*
(
*
entry
)
(
void
*
);
void
*
data
;
};
static
void
vlc_cancel_self
(
PVOID
dummy
);
static
ULONG
vlc_DosWaitEventSemEx
(
HEV
hev
,
ULONG
ulTimeout
,
BOOL
fCancelable
)
{
HMUX
hmux
;
SEMRECORD
asr
[
2
];
ULONG
ulUser
;
int
n
;
ULONG
rc
;
struct
vlc_thread
*
th
=
vlc_threadvar_get
(
thread_key
);
if
(
th
==
NULL
||
!
fCancelable
)
{
/* Main thread - cannot be cancelled anyway */
return
DosWaitEventSem
(
hev
,
ulTimeout
);
}
n
=
0
;
if
(
hev
!=
NULLHANDLE
)
{
asr
[
n
].
hsemCur
=
(
HSEM
)
hev
;
asr
[
n
].
ulUser
=
0
;
n
++
;
}
asr
[
n
].
hsemCur
=
(
HSEM
)
th
->
cancel_event
;
asr
[
n
].
ulUser
=
0xFFFF
;
n
++
;
DosCreateMuxWaitSem
(
NULL
,
&
hmux
,
n
,
asr
,
DCMW_WAIT_ANY
);
rc
=
DosWaitMuxWaitSem
(
hmux
,
ulTimeout
,
&
ulUser
);
DosCloseMuxWaitSem
(
hmux
);
if
(
rc
)
return
rc
;
if
(
ulUser
==
0xFFFF
)
{
vlc_cancel_self
(
th
);
return
ERROR_INTERRUPT
;
}
return
NO_ERROR
;
}
static
ULONG
vlc_WaitForSingleObject
(
HEV
hev
,
ULONG
ulTimeout
)
{
return
vlc_DosWaitEventSemEx
(
hev
,
ulTimeout
,
TRUE
);
}
static
ULONG
vlc_Sleep
(
ULONG
ulTimeout
)
{
ULONG
rc
=
vlc_DosWaitEventSemEx
(
NULLHANDLE
,
ulTimeout
,
TRUE
);
return
(
rc
!=
ERROR_TIMEOUT
)
?
rc
:
0
;
}
vlc_mutex_t
super_mutex
;
vlc_cond_t
super_variable
;
extern
vlc_rwlock_t
config_lock
,
msg_lock
;
int
_CRT_init
(
void
);
void
_CRT_term
(
void
);
unsigned
long
_System
_DLL_InitTerm
(
unsigned
long
,
unsigned
long
);
unsigned
long
_System
_DLL_InitTerm
(
unsigned
long
hmod
,
unsigned
long
flag
)
{
VLC_UNUSED
(
hmod
);
switch
(
flag
)
{
case
0
:
/* Initialization */
if
(
_CRT_init
()
==
-
1
)
return
0
;
vlc_mutex_init
(
&
super_mutex
);
vlc_cond_init
(
&
super_variable
);
vlc_threadvar_create
(
&
thread_key
,
NULL
);
vlc_rwlock_init
(
&
config_lock
);
vlc_rwlock_init
(
&
msg_lock
);
vlc_CPU_init
();
return
1
;
case
1
:
/* Termination */
vlc_rwlock_destroy
(
&
msg_lock
);
vlc_rwlock_destroy
(
&
config_lock
);
vlc_threadvar_delete
(
&
thread_key
);
vlc_cond_destroy
(
&
super_variable
);
vlc_mutex_destroy
(
&
super_mutex
);
_CRT_term
();
return
1
;
}
return
0
;
/* Failed */
}
/*** Mutexes ***/
void
vlc_mutex_init
(
vlc_mutex_t
*
p_mutex
)
{
/* This creates a recursive mutex. This is OK as fast mutexes have
* no defined behavior in case of recursive locking. */
DosCreateMutexSem
(
NULL
,
&
p_mutex
->
hmtx
,
0
,
FALSE
);
p_mutex
->
dynamic
=
true
;
}
void
vlc_mutex_init_recursive
(
vlc_mutex_t
*
p_mutex
)
{
DosCreateMutexSem
(
NULL
,
&
p_mutex
->
hmtx
,
0
,
FALSE
);
p_mutex
->
dynamic
=
true
;
}
void
vlc_mutex_destroy
(
vlc_mutex_t
*
p_mutex
)
{
assert
(
p_mutex
->
dynamic
);
DosCloseMutexSem
(
p_mutex
->
hmtx
);
}
void
vlc_mutex_lock
(
vlc_mutex_t
*
p_mutex
)
{
if
(
!
p_mutex
->
dynamic
)
{
/* static mutexes */
int
canc
=
vlc_savecancel
();
assert
(
p_mutex
!=
&
super_mutex
);
/* this one cannot be static */
vlc_mutex_lock
(
&
super_mutex
);
while
(
p_mutex
->
locked
)
{
p_mutex
->
contention
++
;
vlc_cond_wait
(
&
super_variable
,
&
super_mutex
);
p_mutex
->
contention
--
;
}
p_mutex
->
locked
=
true
;
vlc_mutex_unlock
(
&
super_mutex
);
vlc_restorecancel
(
canc
);
return
;
}
DosRequestMutexSem
(
p_mutex
->
hmtx
,
SEM_INDEFINITE_WAIT
);
}
int
vlc_mutex_trylock
(
vlc_mutex_t
*
p_mutex
)
{
if
(
!
p_mutex
->
dynamic
)
{
/* static mutexes */
int
ret
=
EBUSY
;
assert
(
p_mutex
!=
&
super_mutex
);
/* this one cannot be static */
vlc_mutex_lock
(
&
super_mutex
);
if
(
!
p_mutex
->
locked
)
{
p_mutex
->
locked
=
true
;
ret
=
0
;
}
vlc_mutex_unlock
(
&
super_mutex
);
return
ret
;
}
return
DosRequestMutexSem
(
p_mutex
->
hmtx
,
0
)
?
EBUSY
:
0
;
}
void
vlc_mutex_unlock
(
vlc_mutex_t
*
p_mutex
)
{
if
(
!
p_mutex
->
dynamic
)
{
/* static mutexes */
assert
(
p_mutex
!=
&
super_mutex
);
/* this one cannot be static */
vlc_mutex_lock
(
&
super_mutex
);
assert
(
p_mutex
->
locked
);
p_mutex
->
locked
=
false
;
if
(
p_mutex
->
contention
)
vlc_cond_broadcast
(
&
super_variable
);
vlc_mutex_unlock
(
&
super_mutex
);
return
;
}
DosReleaseMutexSem
(
p_mutex
->
hmtx
);
}
/*** Condition variables ***/
enum
{
CLOCK_REALTIME
=
0
,
/* must be zero for VLC_STATIC_COND */
CLOCK_MONOTONIC
,
};
static
void
vlc_cond_init_common
(
vlc_cond_t
*
p_condvar
,
unsigned
clock
)
{
/* Create a manual-reset event (manual reset is needed for broadcast). */
if
(
DosCreateEventSem
(
NULL
,
&
p_condvar
->
hev
,
0
,
FALSE
))
abort
();
p_condvar
->
clock
=
clock
;
}
void
vlc_cond_init
(
vlc_cond_t
*
p_condvar
)
{
vlc_cond_init_common
(
p_condvar
,
CLOCK_MONOTONIC
);
}
void
vlc_cond_init_daytime
(
vlc_cond_t
*
p_condvar
)
{
vlc_cond_init_common
(
p_condvar
,
CLOCK_REALTIME
);
}
void
vlc_cond_destroy
(
vlc_cond_t
*
p_condvar
)
{
DosCloseEventSem
(
p_condvar
->
hev
);
}
void
vlc_cond_signal
(
vlc_cond_t
*
p_condvar
)
{
if
(
!
p_condvar
->
hev
)
return
;
/* This is suboptimal but works. */
vlc_cond_broadcast
(
p_condvar
);
}
void
vlc_cond_broadcast
(
vlc_cond_t
*
p_condvar
)
{
if
(
!
p_condvar
->
hev
)
return
;
/* Wake all threads up (as the event HANDLE has manual reset) */
DosPostEventSem
(
p_condvar
->
hev
);
}
void
vlc_cond_wait
(
vlc_cond_t
*
p_condvar
,
vlc_mutex_t
*
p_mutex
)
{
ULONG
ulPost
;
ULONG
rc
;
if
(
!
p_condvar
->
hev
)
{
/* FIXME FIXME FIXME */
msleep
(
50000
);
return
;
}
do
{
vlc_testcancel
();
vlc_mutex_unlock
(
p_mutex
);
rc
=
vlc_WaitForSingleObject
(
p_condvar
->
hev
,
SEM_INDEFINITE_WAIT
);
vlc_mutex_lock
(
p_mutex
);
}
while
(
rc
==
ERROR_INTERRUPT
);
DosResetEventSem
(
p_condvar
->
hev
,
&
ulPost
);
}
int
vlc_cond_timedwait
(
vlc_cond_t
*
p_condvar
,
vlc_mutex_t
*
p_mutex
,
mtime_t
deadline
)
{
ULONG
ulTimeout
;
ULONG
ulPost
;
ULONG
rc
;
if
(
!
p_condvar
->
hev
)
{
/* FIXME FIXME FIXME */
msleep
(
50000
);
return
;
}
do
{
vlc_testcancel
();
mtime_t
total
;
switch
(
p_condvar
->
clock
)
{
case
CLOCK_REALTIME
:
/* FIXME? sub-second precision */
total
=
CLOCK_FREQ
*
time
(
NULL
);
break
;
default:
assert
(
p_condvar
->
clock
==
CLOCK_MONOTONIC
);
total
=
mdate
();
break
;
}
total
=
(
deadline
-
total
)
/
1000
;
if
(
total
<
0
)
total
=
0
;
ulTimeout
=
(
total
>
0x7fffffff
)
?
0x7fffffff
:
total
;
vlc_mutex_unlock
(
p_mutex
);
rc
=
vlc_WaitForSingleObject
(
p_condvar
->
hev
,
ulTimeout
);
vlc_mutex_lock
(
p_mutex
);
}
while
(
rc
==
ERROR_INTERRUPT
);
DosResetEventSem
(
p_condvar
->
hev
,
&
ulPost
);
return
rc
?
ETIMEDOUT
:
0
;
}
/*** Semaphore ***/
void
vlc_sem_init
(
vlc_sem_t
*
sem
,
unsigned
value
)
{
if
(
DosCreateEventSem
(
NULL
,
&
sem
->
hev
,
0
,
value
>
0
?
TRUE
:
FALSE
))
abort
();
if
(
DosCreateMutexSem
(
NULL
,
&
sem
->
wait_mutex
,
0
,
FALSE
))
abort
();
if
(
DosCreateMutexSem
(
NULL
,
&
sem
->
count_mutex
,
0
,
FALSE
))
abort
();
sem
->
count
=
value
;
}
void
vlc_sem_destroy
(
vlc_sem_t
*
sem
)
{
DosCloseEventSem
(
sem
->
hev
);
DosCloseMutexSem
(
sem
->
wait_mutex
);
DosCloseMutexSem
(
sem
->
count_mutex
);
}
int
vlc_sem_post
(
vlc_sem_t
*
sem
)
{
DosRequestMutexSem
(
sem
->
count_mutex
,
SEM_INDEFINITE_WAIT
);
if
(
sem
->
count
<
0x7FFFFFFF
)
{
sem
->
count
++
;
DosPostEventSem
(
sem
->
hev
);
}
DosReleaseMutexSem
(
sem
->
count_mutex
);
return
0
;
/* FIXME */
}
void
vlc_sem_wait
(
vlc_sem_t
*
sem
)
{
ULONG
rc
;
do
{
vlc_testcancel
();
DosRequestMutexSem
(
sem
->
wait_mutex
,
SEM_INDEFINITE_WAIT
);
rc
=
vlc_WaitForSingleObject
(
sem
->
hev
,
SEM_INDEFINITE_WAIT
);
if
(
!
rc
)
{
DosRequestMutexSem
(
sem
->
count_mutex
,
SEM_INDEFINITE_WAIT
);
sem
->
count
--
;
if
(
sem
->
count
==
0
)
{
ULONG
ulPost
;
DosResetEventSem
(
sem
->
hev
,
&
ulPost
);
}
DosReleaseMutexSem
(
sem
->
count_mutex
);
}
DosReleaseMutexSem
(
sem
->
wait_mutex
);
}
while
(
rc
==
ERROR_INTERRUPT
);
}
/*** Read/write locks */
void
vlc_rwlock_init
(
vlc_rwlock_t
*
lock
)
{
vlc_mutex_init
(
&
lock
->
mutex
);
vlc_cond_init
(
&
lock
->
wait
);
lock
->
readers
=
0
;
/* active readers */
lock
->
writers
=
0
;
/* waiting or active writers */
lock
->
writer
=
0
;
/* ID of active writer */
}
void
vlc_rwlock_destroy
(
vlc_rwlock_t
*
lock
)
{
vlc_cond_destroy
(
&
lock
->
wait
);
vlc_mutex_destroy
(
&
lock
->
mutex
);
}
void
vlc_rwlock_rdlock
(
vlc_rwlock_t
*
lock
)
{
vlc_mutex_lock
(
&
lock
->
mutex
);
/* Recursive read-locking is allowed. With the infos available:
* - the loosest possible condition (no active writer) is:
* (lock->writer != 0)
* - the strictest possible condition is:
* (lock->writer != 0 || (lock->readers == 0 && lock->writers > 0))
* or (lock->readers == 0 && (lock->writer != 0 || lock->writers > 0))
*/
while
(
lock
->
writer
!=
0
)
{
assert
(
lock
->
readers
==
0
);
vlc_cond_wait
(
&
lock
->
wait
,
&
lock
->
mutex
);
}
if
(
unlikely
(
lock
->
readers
==
ULONG_MAX
))
abort
();
lock
->
readers
++
;
vlc_mutex_unlock
(
&
lock
->
mutex
);
}
static
void
vlc_rwlock_rdunlock
(
vlc_rwlock_t
*
lock
)
{
vlc_mutex_lock
(
&
lock
->
mutex
);
assert
(
lock
->
readers
>
0
);
/* If there are no readers left, wake up a writer. */
if
(
--
lock
->
readers
==
0
&&
lock
->
writers
>
0
)
vlc_cond_signal
(
&
lock
->
wait
);
vlc_mutex_unlock
(
&
lock
->
mutex
);
}
void
vlc_rwlock_wrlock
(
vlc_rwlock_t
*
lock
)
{
vlc_mutex_lock
(
&
lock
->
mutex
);
if
(
unlikely
(
lock
->
writers
==
ULONG_MAX
))
abort
();
lock
->
writers
++
;
/* Wait until nobody owns the lock in either way. */
while
((
lock
->
readers
>
0
)
||
(
lock
->
writer
!=
0
))
vlc_cond_wait
(
&
lock
->
wait
,
&
lock
->
mutex
);
lock
->
writers
--
;
assert
(
lock
->
writer
==
0
);
lock
->
writer
=
_gettid
();
vlc_mutex_unlock
(
&
lock
->
mutex
);
}
static
void
vlc_rwlock_wrunlock
(
vlc_rwlock_t
*
lock
)
{
vlc_mutex_lock
(
&
lock
->
mutex
);
assert
(
lock
->
writer
==
_gettid
());
assert
(
lock
->
readers
==
0
);
lock
->
writer
=
0
;
/* Write unlock */
/* Let reader and writer compete. Scheduler decides who wins. */
vlc_cond_broadcast
(
&
lock
->
wait
);
vlc_mutex_unlock
(
&
lock
->
mutex
);
}
void
vlc_rwlock_unlock
(
vlc_rwlock_t
*
lock
)
{
/* Note: If the lock is held for reading, lock->writer is nul.
* If the lock is held for writing, only this thread can store a value to
* lock->writer. Either way, lock->writer is safe to fetch here. */
if
(
lock
->
writer
!=
0
)
vlc_rwlock_wrunlock
(
lock
);
else
vlc_rwlock_rdunlock
(
lock
);
}
/*** Thread-specific variables (TLS) ***/
struct
vlc_threadvar
{
PULONG
id
;
void
(
*
destroy
)
(
void
*
);
struct
vlc_threadvar
*
prev
;
struct
vlc_threadvar
*
next
;
}
*
vlc_threadvar_last
=
NULL
;
int
vlc_threadvar_create
(
vlc_threadvar_t
*
p_tls
,
void
(
*
destr
)
(
void
*
))
{
ULONG
rc
;
struct
vlc_threadvar
*
var
=
malloc
(
sizeof
(
*
var
));
if
(
unlikely
(
var
==
NULL
))
return
errno
;
rc
=
DosAllocThreadLocalMemory
(
1
,
&
var
->
id
);
if
(
rc
)
{
free
(
var
);
return
ENOMEM
;
}
var
->
destroy
=
destr
;
var
->
next
=
NULL
;
*
p_tls
=
var
;
vlc_mutex_lock
(
&
super_mutex
);
var
->
prev
=
vlc_threadvar_last
;
vlc_threadvar_last
=
var
;
vlc_mutex_unlock
(
&
super_mutex
);
return
0
;
}
void
vlc_threadvar_delete
(
vlc_threadvar_t
*
p_tls
)
{
struct
vlc_threadvar
*
var
=
*
p_tls
;
vlc_mutex_lock
(
&
super_mutex
);
if
(
var
->
prev
!=
NULL
)
var
->
prev
->
next
=
var
->
next
;
else
vlc_threadvar_last
=
var
->
next
;
if
(
var
->
next
!=
NULL
)
var
->
next
->
prev
=
var
->
prev
;
vlc_mutex_unlock
(
&
super_mutex
);
DosFreeThreadLocalMemory
(
var
->
id
);
free
(
var
);
}
int
vlc_threadvar_set
(
vlc_threadvar_t
key
,
void
*
value
)
{
*
key
->
id
=
(
ULONG
)
value
;
return
0
;
}
void
*
vlc_threadvar_get
(
vlc_threadvar_t
key
)
{
return
(
void
*
)
*
key
->
id
;
}
/*** Threads ***/
void
vlc_threads_setup
(
libvlc_int_t
*
p_libvlc
)
{
(
void
)
p_libvlc
;
}
static
void
vlc_thread_cleanup
(
struct
vlc_thread
*
th
)
{
vlc_threadvar_t
key
;
retry:
/* TODO: use RW lock or something similar */
vlc_mutex_lock
(
&
super_mutex
);
for
(
key
=
vlc_threadvar_last
;
key
!=
NULL
;
key
=
key
->
prev
)
{
void
*
value
=
vlc_threadvar_get
(
key
);
if
(
value
!=
NULL
&&
key
->
destroy
!=
NULL
)
{
vlc_mutex_unlock
(
&
super_mutex
);
vlc_threadvar_set
(
key
,
NULL
);
key
->
destroy
(
value
);
goto
retry
;
}
}
vlc_mutex_unlock
(
&
super_mutex
);
if
(
th
->
detached
)
{
DosCloseEventSem
(
th
->
cancel_event
);
DosCloseEventSem
(
th
->
done_event
);
free
(
th
);
}
}
static
void
vlc_entry
(
void
*
p
)
{
struct
vlc_thread
*
th
=
p
;
vlc_threadvar_set
(
thread_key
,
th
);
th
->
killable
=
true
;
th
->
data
=
th
->
entry
(
th
->
data
);
DosPostEventSem
(
th
->
done_event
);
vlc_thread_cleanup
(
th
);
}
static
int
vlc_clone_attr
(
vlc_thread_t
*
p_handle
,
bool
detached
,
void
*
(
*
entry
)
(
void
*
),
void
*
data
,
int
priority
)
{
struct
vlc_thread
*
th
=
malloc
(
sizeof
(
*
th
));
if
(
unlikely
(
th
==
NULL
))
return
ENOMEM
;
th
->
entry
=
entry
;
th
->
data
=
data
;
th
->
detached
=
detached
;
th
->
killable
=
false
;
/* not until vlc_entry() ! */
th
->
killed
=
false
;
th
->
cleaners
=
NULL
;
if
(
DosCreateEventSem
(
NULL
,
&
th
->
cancel_event
,
0
,
FALSE
))
goto
error
;
if
(
DosCreateEventSem
(
NULL
,
&
th
->
done_event
,
0
,
FALSE
))
goto
error
;
th
->
tid
=
_beginthread
(
vlc_entry
,
NULL
,
1024
*
1024
,
th
);
if
((
int
)
th
->
tid
==
-
1
)
goto
error
;
if
(
p_handle
!=
NULL
)
*
p_handle
=
th
;
if
(
priority
)
DosSetPriority
(
PRTYS_THREAD
,
HIBYTE
(
priority
),
LOBYTE
(
priority
),
th
->
tid
);
return
0
;
error:
DosCloseEventSem
(
th
->
cancel_event
);
DosCloseEventSem
(
th
->
done_event
);
free
(
th
);
return
ENOMEM
;
}
int
vlc_clone
(
vlc_thread_t
*
p_handle
,
void
*
(
*
entry
)
(
void
*
),
void
*
data
,
int
priority
)
{
return
vlc_clone_attr
(
p_handle
,
false
,
entry
,
data
,
priority
);
}
void
vlc_join
(
vlc_thread_t
th
,
void
**
result
)
{
ULONG
rc
;
do
{
vlc_testcancel
();
rc
=
vlc_WaitForSingleObject
(
th
->
done_event
,
SEM_INDEFINITE_WAIT
);
}
while
(
rc
==
ERROR_INTERRUPT
);
if
(
result
!=
NULL
)
*
result
=
th
->
data
;
DosCloseEventSem
(
th
->
cancel_event
);
DosCloseEventSem
(
th
->
done_event
);
free
(
th
);
}
int
vlc_clone_detach
(
vlc_thread_t
*
p_handle
,
void
*
(
*
entry
)
(
void
*
),
void
*
data
,
int
priority
)
{
vlc_thread_t
th
;
if
(
p_handle
==
NULL
)
p_handle
=
&
th
;
return
vlc_clone_attr
(
p_handle
,
true
,
entry
,
data
,
priority
);
}
int
vlc_set_priority
(
vlc_thread_t
th
,
int
priority
)
{
if
(
DosSetPriority
(
PRTYS_THREAD
,
HIBYTE
(
priority
),
LOBYTE
(
priority
),
th
->
tid
))
return
VLC_EGENERIC
;
return
VLC_SUCCESS
;
}
/*** Thread cancellation ***/
/* APC procedure for thread cancellation */
static
void
vlc_cancel_self
(
PVOID
self
)
{
struct
vlc_thread
*
th
=
self
;
if
(
likely
(
th
!=
NULL
))
th
->
killed
=
true
;
}
void
vlc_cancel
(
vlc_thread_t
thread_id
)
{
DosPostEventSem
(
thread_id
->
cancel_event
);
}
int
vlc_savecancel
(
void
)
{
int
state
;
struct
vlc_thread
*
th
=
vlc_threadvar_get
(
thread_key
);
if
(
th
==
NULL
)
return
false
;
/* Main thread - cannot be cancelled anyway */
state
=
th
->
killable
;
th
->
killable
=
false
;
return
state
;
}
void
vlc_restorecancel
(
int
state
)
{
struct
vlc_thread
*
th
=
vlc_threadvar_get
(
thread_key
);
assert
(
state
==
false
||
state
==
true
);
if
(
th
==
NULL
)
return
;
/* Main thread - cannot be cancelled anyway */
assert
(
!
th
->
killable
);
th
->
killable
=
state
!=
0
;
}
void
vlc_testcancel
(
void
)
{
struct
vlc_thread
*
th
=
vlc_threadvar_get
(
thread_key
);
if
(
th
==
NULL
)
return
;
/* Main thread - cannot be cancelled anyway */
/* This check is needed for the case that vlc_cancel() is followed by
* vlc_testcancel() without any cancellation point */
if
(
DosWaitEventSem
(
th
->
cancel_event
,
0
)
==
NO_ERROR
)
vlc_cancel_self
(
NULL
);
if
(
th
->
killable
&&
th
->
killed
)
{
for
(
vlc_cleanup_t
*
p
=
th
->
cleaners
;
p
!=
NULL
;
p
=
p
->
next
)
p
->
proc
(
p
->
data
);
DosPostEventSem
(
th
->
done_event
);
th
->
data
=
NULL
;
/* TODO: special value? */
vlc_thread_cleanup
(
th
);
_endthread
();
}
}
void
vlc_control_cancel
(
int
cmd
,
...)
{
/* NOTE: This function only modifies thread-specific data, so there is no
* need to lock anything. */
va_list
ap
;
struct
vlc_thread
*
th
=
vlc_threadvar_get
(
thread_key
);
if
(
th
==
NULL
)
return
;
/* Main thread - cannot be cancelled anyway */
va_start
(
ap
,
cmd
);
switch
(
cmd
)
{
case
VLC_CLEANUP_PUSH
:
{
/* cleaner is a pointer to the caller stack, no need to allocate
* and copy anything. As a nice side effect, this cannot fail. */
vlc_cleanup_t
*
cleaner
=
va_arg
(
ap
,
vlc_cleanup_t
*
);
cleaner
->
next
=
th
->
cleaners
;
th
->
cleaners
=
cleaner
;
break
;
}
case
VLC_CLEANUP_POP
:
{
th
->
cleaners
=
th
->
cleaners
->
next
;
break
;
}
}
va_end
(
ap
);
}
#define Q2LL( q ) ( *( long long * )&( q ))
/*** Clock ***/
mtime_t
mdate
(
void
)
{
/* We don't need the real date, just the value of a high precision timer */
QWORD
counter
;
ULONG
freq
;
if
(
DosTmrQueryTime
(
&
counter
)
||
DosTmrQueryFreq
(
&
freq
))
abort
();
/* Convert to from (1/freq) to microsecond resolution */
/* We need to split the division to avoid 63-bits overflow */
lldiv_t
d
=
lldiv
(
Q2LL
(
counter
),
freq
);
return
(
d
.
quot
*
1000000
)
+
((
d
.
rem
*
1000000
)
/
freq
);
}
#undef mwait
void
mwait
(
mtime_t
deadline
)
{
mtime_t
delay
;
vlc_testcancel
();
while
((
delay
=
(
deadline
-
mdate
()))
>
0
)
{
delay
/=
1000
;
if
(
unlikely
(
delay
>
0x7fffffff
))
delay
=
0x7fffffff
;
vlc_Sleep
(
delay
);
vlc_testcancel
();
}
}
#undef msleep
void
msleep
(
mtime_t
delay
)
{
mwait
(
mdate
()
+
delay
);
}
/*** Timers ***/
struct
vlc_timer
{
TID
tid
;
HEV
hev
;
HTIMER
htimer
;
ULONG
interval
;
bool
quit
;
void
(
*
func
)
(
void
*
);
void
*
data
;
};
static
void
vlc_timer_do
(
void
*
arg
)
{
struct
vlc_timer
*
timer
=
arg
;
while
(
1
)
{
ULONG
count
;
DosWaitEventSem
(
timer
->
hev
,
SEM_INDEFINITE_WAIT
);
DosResetEventSem
(
timer
->
hev
,
&
count
);
if
(
timer
->
quit
)
break
;
timer
->
func
(
timer
->
data
);
if
(
timer
->
interval
)
DosAsyncTimer
(
timer
->
interval
,
(
HSEM
)
timer
->
hev
,
&
timer
->
htimer
);
}
}
int
vlc_timer_create
(
vlc_timer_t
*
id
,
void
(
*
func
)
(
void
*
),
void
*
data
)
{
struct
vlc_timer
*
timer
=
malloc
(
sizeof
(
*
timer
));
if
(
timer
==
NULL
)
return
ENOMEM
;
timer
->
func
=
func
;
timer
->
data
=
data
;
DosCreateEventSem
(
NULL
,
&
timer
->
hev
,
DC_SEM_SHARED
,
FALSE
);
timer
->
htimer
=
NULLHANDLE
;
timer
->
interval
=
0
;
timer
->
quit
=
false
;
timer
->
tid
=
_beginthread
(
vlc_timer_do
,
NULL
,
1024
*
1024
,
timer
);
*
id
=
timer
;
return
0
;
}
void
vlc_timer_destroy
(
vlc_timer_t
timer
)
{
if
(
timer
->
htimer
!=
NULLHANDLE
)
DosStopTimer
(
timer
->
htimer
);
timer
->
quit
=
true
;
DosPostEventSem
(
timer
->
hev
);
DosWaitThread
(
&
timer
->
tid
,
DCWW_WAIT
);
DosCloseEventSem
(
timer
->
hev
);
free
(
timer
);
}
void
vlc_timer_schedule
(
vlc_timer_t
timer
,
bool
absolute
,
mtime_t
value
,
mtime_t
interval
)
{
if
(
timer
->
htimer
!=
NULLHANDLE
)
{
DosStopTimer
(
timer
->
htimer
);
timer
->
htimer
=
NULLHANDLE
;
timer
->
interval
=
0
;
}
if
(
value
==
0
)
return
;
/* Disarm */
if
(
absolute
)
value
-=
mdate
();
value
=
(
value
+
999
)
/
1000
;
interval
=
(
interval
+
999
)
/
1000
;
timer
->
interval
=
interval
;
if
(
DosAsyncTimer
(
value
,
(
HSEM
)
timer
->
hev
,
&
timer
->
htimer
))
abort
();
}
unsigned
vlc_timer_getoverrun
(
vlc_timer_t
timer
)
{
(
void
)
timer
;
return
0
;
}
/*** CPU ***/
unsigned
vlc_GetCPUCount
(
void
)
{
ULONG
numprocs
=
1
;
DosQuerySysInfo
(
QSV_NUMPROCESSORS
,
QSV_NUMPROCESSORS
,
&
numprocs
,
sizeof
(
numprocs
));
return
numprocs
;
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment