[vlc-devel] [PATCH 01/11] os2: thread: implement missing threading functions
KO Myung-Hun
komh78 at gmail.com
Mon Jan 25 13:18:07 UTC 2021
Hi/2.
Rémi Denis-Courmont wrote:
> Hi,
>
> Where is the atomic-wait algorithm from? It's entirely clear to me if it's correct.
>
>
It was ported from posix/wait.c and win32/thread.c.
Any problem ?
> Le 20 janvier 2021 11:49:23 GMT+02:00, KO Myung-Hun <komh78 at gmail.com> a écrit :
>> ---
>> src/os2/thread.c | 351 ++++++++++++++++++++++++++++++++++++++++-------
>> 1 file changed, 302 insertions(+), 49 deletions(-)
>>
>> diff --git a/src/os2/thread.c b/src/os2/thread.c
>> index 0d7bc9e79f..1c4774f04c 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
>> @@ -61,11 +69,17 @@ struct vlc_thread
>> int cancel_sock;
>>
>> 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);
>> @@ -129,40 +143,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;
>> -
>> -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);
>> -
>> - return 1;
>> -
>> - case 1 : /* Termination */
>> - vlc_threadvar_delete (&thread_key);
>> -
>> - _CRT_term();
>> -
>> - return 1;
>> - }
>> -
>> - return 0; /* Failed */
>> -}
>>
>> /*** Thread-specific variables (TLS) ***/
>> struct vlc_threadvar
>> @@ -232,6 +212,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)
>> @@ -280,8 +451,9 @@ int vlc_clone (vlc_thread_t *p_handle, void
>> *(*entry) (void *),
>> th->entry = entry;
>> th->data = data;
>> 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;
>> @@ -292,6 +464,9 @@ int vlc_clone (vlc_thread_t *p_handle, void
>> *(*entry) (void *),
>> 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;
>> @@ -308,6 +483,7 @@ int vlc_clone (vlc_thread_t *p_handle, void
>> *(*entry) (void *),
>> return 0;
>>
>> error:
>> + DosCloseMutexSem (th->wait.lock);
>> soclose (th->cancel_sock);
>> DosCloseEventSem (th->cancel_event);
>> DosCloseEventSem (th->done_event);
>> @@ -334,6 +510,8 @@ void vlc_join (vlc_thread_t th, void **result)
>>
>> soclose( th->cancel_sock );
>>
>> + DosCloseMutexSem( th->wait.lock );
>> +
>> free( th );
>> }
>>
>> @@ -360,13 +538,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)
>> @@ -400,21 +588,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)
>> @@ -439,6 +632,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 )
>> {
>> @@ -705,3 +922,39 @@ unsigned vlc_GetCPUCount (void)
>>
>> return numprocs;
>> }
>> +
>> +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);
>> +
>> + return 1;
>> +
>> + case 1 : /* Termination */
>> + 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
>
--
KO Myung-Hun
Using Mozilla SeaMonkey 2.7.2
Under OS/2 Warp 4 for Korean with FixPak #15
In VirtualBox v6.1.10 on Intel Core i7-3615QM 2.30GHz with 8GB RAM
Korean OS/2 User Community : http://www.os2.kr/
More information about the vlc-devel
mailing list