mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-11-03 23:02:24 -06:00 
			
		
		
		
	
		
			
	
	
		
			509 lines
		
	
	
	
		
			13 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
		
		
			
		
	
	
			509 lines
		
	
	
	
		
			13 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| 
								 | 
							
								// Copyright 2024 The Libc Authors. All rights reserved.
							 | 
						||
| 
								 | 
							
								// Use of this source code is governed by a BSD-style
							 | 
						||
| 
								 | 
							
								// license that can be found in the LICENSE file.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//go:build linux && (amd64 || loong64)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								package libc // import "modernc.org/libc"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import (
							 | 
						||
| 
								 | 
							
									"runtime"
							 | 
						||
| 
								 | 
							
									"slices"
							 | 
						||
| 
								 | 
							
									"sync"
							 | 
						||
| 
								 | 
							
									"sync/atomic"
							 | 
						||
| 
								 | 
							
									"time"
							 | 
						||
| 
								 | 
							
									"unsafe"
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								type pthreadAttr struct {
							 | 
						||
| 
								 | 
							
									detachState int32
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								type pthreadCleanupItem struct {
							 | 
						||
| 
								 | 
							
									routine, arg uintptr
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// C version is 40 bytes.
							 | 
						||
| 
								 | 
							
								type pthreadMutex struct {
							 | 
						||
| 
								 | 
							
									sync.Mutex            //  0	8
							 | 
						||
| 
								 | 
							
									count      int32      //  8	4
							 | 
						||
| 
								 | 
							
									mType      uint32     // 12	4
							 | 
						||
| 
								 | 
							
									outer      sync.Mutex // 16	8
							 | 
						||
| 
								 | 
							
									owner      int32      // 20	4
							 | 
						||
| 
								 | 
							
									//			 24
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								type pthreadConds struct {
							 | 
						||
| 
								 | 
							
									sync.Mutex
							 | 
						||
| 
								 | 
							
									conds map[uintptr][]chan struct{}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								var (
							 | 
						||
| 
								 | 
							
									// Ensure there's enough space for unsafe type conversions.
							 | 
						||
| 
								 | 
							
									_ [unsafe.Sizeof(sync.Mutex{}) - __CCGO_SIZEOF_GO_MUTEX]byte
							 | 
						||
| 
								 | 
							
									_ [unsafe.Sizeof(Tpthread_mutex_t{}) - unsafe.Sizeof(pthreadMutex{})]byte
							 | 
						||
| 
								 | 
							
									_ [unsafe.Sizeof(Tpthread_attr_t{}) - unsafe.Sizeof(pthreadAttr{})]byte
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									pthreadKeysMutex      sync.Mutex
							 | 
						||
| 
								 | 
							
									pthreadKeyDestructors []uintptr
							 | 
						||
| 
								 | 
							
									pthreadKeysFree       []Tpthread_key_t
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									conds = pthreadConds{conds: map[uintptr][]chan struct{}{}}
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func _pthread_setcancelstate(tls *TLS, new int32, old uintptr) int32 {
							 | 
						||
| 
								 | 
							
									//TODO actually respect cancel state
							 | 
						||
| 
								 | 
							
									if uint32(new) > 2 {
							 | 
						||
| 
								 | 
							
										return EINVAL
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									p := tls.pthread + unsafe.Offsetof(t__pthread{}.Fcanceldisable)
							 | 
						||
| 
								 | 
							
									if old != 0 {
							 | 
						||
| 
								 | 
							
										r := *(*int32)(unsafe.Pointer(p))
							 | 
						||
| 
								 | 
							
										*(*int32)(unsafe.Pointer(old)) = int32(byte(r))
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									*(*int32)(unsafe.Pointer(p)) = new
							 | 
						||
| 
								 | 
							
									return 0
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func Xpthread_getspecific(tls *TLS, k Tpthread_key_t) uintptr {
							 | 
						||
| 
								 | 
							
									return tls.pthreadKeyValues[k]
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func Xpthread_setspecific(tls *TLS, k Tpthread_key_t, x uintptr) int32 {
							 | 
						||
| 
								 | 
							
									if tls.pthreadKeyValues == nil {
							 | 
						||
| 
								 | 
							
										tls.pthreadKeyValues = map[Tpthread_key_t]uintptr{}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									tls.pthreadKeyValues[k] = x
							 | 
						||
| 
								 | 
							
									return 0
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func Xpthread_key_create(tls *TLS, k uintptr, dtor uintptr) int32 {
							 | 
						||
| 
								 | 
							
									pthreadKeysMutex.Lock()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									defer pthreadKeysMutex.Unlock()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									var key Tpthread_key_t
							 | 
						||
| 
								 | 
							
									switch l := Tpthread_key_t(len(pthreadKeysFree)); {
							 | 
						||
| 
								 | 
							
									case l == 0:
							 | 
						||
| 
								 | 
							
										key = Tpthread_key_t(len(pthreadKeyDestructors))
							 | 
						||
| 
								 | 
							
										pthreadKeyDestructors = append(pthreadKeyDestructors, dtor)
							 | 
						||
| 
								 | 
							
									default:
							 | 
						||
| 
								 | 
							
										key = pthreadKeysFree[l-1]
							 | 
						||
| 
								 | 
							
										pthreadKeysFree = pthreadKeysFree[:l-1]
							 | 
						||
| 
								 | 
							
										pthreadKeyDestructors[key] = dtor
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									*(*Tpthread_key_t)(unsafe.Pointer(k)) = key
							 | 
						||
| 
								 | 
							
									return 0
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func Xpthread_key_delete(tls *TLS, k Tpthread_key_t) int32 {
							 | 
						||
| 
								 | 
							
									pthreadKeysMutex.Lock()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									defer pthreadKeysMutex.Unlock()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									pthreadKeysFree = append(pthreadKeysFree, k)
							 | 
						||
| 
								 | 
							
									return 0
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func Xpthread_create(tls *TLS, res, attrp, entry, arg uintptr) int32 {
							 | 
						||
| 
								 | 
							
									var attr pthreadAttr
							 | 
						||
| 
								 | 
							
									if attrp != 0 {
							 | 
						||
| 
								 | 
							
										attr = *(*pthreadAttr)(unsafe.Pointer(attrp))
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									detachState := int32(_DT_JOINABLE)
							 | 
						||
| 
								 | 
							
									if attr.detachState != 0 {
							 | 
						||
| 
								 | 
							
										detachState = _DT_DETACHED
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									tls2 := NewTLS()
							 | 
						||
| 
								 | 
							
									tls2.ownsPthread = false
							 | 
						||
| 
								 | 
							
									*(*Tpthread_t)(unsafe.Pointer(res)) = tls2.pthread
							 | 
						||
| 
								 | 
							
									(*t__pthread)(unsafe.Pointer(tls2.pthread)).Fdetach_state = detachState
							 | 
						||
| 
								 | 
							
									if detachState == _DT_JOINABLE {
							 | 
						||
| 
								 | 
							
										(*sync.Mutex)(unsafe.Pointer(tls2.pthread + unsafe.Offsetof(t__pthread{}.F__ccgo_join_mutex))).Lock()
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									go func() {
							 | 
						||
| 
								 | 
							
										Xpthread_exit(tls2, (*(*func(*TLS, uintptr) uintptr)(unsafe.Pointer(&struct{ uintptr }{entry})))(tls2, arg))
							 | 
						||
| 
								 | 
							
									}()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return 0
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func Xpthread_exit(tls *TLS, result uintptr) {
							 | 
						||
| 
								 | 
							
									state := atomic.LoadInt32((*int32)(unsafe.Pointer(tls.pthread + unsafe.Offsetof(t__pthread{}.Fdetach_state))))
							 | 
						||
| 
								 | 
							
									(*t__pthread)(unsafe.Pointer(tls.pthread)).Fresult = result
							 | 
						||
| 
								 | 
							
									switch state {
							 | 
						||
| 
								 | 
							
									case _DT_JOINABLE, _DT_DETACHED:
							 | 
						||
| 
								 | 
							
										// ok
							 | 
						||
| 
								 | 
							
									default:
							 | 
						||
| 
								 | 
							
										panic(todo("", state))
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									for len(tls.pthreadCleanupItems) != 0 {
							 | 
						||
| 
								 | 
							
										Xpthread_cleanup_pop(tls, 1)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									for {
							 | 
						||
| 
								 | 
							
										done := true
							 | 
						||
| 
								 | 
							
										for k, v := range tls.pthreadKeyValues {
							 | 
						||
| 
								 | 
							
											if v != 0 {
							 | 
						||
| 
								 | 
							
												delete(tls.pthreadKeyValues, k)
							 | 
						||
| 
								 | 
							
												pthreadKeysMutex.Lock()
							 | 
						||
| 
								 | 
							
												d := pthreadKeyDestructors[k]
							 | 
						||
| 
								 | 
							
												pthreadKeysMutex.Unlock()
							 | 
						||
| 
								 | 
							
												if d != 0 {
							 | 
						||
| 
								 | 
							
													done = false
							 | 
						||
| 
								 | 
							
													(*(*func(*TLS, uintptr))(unsafe.Pointer(&struct{ uintptr }{d})))(tls, v)
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										if done {
							 | 
						||
| 
								 | 
							
											break
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									if state == _DT_JOINABLE {
							 | 
						||
| 
								 | 
							
										(*sync.Mutex)(unsafe.Pointer(tls.pthread + unsafe.Offsetof(t__pthread{}.F__ccgo_join_mutex))).Unlock()
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									atomic.StoreInt32((*int32)(unsafe.Pointer(tls.pthread+unsafe.Offsetof(t__pthread{}.Fdetach_state))), _DT_EXITED)
							 | 
						||
| 
								 | 
							
									tls.Close()
							 | 
						||
| 
								 | 
							
									runtime.Goexit()
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func Xpthread_join(tls *TLS, t Tpthread_t, res uintptr) (r int32) {
							 | 
						||
| 
								 | 
							
									if (*t__pthread)(unsafe.Pointer(t)).Fdetach_state > _DT_JOINABLE {
							 | 
						||
| 
								 | 
							
										return EINVAL
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									(*sync.Mutex)(unsafe.Pointer(t + unsafe.Offsetof(t__pthread{}.F__ccgo_join_mutex))).Lock()
							 | 
						||
| 
								 | 
							
									if res != 0 {
							 | 
						||
| 
								 | 
							
										*(*uintptr)(unsafe.Pointer(res)) = (*t__pthread)(unsafe.Pointer(tls.pthread)).Fresult
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return 0
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func Xpthread_cleanup_push(tls *TLS, f, x uintptr) {
							 | 
						||
| 
								 | 
							
									X_pthread_cleanup_push(tls, 0, f, x)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func __pthread_cleanup_push(tls *TLS, _, f, x uintptr) {
							 | 
						||
| 
								 | 
							
									tls.pthreadCleanupItems = append(tls.pthreadCleanupItems, pthreadCleanupItem{f, x})
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func X_pthread_cleanup_push(tls *TLS, _, f, x uintptr) {
							 | 
						||
| 
								 | 
							
									tls.pthreadCleanupItems = append(tls.pthreadCleanupItems, pthreadCleanupItem{f, x})
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func Xpthread_cleanup_pop(tls *TLS, run int32) {
							 | 
						||
| 
								 | 
							
									X_pthread_cleanup_pop(tls, 0, run)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func __pthread_cleanup_pop(tls *TLS, _ uintptr, run int32) {
							 | 
						||
| 
								 | 
							
									X_pthread_cleanup_pop(tls, 0, run)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func X_pthread_cleanup_pop(tls *TLS, _ uintptr, run int32) {
							 | 
						||
| 
								 | 
							
									l := len(tls.pthreadCleanupItems)
							 | 
						||
| 
								 | 
							
									item := tls.pthreadCleanupItems[l-1]
							 | 
						||
| 
								 | 
							
									tls.pthreadCleanupItems = tls.pthreadCleanupItems[:l-1]
							 | 
						||
| 
								 | 
							
									if run != 0 {
							 | 
						||
| 
								 | 
							
										(*(*func(*TLS, uintptr))(unsafe.Pointer(&struct{ uintptr }{item.routine})))(tls, item.arg)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func Xpthread_attr_init(tls *TLS, a uintptr) int32 {
							 | 
						||
| 
								 | 
							
									*(*Tpthread_attr_t)(unsafe.Pointer(a)) = Tpthread_attr_t{}
							 | 
						||
| 
								 | 
							
									return 0
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func Xpthread_attr_setscope(tls *TLS, a uintptr, scope int32) int32 {
							 | 
						||
| 
								 | 
							
									switch scope {
							 | 
						||
| 
								 | 
							
									case PTHREAD_SCOPE_SYSTEM:
							 | 
						||
| 
								 | 
							
										return 0
							 | 
						||
| 
								 | 
							
									case PTHREAD_SCOPE_PROCESS:
							 | 
						||
| 
								 | 
							
										return ENOTSUP
							 | 
						||
| 
								 | 
							
									default:
							 | 
						||
| 
								 | 
							
										return EINVAL
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func Xpthread_attr_setstacksize(tls *TLS, a uintptr, stacksite Tsize_t) int32 {
							 | 
						||
| 
								 | 
							
									return 0
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func Xpthread_attr_setdetachstate(tls *TLS, a uintptr, state int32) (r int32) {
							 | 
						||
| 
								 | 
							
									if uint32(state) > 1 {
							 | 
						||
| 
								 | 
							
										return EINVAL
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									(*pthreadAttr)(unsafe.Pointer(a)).detachState = state
							 | 
						||
| 
								 | 
							
									return 0
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func Xpthread_attr_getdetachstate(tls *TLS, a uintptr, state uintptr) int32 {
							 | 
						||
| 
								 | 
							
									*(*int32)(unsafe.Pointer(state)) = (*pthreadAttr)(unsafe.Pointer(a)).detachState
							 | 
						||
| 
								 | 
							
									return 0
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func Xpthread_attr_destroy(tls *TLS, a uintptr) int32 {
							 | 
						||
| 
								 | 
							
									return 0
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func Xpthread_self(tls *TLS) uintptr {
							 | 
						||
| 
								 | 
							
									return tls.pthread
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func Xpthread_mutex_init(tls *TLS, m, a uintptr) int32 {
							 | 
						||
| 
								 | 
							
									*(*Tpthread_mutex_t)(unsafe.Pointer(m)) = Tpthread_mutex_t{}
							 | 
						||
| 
								 | 
							
									if a != 0 {
							 | 
						||
| 
								 | 
							
										(*pthreadMutex)(unsafe.Pointer(m)).mType = (*Tpthread_mutexattr_t)(unsafe.Pointer(a)).F__attr
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return 0
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func Xpthread_mutex_destroy(tls *TLS, mutex uintptr) int32 {
							 | 
						||
| 
								 | 
							
									return 0
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func Xpthread_mutex_lock(tls *TLS, m uintptr) int32 {
							 | 
						||
| 
								 | 
							
									(*pthreadMutex)(unsafe.Pointer(m)).outer.Lock()
							 | 
						||
| 
								 | 
							
									owner := (*pthreadMutex)(unsafe.Pointer(m)).owner
							 | 
						||
| 
								 | 
							
									typ := (*pthreadMutex)(unsafe.Pointer(m)).mType
							 | 
						||
| 
								 | 
							
									switch typ {
							 | 
						||
| 
								 | 
							
									case PTHREAD_MUTEX_NORMAL:
							 | 
						||
| 
								 | 
							
										(*pthreadMutex)(unsafe.Pointer(m)).owner = tls.ID
							 | 
						||
| 
								 | 
							
										(*pthreadMutex)(unsafe.Pointer(m)).outer.Unlock()
							 | 
						||
| 
								 | 
							
										(*pthreadMutex)(unsafe.Pointer(m)).Lock()
							 | 
						||
| 
								 | 
							
									case PTHREAD_MUTEX_RECURSIVE:
							 | 
						||
| 
								 | 
							
										switch owner {
							 | 
						||
| 
								 | 
							
										case 0:
							 | 
						||
| 
								 | 
							
											(*pthreadMutex)(unsafe.Pointer(m)).count = 1
							 | 
						||
| 
								 | 
							
											(*pthreadMutex)(unsafe.Pointer(m)).owner = tls.ID
							 | 
						||
| 
								 | 
							
											(*pthreadMutex)(unsafe.Pointer(m)).outer.Unlock()
							 | 
						||
| 
								 | 
							
											(*pthreadMutex)(unsafe.Pointer(m)).Lock()
							 | 
						||
| 
								 | 
							
											return 0
							 | 
						||
| 
								 | 
							
										case tls.ID:
							 | 
						||
| 
								 | 
							
											(*pthreadMutex)(unsafe.Pointer(m)).count++
							 | 
						||
| 
								 | 
							
											(*pthreadMutex)(unsafe.Pointer(m)).outer.Unlock()
							 | 
						||
| 
								 | 
							
											return 0
							 | 
						||
| 
								 | 
							
										default:
							 | 
						||
| 
								 | 
							
										wait:
							 | 
						||
| 
								 | 
							
											(*pthreadMutex)(unsafe.Pointer(m)).outer.Unlock()
							 | 
						||
| 
								 | 
							
											(*pthreadMutex)(unsafe.Pointer(m)).Lock()
							 | 
						||
| 
								 | 
							
											(*pthreadMutex)(unsafe.Pointer(m)).outer.Lock()
							 | 
						||
| 
								 | 
							
											if (*pthreadMutex)(unsafe.Pointer(m)).owner != 0 {
							 | 
						||
| 
								 | 
							
												goto wait
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											(*pthreadMutex)(unsafe.Pointer(m)).count = 1
							 | 
						||
| 
								 | 
							
											(*pthreadMutex)(unsafe.Pointer(m)).owner = tls.ID
							 | 
						||
| 
								 | 
							
											(*pthreadMutex)(unsafe.Pointer(m)).outer.Unlock()
							 | 
						||
| 
								 | 
							
											return 0
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									default:
							 | 
						||
| 
								 | 
							
										panic(todo("typ=%v", typ))
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return 0
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func Xpthread_mutex_trylock(tls *TLS, m uintptr) int32 {
							 | 
						||
| 
								 | 
							
									(*pthreadMutex)(unsafe.Pointer(m)).outer.Lock()
							 | 
						||
| 
								 | 
							
									owner := (*pthreadMutex)(unsafe.Pointer(m)).owner
							 | 
						||
| 
								 | 
							
									typ := (*pthreadMutex)(unsafe.Pointer(m)).mType
							 | 
						||
| 
								 | 
							
									switch typ {
							 | 
						||
| 
								 | 
							
									case PTHREAD_MUTEX_NORMAL:
							 | 
						||
| 
								 | 
							
										if owner != 0 {
							 | 
						||
| 
								 | 
							
											(*pthreadMutex)(unsafe.Pointer(m)).outer.Unlock()
							 | 
						||
| 
								 | 
							
											return EBUSY
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										(*pthreadMutex)(unsafe.Pointer(m)).owner = tls.ID
							 | 
						||
| 
								 | 
							
										(*pthreadMutex)(unsafe.Pointer(m)).outer.Unlock()
							 | 
						||
| 
								 | 
							
										(*pthreadMutex)(unsafe.Pointer(m)).Lock()
							 | 
						||
| 
								 | 
							
										return 0
							 | 
						||
| 
								 | 
							
									default:
							 | 
						||
| 
								 | 
							
										panic(todo("typ=%v", typ))
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func Xpthread_mutex_unlock(tls *TLS, m uintptr) int32 {
							 | 
						||
| 
								 | 
							
									(*pthreadMutex)(unsafe.Pointer(m)).outer.Lock()
							 | 
						||
| 
								 | 
							
									count := (*pthreadMutex)(unsafe.Pointer(m)).count
							 | 
						||
| 
								 | 
							
									owner := (*pthreadMutex)(unsafe.Pointer(m)).owner
							 | 
						||
| 
								 | 
							
									typ := (*pthreadMutex)(unsafe.Pointer(m)).mType
							 | 
						||
| 
								 | 
							
									switch typ {
							 | 
						||
| 
								 | 
							
									case PTHREAD_MUTEX_NORMAL:
							 | 
						||
| 
								 | 
							
										(*pthreadMutex)(unsafe.Pointer(m)).outer.Unlock()
							 | 
						||
| 
								 | 
							
										(*pthreadMutex)(unsafe.Pointer(m)).Unlock()
							 | 
						||
| 
								 | 
							
										return 0
							 | 
						||
| 
								 | 
							
									case PTHREAD_MUTEX_RECURSIVE:
							 | 
						||
| 
								 | 
							
										switch owner {
							 | 
						||
| 
								 | 
							
										case tls.ID:
							 | 
						||
| 
								 | 
							
											switch count {
							 | 
						||
| 
								 | 
							
											case 1:
							 | 
						||
| 
								 | 
							
												(*pthreadMutex)(unsafe.Pointer(m)).owner = 0
							 | 
						||
| 
								 | 
							
												(*pthreadMutex)(unsafe.Pointer(m)).outer.Unlock()
							 | 
						||
| 
								 | 
							
												(*pthreadMutex)(unsafe.Pointer(m)).Unlock()
							 | 
						||
| 
								 | 
							
												return 0
							 | 
						||
| 
								 | 
							
											default:
							 | 
						||
| 
								 | 
							
												(*pthreadMutex)(unsafe.Pointer(m)).count--
							 | 
						||
| 
								 | 
							
												(*pthreadMutex)(unsafe.Pointer(m)).outer.Unlock()
							 | 
						||
| 
								 | 
							
												return 0
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										default:
							 | 
						||
| 
								 | 
							
											panic(todo("", owner, tls.ID))
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									default:
							 | 
						||
| 
								 | 
							
										panic(todo("", typ))
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func Xpthread_cond_init(tls *TLS, c, a uintptr) int32 {
							 | 
						||
| 
								 | 
							
									*(*Tpthread_cond_t)(unsafe.Pointer(c)) = Tpthread_cond_t{}
							 | 
						||
| 
								 | 
							
									if a != 0 {
							 | 
						||
| 
								 | 
							
										panic(todo(""))
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									conds.Lock()
							 | 
						||
| 
								 | 
							
									delete(conds.conds, c)
							 | 
						||
| 
								 | 
							
									conds.Unlock()
							 | 
						||
| 
								 | 
							
									return 0
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func Xpthread_cond_timedwait(tls *TLS, c, m, ts uintptr) (r int32) {
							 | 
						||
| 
								 | 
							
									var to <-chan time.Time
							 | 
						||
| 
								 | 
							
									if ts != 0 {
							 | 
						||
| 
								 | 
							
										deadlineSecs := (*Ttimespec)(unsafe.Pointer(ts)).Ftv_sec
							 | 
						||
| 
								 | 
							
										deadlineNsecs := (*Ttimespec)(unsafe.Pointer(ts)).Ftv_nsec
							 | 
						||
| 
								 | 
							
										deadline := time.Unix(deadlineSecs, deadlineNsecs)
							 | 
						||
| 
								 | 
							
										d := deadline.Sub(time.Now())
							 | 
						||
| 
								 | 
							
										if d <= 0 {
							 | 
						||
| 
								 | 
							
											return ETIMEDOUT
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										to = time.After(d)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									conds.Lock()
							 | 
						||
| 
								 | 
							
									waiters := conds.conds[c]
							 | 
						||
| 
								 | 
							
									ch := make(chan struct{}, 1)
							 | 
						||
| 
								 | 
							
									waiters = append(waiters, ch)
							 | 
						||
| 
								 | 
							
									conds.conds[c] = waiters
							 | 
						||
| 
								 | 
							
									conds.Unlock()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									defer func() {
							 | 
						||
| 
								 | 
							
										conds.Lock()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										defer conds.Unlock()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										waiters = conds.conds[c]
							 | 
						||
| 
								 | 
							
										for i, v := range waiters {
							 | 
						||
| 
								 | 
							
											if v == ch {
							 | 
						||
| 
								 | 
							
												conds.conds[c] = slices.Delete(waiters, i, i+1)
							 | 
						||
| 
								 | 
							
												return
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									switch typ := (*pthreadMutex)(unsafe.Pointer(m)).mType; typ {
							 | 
						||
| 
								 | 
							
									case PTHREAD_MUTEX_NORMAL:
							 | 
						||
| 
								 | 
							
										(*pthreadMutex)(unsafe.Pointer(m)).owner = 0
							 | 
						||
| 
								 | 
							
										(*pthreadMutex)(unsafe.Pointer(m)).Unlock()
							 | 
						||
| 
								 | 
							
										select {
							 | 
						||
| 
								 | 
							
										case <-ch:
							 | 
						||
| 
								 | 
							
											// ok
							 | 
						||
| 
								 | 
							
										case <-to:
							 | 
						||
| 
								 | 
							
											r = ETIMEDOUT
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										(*pthreadMutex)(unsafe.Pointer(m)).owner = tls.ID
							 | 
						||
| 
								 | 
							
										(*pthreadMutex)(unsafe.Pointer(m)).Lock()
							 | 
						||
| 
								 | 
							
										return r
							 | 
						||
| 
								 | 
							
									default:
							 | 
						||
| 
								 | 
							
										panic(todo("", typ))
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func Xpthread_cond_wait(tls *TLS, c, m uintptr) int32 {
							 | 
						||
| 
								 | 
							
									return Xpthread_cond_timedwait(tls, c, m, 0)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func Xpthread_cond_signal(tls *TLS, c uintptr) int32 {
							 | 
						||
| 
								 | 
							
									return pthreadSignalN(tls, c, false)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func pthreadSignalN(tls *TLS, c uintptr, all bool) int32 {
							 | 
						||
| 
								 | 
							
									conds.Lock()
							 | 
						||
| 
								 | 
							
									waiters := conds.conds[c]
							 | 
						||
| 
								 | 
							
									handle := waiters
							 | 
						||
| 
								 | 
							
									if len(waiters) != 0 {
							 | 
						||
| 
								 | 
							
										switch {
							 | 
						||
| 
								 | 
							
										case all:
							 | 
						||
| 
								 | 
							
											delete(conds.conds, c)
							 | 
						||
| 
								 | 
							
										default:
							 | 
						||
| 
								 | 
							
											handle = handle[:1]
							 | 
						||
| 
								 | 
							
											conds.conds[c] = waiters[1:]
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									conds.Unlock()
							 | 
						||
| 
								 | 
							
									for _, v := range handle {
							 | 
						||
| 
								 | 
							
										close(v)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return 0
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func Xpthread_cond_broadcast(tls *TLS, c uintptr) int32 {
							 | 
						||
| 
								 | 
							
									return pthreadSignalN(tls, c, true)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func Xpthread_cond_destroy(tls *TLS, c uintptr) int32 {
							 | 
						||
| 
								 | 
							
									return Xpthread_cond_broadcast(tls, c)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func Xpthread_atfork(tls *TLS, prepare, parent, child uintptr) int32 {
							 | 
						||
| 
								 | 
							
									// fork(2) not supported.
							 | 
						||
| 
								 | 
							
									return 0
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func Xpthread_mutexattr_init(tls *TLS, a uintptr) int32 {
							 | 
						||
| 
								 | 
							
									*(*Tpthread_mutexattr_t)(unsafe.Pointer(a)) = Tpthread_mutexattr_t{}
							 | 
						||
| 
								 | 
							
									return 0
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func Xpthread_mutexattr_destroy(tls *TLS, a uintptr) int32 {
							 | 
						||
| 
								 | 
							
									return 0
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func Xpthread_mutexattr_settype(tls *TLS, a uintptr, typ int32) int32 {
							 | 
						||
| 
								 | 
							
									if uint32(typ) > 2 {
							 | 
						||
| 
								 | 
							
										return EINVAL
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									(*Tpthread_mutexattr_t)(unsafe.Pointer(a)).F__attr = uint32(typ) & 3
							 | 
						||
| 
								 | 
							
									return 0
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func Xpthread_detach(tls *TLS, t uintptr) int32 {
							 | 
						||
| 
								 | 
							
									state := atomic.SwapInt32((*int32)(unsafe.Pointer(tls.pthread+unsafe.Offsetof(t__pthread{}.Fdetach_state))), _DT_DETACHED)
							 | 
						||
| 
								 | 
							
									switch state {
							 | 
						||
| 
								 | 
							
									case _DT_EXITED, _DT_DETACHED:
							 | 
						||
| 
								 | 
							
										return 0
							 | 
						||
| 
								 | 
							
									default:
							 | 
						||
| 
								 | 
							
										panic(todo("", tls.ID, state))
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// int pthread_equal(pthread_t, pthread_t);
							 | 
						||
| 
								 | 
							
								func Xpthread_equal(tls *TLS, t, u uintptr) int32 {
							 | 
						||
| 
								 | 
							
									return Bool32(t == u)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// int pthread_sigmask(int how, const sigset_t *restrict set, sigset_t *restrict old)
							 | 
						||
| 
								 | 
							
								func _pthread_sigmask(tls *TLS, now int32, set, old uintptr) int32 {
							 | 
						||
| 
								 | 
							
									// ignored
							 | 
						||
| 
								 | 
							
									return 0
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// 202402251838      all_test.go:589: files=36 buildFails=30 execFails=2 pass=4
							 | 
						||
| 
								 | 
							
								// 202402262246      all_test.go:589: files=36 buildFails=26 execFails=2 pass=8
							 | 
						||
| 
								 | 
							
								// 202403041858 all_musl_test.go:640: files=36 buildFails=22 execFails=4 pass=10
							 |