[vlc-devel] [PATCH 19/41] Implement thread support for OS/2

KO Myung-Hun komh78 at gmail.com
Fri Oct 14 16:28:46 CEST 2011



Rémi Denis-Courmont wrote:
> Comments inline...
> 
> Le lundi 10 octobre 2011 14:43:58 KO Myung-Hun, vous avez écrit :
>> ---
>>  include/vlc_common.h  |   15 +
>>  include/vlc_threads.h |   63 ++++
>>  src/Makefile.am       |   13 +
>>  src/os2/thread.c      |  932
>> +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 1023
>> insertions(+), 0 deletions(-)
>>  create mode 100644 src/os2/thread.c
>>
>> diff --git a/include/vlc_common.h b/include/vlc_common.h
>> index 8e03ed3..95a9531 100644
>> --- a/include/vlc_common.h
>> +++ b/include/vlc_common.h
>> @@ -134,6 +134,9 @@
>>
>>  #define VLC_API VLC_EXTERN VLC_EXPORT
>>
>> +#ifdef __OS2__
>> +#   define pthread_sigmask  sigprocmask
>> +#endif
> 
> That feels a bit out of place.
> Is there any reason why it's not in <vlc_threads.h> ?
> 

Fixed.

>>
>>  /*************************************************************************
>> **** * Basic types definitions
>> @@ -149,6 +152,11 @@
>>   #include <sys/syslimits.h>
>>  #endif
>>
>> +#ifdef __OS2__
>> +#   include <unistd.h>
>> +#   include <time.h>
>> +#endif
>> +
> 
> Those two headers should not be needed in <vlc_common.h>. Normally, files that 
> dependent on them already include them explicitly.
> 

Fixed.

>>  /* Counter for statistics and profiling */
>>  typedef unsigned long       count_t;
>>
>> @@ -476,6 +484,13 @@ typedef int ( * vlc_callback_t ) ( vlc_object_t *,    
>>  /* variable's object */ # include <windows.h>
>>  #endif
>>
>> +#ifdef __OS2__
>> +#   define OS2EMX_PLAIN_CHAR
>> +#   define INCL_BASE
>> +#   define INCL_PM
>> +#   include <os2.h>
>> +#endif
>> +
>>  #include "vlc_mtime.h"
>>  #include "vlc_threads.h"
>>
>> diff --git a/include/vlc_threads.h b/include/vlc_threads.h
>> index 3fefbaf..e76a6bc 100644
>> --- a/include/vlc_threads.h
>> +++ b/include/vlc_threads.h
>> @@ -38,6 +38,10 @@
>>  #elif defined( WIN32 )
>>  #   include <process.h>                                         /* Win32
>> API */
>>
>> +#elif defined( __OS2__ )                                        /* OS/2
>> API  */
>> +#   include <stdlib.h>
> 
> This should not be needed. Unfortunately, for historical reasons, stdlib.h is 
> included in <vlc_common.h> anyway.
> 

Fixed.

>> +#   include <errno.h>
>> +
>>  #else                                         /* pthreads (like Linux &
>> BSD) */
>>  #   define LIBVLC_USE_PTHREAD 1
>>  #   define LIBVLC_USE_PTHREAD_CANCEL 1
>> @@ -90,6 +94,14 @@
>>  #   define VLC_THREAD_PRIORITY_HIGHEST \
>>          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
>>  #   define VLC_THREAD_PRIORITY_LOW 0
>>  #   define VLC_THREAD_PRIORITY_INPUT 0
>> @@ -161,6 +173,57 @@ typedef struct
>>
>>  typedef struct vlc_threadvar *vlc_threadvar_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;
>> +    int  max_count;
>> +} vlc_sem_t;
> 
> A semaphore can be reimplemented with one mutex, one condition variable and 
> one integer. So it's surprising that 'HMTX' are required here.
> 

HMTX is a mutex. What problem ?

>> +
>> +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
>>
>>  #if defined( WIN32 ) && !defined ETIMEDOUT
>> diff --git a/src/Makefile.am b/src/Makefile.am
>> index 3210814..9cfa200 100644
>> --- a/src/Makefile.am
>> +++ b/src/Makefile.am
>> @@ -197,6 +197,7 @@ EXTRA_libvlccore_la_SOURCES = \
>>  	$(SOURCES_libvlc_darwin) \
>>  	$(SOURCES_libvlc_linux) \
>>  	$(SOURCES_libvlc_win32) \
>> +	$(SOURCES_libvlc_os2) \
>>  	$(SOURCES_libvlc_other) \
>>  	$(SOURCES_libvlc_httpd) \
>>  	$(SOURCES_libvlc_sout) \
>> @@ -217,12 +218,16 @@ else
>>  if HAVE_SYMBIAN
>>  #libvlccore_la_SOURCES += $(SOURCES_libvlc_symbian)
>>  else
>> +if HAVE_OS2
>> +libvlccore_la_SOURCES += $(SOURCES_libvlc_os2)
>> +else
>>  libvlccore_la_SOURCES += $(SOURCES_libvlc_other)
>>  endif
>>  endif
>>  endif
>>  endif
>>  endif
>> +endif
>>  if BUILD_HTTPD
>>  libvlccore_la_SOURCES += $(SOURCES_libvlc_httpd)
>>  endif
>> @@ -271,6 +276,14 @@ SOURCES_libvlc_symbian = \
>>  	win32/plugin.c \
>>  	$(NULL)
>>
>> +SOURCES_libvlc_os2 = \
>> +	posix/dirs.c \
>> +	misc/atomic.c \
>> +	posix/filesystem.c \
>> +	os2/thread.c \
>> +	posix/specific.c \
>> +	$(NULL)
>> +
>>  SOURCES_libvlc_other = \
>>  	posix/dirs.c \
>>  	misc/atomic.c \
>> diff --git a/src/os2/thread.c b/src/os2/thread.c
>> new file mode 100644
>> index 0000000..131e6b6
>> --- /dev/null
>> +++ b/src/os2/thread.c
>> @@ -0,0 +1,932 @@
>> +/*************************************************************************
>> **** + * thread.c : OS/2 back-end for LibVLC
>> +
>> **************************************************************************
>> ***
>> + * Copyright (C) 2010 KO Myung-Hun
> 
> This being based on src/win32/thread.c should probably carry the original 
> copyright notice as well, but JB would know what it should be.
> 

Maybe fixed. ^^

>> + *
>> + * 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>
>> +
>> +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;
>> +    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 );
>> +    }
>> +
>> +    asr[ 0 ].hsemCur = ( HSEM )hev;
>> +    asr[ 0 ].ulUser  = 0;
>> +    asr[ 1 ].hsemCur = ( HSEM )th->cancel_event;
>> +    asr[ 1 ].ulUser  = 0xFFFF;
>> +    DosCreateMuxWaitSem( NULL, &hmux, 2, 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)
>> +{
>> +    DosSleep( ulTimeout );
>> +
>> +    return 0;
>> +}
> 
> I guess this will cause very long delays if ulTimeout is large, and the thread 
> got canceled.
> 

Fixed.

>> +
>> +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;
>> +    sem->max_count = 0x7FFFFFFF;
> 
> It seems that 'max_count' is constant, so you probably don't need to store it.
> 

Fixed.

>> +}
>> +
>> +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 < sem->max_count)
>> +    {
>> +        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;
>> +}
>> +
> 
> 

-- 
KO Myung-Hun

Using Mozilla SeaMonkey 2.0.14
Under OS/2 Warp 4 for Korean with FixPak #15
On AMD ThunderBird 1GHz with 512 MB RAM

Korean OS/2 User Community : http://www.ecomstation.co.kr

-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: 0009-Implement-thread-support-for-OS-2.patch
URL: <http://mailman.videolan.org/pipermail/vlc-devel/attachments/20111014/41b344f2/attachment.ksh>


More information about the vlc-devel mailing list