diff --git a/c/pthread/sync/sync.go b/c/pthread/sync/sync.go index a3445a04..065e4b44 100644 --- a/c/pthread/sync/sync.go +++ b/c/pthread/sync/sync.go @@ -23,6 +23,7 @@ import ( _ "unsafe" "github.com/goplus/llgo/c" + "github.com/goplus/llgo/c/time" ) const ( @@ -85,3 +86,89 @@ func (m *Mutex) TryLock() c.Int { return 0 } func (m *Mutex) Unlock() {} // ----------------------------------------------------------------------------- + +// RWLockAttr is a read-write lock attribute object. +type RWLockAttr C.pthread_rwlockattr_t + +// llgo:link (*RWLockAttr).Init C.pthread_rwlockattr_init +func (a *RWLockAttr) Init(attr *RWLockAttr) c.Int { return 0 } + +// llgo:link (*RWLockAttr).Destroy C.pthread_rwlockattr_destroy +func (a *RWLockAttr) Destroy() {} + +// llgo:link (*RWLockAttr).SetPShared C.pthread_rwlockattr_setpshared +func (a *RWLockAttr) SetPShared(pshared c.Int) c.Int { return 0 } + +// llgo:link (*RWLockAttr).GetPShared C.pthread_rwlockattr_getpshared +func (a *RWLockAttr) GetPShared(pshared *c.Int) c.Int { return 0 } + +// ----------------------------------------------------------------------------- + +// RWLock is a read-write lock. +type RWLock C.pthread_rwlock_t + +// llgo:link (*RWLock).Init C.pthread_rwlock_init +func (rw *RWLock) Init(attr *RWLockAttr) c.Int { return 0 } + +// llgo:link (*RWLock).Destroy C.pthread_rwlock_destroy +func (rw *RWLock) Destroy() {} + +// llgo:link (*RWLock).RLock C.pthread_rwlock_rdlock +func (rw *RWLock) RLock() {} + +// llgo:link (*RWLock).TryRLock C.pthread_rwlock_tryrdlock +func (rw *RWLock) TryRLock() c.Int { return 0 } + +// llgo:link (*RWLock).RUnlock C.pthread_rwlock_unlock +func (rw *RWLock) RUnlock() {} + +// llgo:link (*RWLock).Lock C.pthread_rwlock_wrlock +func (rw *RWLock) Lock() {} + +// llgo:link (*RWLock).TryLock C.pthread_rwlock_trywrlock +func (rw *RWLock) TryLock() c.Int { return 0 } + +// llgo:link (*RWLock).Unlock C.pthread_rwlock_unlock +func (rw *RWLock) Unlock() {} + +// ----------------------------------------------------------------------------- + +// CondAttr is a condition variable attribute object. +type CondAttr C.pthread_condattr_t + +// llgo:link (*CondAttr).Init C.pthread_condattr_init +func (a *CondAttr) Init(attr *CondAttr) c.Int { return 0 } + +// llgo:link (*CondAttr).Destroy C.pthread_condattr_destroy +func (a *CondAttr) Destroy() {} + +// llgo:link (*CondAttr).SetClock C.pthread_condattr_setclock +func (a *CondAttr) SetClock(clock time.ClockID) c.Int { return 0 } + +// llgo:link (*CondAttr).GetClock C.pthread_condattr_getclock +func (a *CondAttr) GetClock(clock *time.ClockID) c.Int { return 0 } + +// ----------------------------------------------------------------------------- + +// Cond is a condition variable. +type Cond C.pthread_cond_t + +// llgo:link (*Cond).Init C.pthread_cond_init +func (c *Cond) Init(attr *CondAttr) c.Int { return 0 } + +// llgo:link (*Cond).Destroy C.pthread_cond_destroy +func (c *Cond) Destroy() {} + +// llgo:link (*Cond).Signal C.pthread_cond_signal +func (c *Cond) Signal() c.Int { return 0 } + +// llgo:link (*Cond).Broadcast C.pthread_cond_broadcast +func (c *Cond) Broadcast() c.Int { return 0 } + +// llgo:link (*Cond).Wait C.pthread_cond_wait +func (c *Cond) Wait(m *Mutex) c.Int { return 0 } + +// llgo:link (*Cond).TimedWait C.pthread_cond_timedwait +func (c *Cond) TimedWait(m *Mutex, abstime *time.Timespec) c.Int { return 0 } + +// ----------------------------------------------------------------------------- diff --git a/c/time/time.go b/c/time/time.go new file mode 100644 index 00000000..e650c383 --- /dev/null +++ b/c/time/time.go @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package time + +// #include +import "C" + +import ( + _ "unsafe" +) + +const ( + LLGoPackage = "decl" +) + +// ----------------------------------------------------------------------------- + +type Timespec C.struct_timespec + +// ----------------------------------------------------------------------------- + +type ClockID C.clockid_t + +// ----------------------------------------------------------------------------- diff --git a/internal/lib/sync/sync.go b/internal/lib/sync/sync.go index 1ee685cd..415b6dec 100644 --- a/internal/lib/sync/sync.go +++ b/internal/lib/sync/sync.go @@ -18,6 +18,7 @@ package sync // llgo:skipall import ( + gosync "sync" "unsafe" "github.com/goplus/llgo/c" @@ -34,7 +35,7 @@ type Mutex sync.Mutex func (m *Mutex) Lock() { if *(*c.Long)(unsafe.Pointer(m)) == 0 { - (*sync.Mutex)(m).Init(nil) + (*sync.Mutex)(m).Init(nil) // TODO(xsw): finalize } (*sync.Mutex)(m).Lock() } @@ -46,10 +47,47 @@ func (m *Mutex) TryLock() bool { return (*sync.Mutex)(m).TryLock() == 0 } -func (m *Mutex) Unlock() { - (*sync.Mutex)(m).Unlock() +// llgo:link (*Mutex).Unlock C.pthread_mutex_unlock +func (m *Mutex) Unlock() {} + +// ----------------------------------------------------------------------------- + +type RWMutex sync.RWLock + +func (rw *RWMutex) RLock() { + if *(*c.Long)(unsafe.Pointer(rw)) == 0 { + (*sync.RWLock)(rw).Init(nil) + } + (*sync.RWLock)(rw).RLock() } +func (rw *RWMutex) TryRLock() bool { + if *(*c.Long)(unsafe.Pointer(rw)) == 0 { + (*sync.RWLock)(rw).Init(nil) + } + return (*sync.RWLock)(rw).TryRLock() == 0 +} + +// llgo:link (*RWMutex).RUnlock C.pthread_rwlock_unlock +func (rw *RWMutex) RUnlock() {} + +func (rw *RWMutex) Lock() { + if *(*c.Long)(unsafe.Pointer(rw)) == 0 { + (*sync.RWLock)(rw).Init(nil) + } + (*sync.RWLock)(rw).Lock() +} + +func (rw *RWMutex) TryLock() bool { + if *(*c.Long)(unsafe.Pointer(rw)) == 0 { + (*sync.RWLock)(rw).Init(nil) + } + return (*sync.RWLock)(rw).TryLock() == 0 +} + +// llgo:link (*RWMutex).Unlock C.pthread_rwlock_unlock +func (rw *RWMutex) Unlock() {} + // ----------------------------------------------------------------------------- type Once struct { @@ -69,3 +107,66 @@ func (o *Once) Do(f func()) { } // ----------------------------------------------------------------------------- + +type Cond struct { + cond sync.Cond + m *sync.Mutex +} + +func NewCond(l gosync.Locker) *Cond { + ret := &Cond{m: l.(*sync.Mutex)} + ret.cond.Init(nil) // TODO(xsw): finalize + return ret +} + +// llgo:link (*Cond).Signal C.pthread_cond_signal +func (c *Cond) Signal() {} + +// llgo:link (*Cond).Broadcast C.pthread_cond_broadcast +func (c *Cond) Broadcast() {} + +func (c *Cond) Wait() { + c.cond.Wait(c.m) +} + +// ----------------------------------------------------------------------------- + +type WaitGroup struct { + mutex sync.Mutex + cond sync.Cond + count int +} + +func (wg *WaitGroup) doInit() { + wg.mutex.Init(nil) + wg.cond.Init(nil) // TODO(xsw): finalize +} + +func (wg *WaitGroup) Add(delta int) { + if *(*c.Long)(unsafe.Pointer(wg)) == 0 { + wg.doInit() + } + wg.mutex.Lock() + wg.count += delta + if wg.count <= 0 { + wg.cond.Broadcast() + } + wg.mutex.Unlock() +} + +func (wg *WaitGroup) Done() { + wg.Add(-1) +} + +func (wg *WaitGroup) Wait() { + if *(*c.Long)(unsafe.Pointer(wg)) == 0 { + wg.doInit() + } + wg.mutex.Lock() + for wg.count > 0 { + wg.cond.Wait(&wg.mutex) + } + wg.mutex.Unlock() +} + +// -----------------------------------------------------------------------------