[vlc-devel] [PATCH 2/2] os2: thread: implemet missing threading functions

KO Myung-Hun komh78 at gmail.com
Wed Apr 1 16:05:41 CEST 2020


Attached the fixed patch, thanks!

Alexandre Janniaux wrote:
> Hi, just for info, typo in the commit message.
> 
> Regards,
> --
> Alexandre Janniaux
> Videolabs
> 
> 
> On Tue, Mar 31, 2020 at 06:17:15PM +0900, KO Myung-Hun wrote:
>> ---
>>  src/os2/thread.c | 362 ++++++++++++++++++++++++++++++++++++++++-------
>>  1 file changed, 309 insertions(+), 53 deletions(-)
>>
>> diff --git a/src/os2/thread.c b/src/os2/thread.c
>> index 66932bd2a1..6151ee57d5 100644
>> --- a/src/os2/thread.c
>> +++ b/src/os2/thread.c
>> @@ -39,6 +39,9 @@
>>  #include <errno.h>
>>  #include <time.h>
>>
>> +#include <stdalign.h>
>> +#include <stdatomic.h>
>> +
>>  #include <sys/types.h>
>>  #ifdef HAVE_SYS_SOCKET_H
>>  #include <sys/socket.h>
>> @@ -51,6 +54,11 @@
>>
>>  #include <sys/stat.h>
>>
>> +/* Static mutex and condition variable */
>> +static vlc_mutex_t super_mutex;
>> +static vlc_cond_t  super_variable;
>> +
>> +/* Threads */
>>  static vlc_threadvar_t thread_key;
>>
>>  struct vlc_thread
>> @@ -62,11 +70,17 @@ struct vlc_thread
>>
>>      bool           detached;
>>      bool           killable;
>> -    bool           killed;
>> +    atomic_bool    killed;
>>      vlc_cleanup_t *cleaners;
>>
>>      void        *(*entry) (void *);
>>      void          *data;
>> +
>> +    struct
>> +    {
>> +        atomic_uint *addr;
>> +        HMTX        lock;
>> +    } wait;
>>  };
>>
>>  static void vlc_cancel_self (PVOID dummy);
>> @@ -130,44 +144,6 @@ static ULONG vlc_Sleep (ULONG ulTimeout)
>>      return ( rc != ERROR_TIMEOUT ) ? rc : 0;
>>  }
>>
>> -static vlc_mutex_t super_mutex;
>> -static vlc_cond_t  super_variable;
>> -extern vlc_rwlock_t config_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);
>> -
>> -            return 1;
>> -
>> -        case 1 :    /* Termination */
>> -            vlc_rwlock_destroy (&config_lock);
>> -            vlc_threadvar_delete (&thread_key);
>> -
>> -            _CRT_term();
>> -
>> -            return 1;
>> -    }
>> -
>> -    return 0;   /* Failed */
>> -}
>> -
>>  void vlc_once(vlc_once_t *once, void (*cb)(void))
>>  {
>>      /* not initialized ? */
>> @@ -256,6 +232,197 @@ void *vlc_threadvar_get (vlc_threadvar_t key)
>>      return ( void * )*key->id;
>>  }
>>
>> +static struct wait_bucket
>> +{
>> +    HMTX lock;
>> +    HEV wait;
>> +    unsigned waiters;
>> +} wait_buckets[ 32 ];
>> +
>> +static void wait_bucket_init( void )
>> +{
>> +    for( size_t i = 0; i < ARRAY_SIZE( wait_buckets ); i++ )
>> +    {
>> +        struct wait_bucket *bucket = wait_buckets + i;
>> +
>> +        DosCreateMutexSem( NULL, &bucket->lock, 0L, FALSE );
>> +        DosCreateEventSem( NULL, &bucket->wait, 0L, FALSE );
>> +    }
>> +}
>> +
>> +static void wait_bucket_destroy( void )
>> +{
>> +    for( size_t i = 0; i < ARRAY_SIZE( wait_buckets ); i++ )
>> +    {
>> +        struct wait_bucket *bucket = wait_buckets + i;
>> +
>> +        DosCloseMutexSem( bucket->lock );
>> +        DosCloseEventSem( bucket->wait );
>> +    }
>> +}
>> +
>> +static struct wait_bucket *wait_bucket_get( atomic_uint *addr )
>> +{
>> +    uintptr_t u = ( uintptr_t )addr;
>> +    size_t idx = ( u / alignof ( *addr )) % ARRAY_SIZE( wait_buckets );
>> +
>> +    return &wait_buckets[ idx ];
>> +}
>> +
>> +static struct wait_bucket *wait_bucket_enter( atomic_uint *addr )
>> +{
>> +    struct wait_bucket *bucket = wait_bucket_get(addr);
>> +
>> +    DosRequestMutexSem( bucket->lock, SEM_INDEFINITE_WAIT );
>> +    bucket->waiters++;
>> +
>> +    return bucket;
>> +}
>> +
>> +static void wait_bucket_leave( void *data )
>> +{
>> +    struct wait_bucket *bucket = data;
>> +
>> +    bucket->waiters--;
>> +    DosReleaseMutexSem( bucket->lock );
>> +}
>> +
>> +void vlc_atomic_wait( void *addr, unsigned value )
>> +{
>> +    atomic_uint *futex = addr;
>> +    struct wait_bucket *bucket = wait_bucket_enter( futex );
>> +
>> +    vlc_cleanup_push( wait_bucket_leave, bucket );
>> +
>> +    if( value == atomic_load_explicit( futex, memory_order_relaxed ))
>> +    {
>> +        ULONG count;
>> +
>> +        DosReleaseMutexSem( bucket->lock );
>> +        vlc_WaitForSingleObject( bucket->wait, SEM_INDEFINITE_WAIT );
>> +        DosResetEventSem( bucket->wait, &count );
>> +        DosRequestMutexSem( bucket->lock, SEM_INDEFINITE_WAIT );
>> +    }
>> +    else
>> +        vlc_testcancel();
>> +
>> +    wait_bucket_leave( bucket );
>> +    vlc_cleanup_pop();
>> +}
>> +
>> +int vlc_atomic_timedwait(void *addr, unsigned value, vlc_tick_t deadline)
>> +{
>> +    atomic_uint *futex = addr;
>> +    struct wait_bucket *bucket = wait_bucket_enter( futex );
>> +
>> +    ULONG rc = 0;
>> +
>> +    vlc_cleanup_push( wait_bucket_leave, bucket );
>> +
>> +    if( value == atomic_load_explicit( futex, memory_order_relaxed ))
>> +    {
>> +        vlc_tick_t delay;
>> +
>> +        DosReleaseMutexSem( bucket->lock );
>> +
>> +        do
>> +        {
>> +            ULONG ms;
>> +            ULONG count;
>> +
>> +            delay = deadline - vlc_tick_now();
>> +
>> +            if( delay < 0 )
>> +                ms = 0;
>> +            else if( delay >= VLC_TICK_FROM_MS( LONG_MAX ))
>> +                ms = LONG_MAX;
>> +            else
>> +                ms = MS_FROM_VLC_TICK( delay );
>> +
>> +            rc = vlc_WaitForSingleObject( bucket->wait, ms );
>> +            if( rc == 0 )
>> +            {
>> +                DosResetEventSem( bucket->wait, &count );
>> +                break;
>> +            }
>> +        } while( delay > 0 );
>> +
>> +        DosRequestMutexSem( bucket->lock, SEM_INDEFINITE_WAIT );
>> +    }
>> +    else
>> +        vlc_testcancel();
>> +
>> +    wait_bucket_leave( bucket );
>> +    vlc_cleanup_pop();
>> +
>> +    return rc == 0 ? 0 : ETIMEDOUT;
>> +}
>> +
>> +int vlc_atomic_timedwait_daytime(void *addr, unsigned value, time_t deadline)
>> +{
>> +    atomic_uint *futex = addr;
>> +    struct wait_bucket *bucket = wait_bucket_enter( futex );
>> +
>> +    ULONG rc = 0;
>> +
>> +    vlc_cleanup_push( wait_bucket_leave, bucket );
>> +
>> +    if( value == atomic_load_explicit( futex, memory_order_relaxed ))
>> +    {
>> +        vlc_tick_t delay;
>> +
>> +        DosReleaseMutexSem( bucket->lock );
>> +
>> +        do
>> +        {
>> +            ULONG ms;
>> +            ULONG count;
>> +
>> +            delay = deadline - time( NULL );
>> +
>> +            if( delay < 0 )
>> +                ms = 0;
>> +            else if( delay >= ( LONG_MAX / 1000 ))
>> +                ms = LONG_MAX;
>> +            else
>> +                ms = delay * 1000;
>> +
>> +            rc = vlc_WaitForSingleObject( bucket->wait, ms );
>> +            if( rc == 0 )
>> +            {
>> +                DosResetEventSem( bucket->wait, &count );
>> +                break;
>> +            }
>> +        } while( delay > 0 );
>> +
>> +        DosRequestMutexSem( bucket->lock, SEM_INDEFINITE_WAIT );
>> +    }
>> +    else
>> +        vlc_testcancel();
>> +
>> +    wait_bucket_leave( bucket );
>> +    vlc_cleanup_pop();
>> +
>> +    return rc == 0 ? 0 : ETIMEDOUT;
>> +}
>> +
>> +void vlc_atomic_notify_one(void *addr)
>> +{
>> +    vlc_atomic_notify_all(addr);
>> +}
>> +
>> +void vlc_atomic_notify_all(void *addr)
>> +{
>> +    struct wait_bucket *bucket = wait_bucket_get(addr);
>> +
>> +    DosRequestMutexSem( bucket->lock, SEM_INDEFINITE_WAIT );
>> +
>> +    if( bucket->waiters > 0 )
>> +        DosPostEventSem( bucket->wait );
>> +
>> +    DosReleaseMutexSem( bucket->lock);
>> +}
>> +
>>
>>  /*** Threads ***/
>>  void vlc_threads_setup (libvlc_int_t *p_libvlc)
>> @@ -290,6 +457,8 @@ retry:
>>
>>          soclose (th->cancel_sock);
>>
>> +        DosCloseMutexSem (th->wait.lock);
>> +
>>          free (th);
>>      }
>>  }
>> @@ -315,8 +484,9 @@ static int vlc_clone_attr (vlc_thread_t *p_handle, bool detached,
>>      th->data = data;
>>      th->detached = detached;
>>      th->killable = false; /* not until vlc_entry() ! */
>> -    th->killed = false;
>> +    atomic_init (&th->killed, false);
>>      th->cleaners = NULL;
>> +    th->wait.addr = NULL;
>>
>>      if( DosCreateEventSem (NULL, &th->cancel_event, 0, FALSE))
>>          goto error;
>> @@ -327,6 +497,9 @@ static int vlc_clone_attr (vlc_thread_t *p_handle, bool detached,
>>      if( th->cancel_sock < 0 )
>>          goto error;
>>
>> +    if( DosCreateMutexSem (NULL, &th->wait.lock, 0, FALSE))
>> +        goto error;
>> +
>>      th->tid = _beginthread (vlc_entry, NULL, 1024 * 1024, th);
>>      if((int)th->tid == -1)
>>          goto error;
>> @@ -343,6 +516,7 @@ static int vlc_clone_attr (vlc_thread_t *p_handle, bool detached,
>>      return 0;
>>
>>  error:
>> +    DosCloseMutexSem (th->wait.lock);
>>      soclose (th->cancel_sock);
>>      DosCloseEventSem (th->cancel_event);
>>      DosCloseEventSem (th->done_event);
>> @@ -375,6 +549,8 @@ void vlc_join (vlc_thread_t th, void **result)
>>
>>      soclose( th->cancel_sock );
>>
>> +    DosCloseMutexSem( th->wait.lock );
>> +
>>      free( th );
>>  }
>>
>> @@ -411,13 +587,23 @@ static void vlc_cancel_self (PVOID self)
>>      struct vlc_thread *th = self;
>>
>>      if (likely(th != NULL))
>> -        th->killed = true;
>> +        atomic_store_explicit (&th->killed, true, memory_order_relaxed);
>>  }
>>
>> -void vlc_cancel (vlc_thread_t thread_id)
>> +void vlc_cancel (vlc_thread_t th)
>>  {
>> -    DosPostEventSem( thread_id->cancel_event );
>> -    so_cancel( thread_id->cancel_sock );
>> +    atomic_store_explicit( &th->killed, true, memory_order_relaxed );
>> +
>> +    DosRequestMutexSem( th->wait.lock, SEM_INDEFINITE_WAIT );
>> +    if( th->wait.addr != NULL )
>> +    {
>> +        atomic_fetch_or_explicit( th->wait.addr, 1, memory_order_relaxed );
>> +        vlc_atomic_notify_all( th->wait.addr );
>> +    }
>> +    DosReleaseMutexSem( th->wait.lock );
>> +
>> +    DosPostEventSem( th->cancel_event );
>> +    so_cancel( th->cancel_sock );
>>  }
>>
>>  int vlc_savecancel (void)
>> @@ -451,21 +637,26 @@ void vlc_testcancel (void)
>>      if (th == NULL)
>>          return; /* Main thread - cannot be cancelled anyway */
>>
>> +    if (!th->killable)
>> +        return;
>> +
>>      /* 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( th );
>>
>> -    if (th->killable && th->killed)
>> -    {
>> -        for (vlc_cleanup_t *p = th->cleaners; p != NULL; p = p->next)
>> -             p->proc (p->data);
>> +    if( !atomic_load_explicit( &th->killed, memory_order_relaxed ))
>> +        return;
>>
>> -        DosPostEventSem( th->done_event );
>> -        th->data = NULL; /* TODO: special value? */
>> -        vlc_thread_cleanup (th);
>> -        _endthread();
>> -    }
>> +    th->killable = true; /* Do not re-enter cancellation cleanup */
>> +
>> +    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 (vlc_cleanup_t *cleaner)
>> @@ -490,6 +681,30 @@ void vlc_control_cancel (vlc_cleanup_t *cleaner)
>>      }
>>  }
>>
>> +void vlc_cancel_addr_set( atomic_uint *addr )
>> +{
>> +    struct vlc_thread *th = vlc_threadvar_get( thread_key );
>> +    if( th == NULL )
>> +        return; /* Main thread - cannot be cancelled anyway */
>> +
>> +    DosRequestMutexSem( th->wait.lock, SEM_INDEFINITE_WAIT );
>> +    assert( th->wait.addr == NULL );
>> +    th->wait.addr = addr;
>> +    DosReleaseMutexSem( th->wait.lock );
>> +}
>> +
>> +void vlc_cancel_addr_clear( atomic_uint *addr )
>> +{
>> +    struct vlc_thread *th = vlc_threadvar_get( thread_key );
>> +    if( th == NULL )
>> +        return; /* Main thread - cannot be cancelled anyway */
>> +
>> +    DosRequestMutexSem( th->wait.lock, SEM_INDEFINITE_WAIT );
>> +    assert( th->wait.addr == addr );
>> +    th->wait.addr = NULL;
>> +    DosReleaseMutexSem( th->wait.lock );
>> +}
>> +
>>  static int vlc_select( int nfds, fd_set *rdset, fd_set *wrset, fd_set *exset,
>>                         struct timeval *timeout )
>>  {
>> @@ -756,3 +971,44 @@ unsigned vlc_GetCPUCount (void)
>>
>>      return numprocs;
>>  }
>> +
>> +extern vlc_rwlock_t config_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;
>> +
>> +            wait_bucket_init();
>> +
>> +            vlc_mutex_init (&super_mutex);
>> +            vlc_cond_init (&super_variable);
>> +            vlc_threadvar_create (&thread_key, NULL);
>> +            vlc_rwlock_init (&config_lock);
>> +
>> +            return 1;
>> +
>> +        case 1 :    /* Termination */
>> +            vlc_rwlock_destroy (&config_lock);
>> +            vlc_threadvar_delete (&thread_key);
>> +
>> +            wait_bucket_destroy();
>> +
>> +            _CRT_term();
>> +
>> +            return 1;
>> +    }
>> +
>> +    return 0;   /* Failed */
>> +}
>> +
>> --
>> 2.22.0
>>
>> _______________________________________________
>> vlc-devel mailing list
>> To unsubscribe or modify your subscription options:
>> https://mailman.videolan.org/listinfo/vlc-devel
> _______________________________________________
> vlc-devel mailing list
> To unsubscribe or modify your subscription options:
> https://mailman.videolan.org/listinfo/vlc-devel

-- 
KO Myung-Hun

Using Mozilla SeaMonkey 2.7.2
Under OS/2 Warp 4 for Korean with FixPak #15
In VirtualBox v6.0.8 on Intel Core i7-3615QM 2.30GHz with 8GB RAM

Korean OS/2 User Community : http://www.os2.kr/

-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0001-os2-thread-implement-missing-threading-functions.patch
Type: application/x-patch
Size: 12571 bytes
Desc: not available
URL: <http://mailman.videolan.org/pipermail/vlc-devel/attachments/20200401/315e0018/attachment.bin>


More information about the vlc-devel mailing list