1cabdff1aSopenharmony_ci/*
2cabdff1aSopenharmony_ci * Copyright (c) 2011-2017 KO Myung-Hun <komh@chollian.net>
3cabdff1aSopenharmony_ci *
4cabdff1aSopenharmony_ci * This file is part of FFmpeg.
5cabdff1aSopenharmony_ci *
6cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or
7cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public
8cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either
9cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version.
10cabdff1aSopenharmony_ci *
11cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful,
12cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
13cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14cabdff1aSopenharmony_ci * Lesser General Public License for more details.
15cabdff1aSopenharmony_ci *
16cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public
17cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software
18cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19cabdff1aSopenharmony_ci */
20cabdff1aSopenharmony_ci
21cabdff1aSopenharmony_ci/**
22cabdff1aSopenharmony_ci * @file
23cabdff1aSopenharmony_ci * os2threads to pthreads wrapper
24cabdff1aSopenharmony_ci */
25cabdff1aSopenharmony_ci
26cabdff1aSopenharmony_ci#ifndef COMPAT_OS2THREADS_H
27cabdff1aSopenharmony_ci#define COMPAT_OS2THREADS_H
28cabdff1aSopenharmony_ci
29cabdff1aSopenharmony_ci#define INCL_DOS
30cabdff1aSopenharmony_ci#define INCL_DOSERRORS
31cabdff1aSopenharmony_ci#include <os2.h>
32cabdff1aSopenharmony_ci
33cabdff1aSopenharmony_ci#undef __STRICT_ANSI__          /* for _beginthread() */
34cabdff1aSopenharmony_ci#include <stdlib.h>
35cabdff1aSopenharmony_ci#include <time.h>
36cabdff1aSopenharmony_ci
37cabdff1aSopenharmony_ci#include <sys/builtin.h>
38cabdff1aSopenharmony_ci#include <sys/fmutex.h>
39cabdff1aSopenharmony_ci
40cabdff1aSopenharmony_ci#include "libavutil/attributes.h"
41cabdff1aSopenharmony_ci#include "libavutil/common.h"
42cabdff1aSopenharmony_ci#include "libavutil/time.h"
43cabdff1aSopenharmony_ci
44cabdff1aSopenharmony_citypedef struct {
45cabdff1aSopenharmony_ci    TID tid;
46cabdff1aSopenharmony_ci    void *(*start_routine)(void *);
47cabdff1aSopenharmony_ci    void *arg;
48cabdff1aSopenharmony_ci    void *result;
49cabdff1aSopenharmony_ci} pthread_t;
50cabdff1aSopenharmony_ci
51cabdff1aSopenharmony_citypedef void pthread_attr_t;
52cabdff1aSopenharmony_ci
53cabdff1aSopenharmony_citypedef _fmutex pthread_mutex_t;
54cabdff1aSopenharmony_citypedef void pthread_mutexattr_t;
55cabdff1aSopenharmony_ci
56cabdff1aSopenharmony_ci#define PTHREAD_MUTEX_INITIALIZER _FMUTEX_INITIALIZER
57cabdff1aSopenharmony_ci
58cabdff1aSopenharmony_citypedef struct {
59cabdff1aSopenharmony_ci    HEV event_sem;
60cabdff1aSopenharmony_ci    HEV ack_sem;
61cabdff1aSopenharmony_ci    volatile unsigned  wait_count;
62cabdff1aSopenharmony_ci} pthread_cond_t;
63cabdff1aSopenharmony_ci
64cabdff1aSopenharmony_citypedef void pthread_condattr_t;
65cabdff1aSopenharmony_ci
66cabdff1aSopenharmony_citypedef struct {
67cabdff1aSopenharmony_ci    volatile int done;
68cabdff1aSopenharmony_ci    _fmutex mtx;
69cabdff1aSopenharmony_ci} pthread_once_t;
70cabdff1aSopenharmony_ci
71cabdff1aSopenharmony_ci#define PTHREAD_ONCE_INIT {0, _FMUTEX_INITIALIZER}
72cabdff1aSopenharmony_ci
73cabdff1aSopenharmony_cistatic void thread_entry(void *arg)
74cabdff1aSopenharmony_ci{
75cabdff1aSopenharmony_ci    pthread_t *thread = arg;
76cabdff1aSopenharmony_ci
77cabdff1aSopenharmony_ci    thread->result = thread->start_routine(thread->arg);
78cabdff1aSopenharmony_ci}
79cabdff1aSopenharmony_ci
80cabdff1aSopenharmony_cistatic av_always_inline int pthread_create(pthread_t *thread,
81cabdff1aSopenharmony_ci                                           const pthread_attr_t *attr,
82cabdff1aSopenharmony_ci                                           void *(*start_routine)(void*),
83cabdff1aSopenharmony_ci                                           void *arg)
84cabdff1aSopenharmony_ci{
85cabdff1aSopenharmony_ci    thread->start_routine = start_routine;
86cabdff1aSopenharmony_ci    thread->arg = arg;
87cabdff1aSopenharmony_ci    thread->result = NULL;
88cabdff1aSopenharmony_ci
89cabdff1aSopenharmony_ci    thread->tid = _beginthread(thread_entry, NULL, 1024 * 1024, thread);
90cabdff1aSopenharmony_ci
91cabdff1aSopenharmony_ci    return 0;
92cabdff1aSopenharmony_ci}
93cabdff1aSopenharmony_ci
94cabdff1aSopenharmony_cistatic av_always_inline int pthread_join(pthread_t thread, void **value_ptr)
95cabdff1aSopenharmony_ci{
96cabdff1aSopenharmony_ci    DosWaitThread(&thread.tid, DCWW_WAIT);
97cabdff1aSopenharmony_ci
98cabdff1aSopenharmony_ci    if (value_ptr)
99cabdff1aSopenharmony_ci        *value_ptr = thread.result;
100cabdff1aSopenharmony_ci
101cabdff1aSopenharmony_ci    return 0;
102cabdff1aSopenharmony_ci}
103cabdff1aSopenharmony_ci
104cabdff1aSopenharmony_cistatic av_always_inline int pthread_mutex_init(pthread_mutex_t *mutex,
105cabdff1aSopenharmony_ci                                               const pthread_mutexattr_t *attr)
106cabdff1aSopenharmony_ci{
107cabdff1aSopenharmony_ci    _fmutex_create(mutex, 0);
108cabdff1aSopenharmony_ci
109cabdff1aSopenharmony_ci    return 0;
110cabdff1aSopenharmony_ci}
111cabdff1aSopenharmony_ci
112cabdff1aSopenharmony_cistatic av_always_inline int pthread_mutex_destroy(pthread_mutex_t *mutex)
113cabdff1aSopenharmony_ci{
114cabdff1aSopenharmony_ci    _fmutex_close(mutex);
115cabdff1aSopenharmony_ci
116cabdff1aSopenharmony_ci    return 0;
117cabdff1aSopenharmony_ci}
118cabdff1aSopenharmony_ci
119cabdff1aSopenharmony_cistatic av_always_inline int pthread_mutex_lock(pthread_mutex_t *mutex)
120cabdff1aSopenharmony_ci{
121cabdff1aSopenharmony_ci    _fmutex_request(mutex, 0);
122cabdff1aSopenharmony_ci
123cabdff1aSopenharmony_ci    return 0;
124cabdff1aSopenharmony_ci}
125cabdff1aSopenharmony_ci
126cabdff1aSopenharmony_cistatic av_always_inline int pthread_mutex_unlock(pthread_mutex_t *mutex)
127cabdff1aSopenharmony_ci{
128cabdff1aSopenharmony_ci    _fmutex_release(mutex);
129cabdff1aSopenharmony_ci
130cabdff1aSopenharmony_ci    return 0;
131cabdff1aSopenharmony_ci}
132cabdff1aSopenharmony_ci
133cabdff1aSopenharmony_cistatic av_always_inline int pthread_cond_init(pthread_cond_t *cond,
134cabdff1aSopenharmony_ci                                              const pthread_condattr_t *attr)
135cabdff1aSopenharmony_ci{
136cabdff1aSopenharmony_ci    DosCreateEventSem(NULL, &cond->event_sem, DCE_POSTONE, FALSE);
137cabdff1aSopenharmony_ci    DosCreateEventSem(NULL, &cond->ack_sem, DCE_POSTONE, FALSE);
138cabdff1aSopenharmony_ci
139cabdff1aSopenharmony_ci    cond->wait_count = 0;
140cabdff1aSopenharmony_ci
141cabdff1aSopenharmony_ci    return 0;
142cabdff1aSopenharmony_ci}
143cabdff1aSopenharmony_ci
144cabdff1aSopenharmony_cistatic av_always_inline int pthread_cond_destroy(pthread_cond_t *cond)
145cabdff1aSopenharmony_ci{
146cabdff1aSopenharmony_ci    DosCloseEventSem(cond->event_sem);
147cabdff1aSopenharmony_ci    DosCloseEventSem(cond->ack_sem);
148cabdff1aSopenharmony_ci
149cabdff1aSopenharmony_ci    return 0;
150cabdff1aSopenharmony_ci}
151cabdff1aSopenharmony_ci
152cabdff1aSopenharmony_cistatic av_always_inline int pthread_cond_signal(pthread_cond_t *cond)
153cabdff1aSopenharmony_ci{
154cabdff1aSopenharmony_ci    if (!__atomic_cmpxchg32(&cond->wait_count, 0, 0)) {
155cabdff1aSopenharmony_ci        DosPostEventSem(cond->event_sem);
156cabdff1aSopenharmony_ci        DosWaitEventSem(cond->ack_sem, SEM_INDEFINITE_WAIT);
157cabdff1aSopenharmony_ci    }
158cabdff1aSopenharmony_ci
159cabdff1aSopenharmony_ci    return 0;
160cabdff1aSopenharmony_ci}
161cabdff1aSopenharmony_ci
162cabdff1aSopenharmony_cistatic av_always_inline int pthread_cond_broadcast(pthread_cond_t *cond)
163cabdff1aSopenharmony_ci{
164cabdff1aSopenharmony_ci    while (!__atomic_cmpxchg32(&cond->wait_count, 0, 0))
165cabdff1aSopenharmony_ci        pthread_cond_signal(cond);
166cabdff1aSopenharmony_ci
167cabdff1aSopenharmony_ci    return 0;
168cabdff1aSopenharmony_ci}
169cabdff1aSopenharmony_ci
170cabdff1aSopenharmony_cistatic av_always_inline int pthread_cond_timedwait(pthread_cond_t *cond,
171cabdff1aSopenharmony_ci                                                   pthread_mutex_t *mutex,
172cabdff1aSopenharmony_ci                                                   const struct timespec *abstime)
173cabdff1aSopenharmony_ci{
174cabdff1aSopenharmony_ci    int64_t abs_milli = abstime->tv_sec * 1000LL + abstime->tv_nsec / 1000000;
175cabdff1aSopenharmony_ci    ULONG t = av_clip64(abs_milli - av_gettime() / 1000, 0, ULONG_MAX);
176cabdff1aSopenharmony_ci
177cabdff1aSopenharmony_ci    __atomic_increment(&cond->wait_count);
178cabdff1aSopenharmony_ci
179cabdff1aSopenharmony_ci    pthread_mutex_unlock(mutex);
180cabdff1aSopenharmony_ci
181cabdff1aSopenharmony_ci    APIRET ret = DosWaitEventSem(cond->event_sem, t);
182cabdff1aSopenharmony_ci
183cabdff1aSopenharmony_ci    __atomic_decrement(&cond->wait_count);
184cabdff1aSopenharmony_ci
185cabdff1aSopenharmony_ci    DosPostEventSem(cond->ack_sem);
186cabdff1aSopenharmony_ci
187cabdff1aSopenharmony_ci    pthread_mutex_lock(mutex);
188cabdff1aSopenharmony_ci
189cabdff1aSopenharmony_ci    return (ret == ERROR_TIMEOUT) ? ETIMEDOUT : 0;
190cabdff1aSopenharmony_ci}
191cabdff1aSopenharmony_ci
192cabdff1aSopenharmony_cistatic av_always_inline int pthread_cond_wait(pthread_cond_t *cond,
193cabdff1aSopenharmony_ci                                              pthread_mutex_t *mutex)
194cabdff1aSopenharmony_ci{
195cabdff1aSopenharmony_ci    __atomic_increment(&cond->wait_count);
196cabdff1aSopenharmony_ci
197cabdff1aSopenharmony_ci    pthread_mutex_unlock(mutex);
198cabdff1aSopenharmony_ci
199cabdff1aSopenharmony_ci    DosWaitEventSem(cond->event_sem, SEM_INDEFINITE_WAIT);
200cabdff1aSopenharmony_ci
201cabdff1aSopenharmony_ci    __atomic_decrement(&cond->wait_count);
202cabdff1aSopenharmony_ci
203cabdff1aSopenharmony_ci    DosPostEventSem(cond->ack_sem);
204cabdff1aSopenharmony_ci
205cabdff1aSopenharmony_ci    pthread_mutex_lock(mutex);
206cabdff1aSopenharmony_ci
207cabdff1aSopenharmony_ci    return 0;
208cabdff1aSopenharmony_ci}
209cabdff1aSopenharmony_ci
210cabdff1aSopenharmony_cistatic av_always_inline int pthread_once(pthread_once_t *once_control,
211cabdff1aSopenharmony_ci                                         void (*init_routine)(void))
212cabdff1aSopenharmony_ci{
213cabdff1aSopenharmony_ci    if (!once_control->done)
214cabdff1aSopenharmony_ci    {
215cabdff1aSopenharmony_ci        _fmutex_request(&once_control->mtx, 0);
216cabdff1aSopenharmony_ci
217cabdff1aSopenharmony_ci        if (!once_control->done)
218cabdff1aSopenharmony_ci        {
219cabdff1aSopenharmony_ci            init_routine();
220cabdff1aSopenharmony_ci
221cabdff1aSopenharmony_ci            once_control->done = 1;
222cabdff1aSopenharmony_ci        }
223cabdff1aSopenharmony_ci
224cabdff1aSopenharmony_ci        _fmutex_release(&once_control->mtx);
225cabdff1aSopenharmony_ci    }
226cabdff1aSopenharmony_ci
227cabdff1aSopenharmony_ci    return 0;
228cabdff1aSopenharmony_ci}
229cabdff1aSopenharmony_ci#endif /* COMPAT_OS2THREADS_H */
230