gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

pthread.go (13081B)


      1 // Copyright 2021 The Libc Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 package libc // import "modernc.org/libc"
      6 
      7 import (
      8 	"runtime"
      9 	"sync"
     10 	"sync/atomic"
     11 	"time"
     12 	"unsafe"
     13 
     14 	"modernc.org/libc/errno"
     15 	"modernc.org/libc/pthread"
     16 	"modernc.org/libc/sys/types"
     17 	ctime "modernc.org/libc/time"
     18 )
     19 
     20 var (
     21 	mutexes   = map[uintptr]*mutex{}
     22 	mutexesMu sync.Mutex
     23 
     24 	threads   = map[int32]*TLS{}
     25 	threadsMu sync.Mutex
     26 
     27 	threadKey            pthread.Pthread_key_t
     28 	threadKeyDestructors = map[pthread.Pthread_key_t][]uintptr{} // key: []destructor
     29 	threadsKeysMu        sync.Mutex
     30 
     31 	conds   = map[uintptr]*cond{}
     32 	condsMu sync.Mutex
     33 )
     34 
     35 // Thread local storage.
     36 type TLS struct {
     37 	errnop uintptr
     38 	pthreadData
     39 	stack stackHeader
     40 
     41 	ID                 int32
     42 	reentryGuard       int32 // memgrind
     43 	stackHeaderBalance int32
     44 }
     45 
     46 var errno0 int32 // Temp errno for NewTLS
     47 
     48 func NewTLS() *TLS {
     49 	return newTLS(false)
     50 }
     51 
     52 func newTLS(detached bool) *TLS {
     53 	id := atomic.AddInt32(&tid, 1)
     54 	t := &TLS{ID: id, errnop: uintptr(unsafe.Pointer(&errno0))}
     55 	t.pthreadData.init(t, detached)
     56 	if memgrind {
     57 		atomic.AddInt32(&tlsBalance, 1)
     58 	}
     59 	t.errnop = t.Alloc(int(unsafe.Sizeof(int32(0))))
     60 	*(*int32)(unsafe.Pointer(t.errnop)) = 0
     61 	return t
     62 }
     63 
     64 // Pthread specific part of a TLS.
     65 type pthreadData struct {
     66 	done   chan struct{}
     67 	kv     map[pthread.Pthread_key_t]uintptr
     68 	retVal uintptr
     69 	wait   chan struct{} // cond var interaction
     70 
     71 	detached bool
     72 }
     73 
     74 func (d *pthreadData) init(t *TLS, detached bool) {
     75 	d.detached = detached
     76 	d.wait = make(chan struct{}, 1)
     77 	if detached {
     78 		return
     79 	}
     80 
     81 	d.done = make(chan struct{})
     82 
     83 	threadsMu.Lock()
     84 
     85 	defer threadsMu.Unlock()
     86 
     87 	threads[t.ID] = t
     88 }
     89 
     90 func (d *pthreadData) close(t *TLS) {
     91 	threadsMu.Lock()
     92 
     93 	defer threadsMu.Unlock()
     94 
     95 	delete(threads, t.ID)
     96 }
     97 
     98 // int pthread_attr_destroy(pthread_attr_t *attr);
     99 func Xpthread_attr_destroy(t *TLS, pAttr uintptr) int32 {
    100 	return 0
    101 }
    102 
    103 // int pthread_attr_setscope(pthread_attr_t *attr, int contentionscope);
    104 func Xpthread_attr_setscope(t *TLS, pAttr uintptr, contentionScope int32) int32 {
    105 	switch contentionScope {
    106 	case pthread.PTHREAD_SCOPE_SYSTEM:
    107 		return 0
    108 	default:
    109 		panic(todo("", contentionScope))
    110 	}
    111 }
    112 
    113 // int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);
    114 func Xpthread_attr_setstacksize(t *TLS, attr uintptr, stackSize types.Size_t) int32 {
    115 	panic(todo(""))
    116 }
    117 
    118 // Go side data of pthread_cond_t.
    119 type cond struct {
    120 	sync.Mutex
    121 	waiters map[*TLS]struct{}
    122 }
    123 
    124 func newCond() *cond {
    125 	return &cond{
    126 		waiters: map[*TLS]struct{}{},
    127 	}
    128 }
    129 
    130 func (c *cond) signal(all bool) int32 {
    131 	if c == nil {
    132 		return errno.EINVAL
    133 	}
    134 
    135 	c.Lock()
    136 
    137 	defer c.Unlock()
    138 
    139 	// The pthread_cond_broadcast() and pthread_cond_signal() functions shall have
    140 	// no effect if there are no threads currently blocked on cond.
    141 	for tls := range c.waiters {
    142 		tls.wait <- struct{}{}
    143 		delete(c.waiters, tls)
    144 		if !all {
    145 			break
    146 		}
    147 	}
    148 	return 0
    149 }
    150 
    151 // The pthread_cond_init() function shall initialize the condition variable
    152 // referenced by cond with attributes referenced by attr. If attr is NULL, the
    153 // default condition variable attributes shall be used; the effect is the same
    154 // as passing the address of a default condition variable attributes object.
    155 // Upon successful initialization, the state of the condition variable shall
    156 // become initialized.
    157 //
    158 // If successful, the pthread_cond_destroy() and pthread_cond_init() functions
    159 // shall return zero; otherwise, an error number shall be returned to indicate
    160 // the error.
    161 //
    162 // int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
    163 func Xpthread_cond_init(t *TLS, pCond, pAttr uintptr) int32 {
    164 	if pCond == 0 {
    165 		return errno.EINVAL
    166 	}
    167 
    168 	if pAttr != 0 {
    169 		panic(todo("%#x %#x", pCond, pAttr))
    170 	}
    171 
    172 	condsMu.Lock()
    173 
    174 	defer condsMu.Unlock()
    175 
    176 	conds[pCond] = newCond()
    177 	return 0
    178 }
    179 
    180 // int pthread_cond_destroy(pthread_cond_t *cond);
    181 func Xpthread_cond_destroy(t *TLS, pCond uintptr) int32 {
    182 	if pCond == 0 {
    183 		return errno.EINVAL
    184 	}
    185 
    186 	condsMu.Lock()
    187 
    188 	defer condsMu.Unlock()
    189 
    190 	cond := conds[pCond]
    191 	if cond == nil {
    192 		return errno.EINVAL
    193 	}
    194 
    195 	cond.Lock()
    196 
    197 	defer cond.Unlock()
    198 
    199 	if len(cond.waiters) != 0 {
    200 		return errno.EBUSY
    201 	}
    202 
    203 	delete(conds, pCond)
    204 	return 0
    205 }
    206 
    207 // int pthread_cond_signal(pthread_cond_t *cond);
    208 func Xpthread_cond_signal(t *TLS, pCond uintptr) int32 {
    209 	return condSignal(pCond, false)
    210 }
    211 
    212 // int pthread_cond_broadcast(pthread_cond_t *cond);
    213 func Xpthread_cond_broadcast(t *TLS, pCond uintptr) int32 {
    214 	return condSignal(pCond, true)
    215 }
    216 
    217 func condSignal(pCond uintptr, all bool) int32 {
    218 	if pCond == 0 {
    219 		return errno.EINVAL
    220 	}
    221 
    222 	condsMu.Lock()
    223 	cond := conds[pCond]
    224 	condsMu.Unlock()
    225 
    226 	return cond.signal(all)
    227 }
    228 
    229 // int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
    230 func Xpthread_cond_wait(t *TLS, pCond, pMutex uintptr) int32 {
    231 	if pCond == 0 {
    232 		return errno.EINVAL
    233 	}
    234 
    235 	condsMu.Lock()
    236 	cond := conds[pCond]
    237 	if cond == nil { // static initialized condition variables are valid
    238 		cond = newCond()
    239 		conds[pCond] = cond
    240 	}
    241 
    242 	cond.Lock()
    243 	cond.waiters[t] = struct{}{}
    244 	cond.Unlock()
    245 
    246 	condsMu.Unlock()
    247 
    248 	mutexesMu.Lock()
    249 	mu := mutexes[pMutex]
    250 	mutexesMu.Unlock()
    251 
    252 	mu.Unlock()
    253 	<-t.wait
    254 	mu.Lock()
    255 	return 0
    256 }
    257 
    258 // int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict abstime);
    259 func Xpthread_cond_timedwait(t *TLS, pCond, pMutex, pAbsTime uintptr) int32 {
    260 	if pCond == 0 {
    261 		return errno.EINVAL
    262 	}
    263 
    264 	condsMu.Lock()
    265 	cond := conds[pCond]
    266 	if cond == nil { // static initialized condition variables are valid
    267 		cond = newCond()
    268 		conds[pCond] = cond
    269 	}
    270 
    271 	cond.Lock()
    272 	cond.waiters[t] = struct{}{}
    273 	cond.Unlock()
    274 
    275 	condsMu.Unlock()
    276 
    277 	mutexesMu.Lock()
    278 	mu := mutexes[pMutex]
    279 	mutexesMu.Unlock()
    280 
    281 	deadlineSecs := (*ctime.Timespec)(unsafe.Pointer(pAbsTime)).Ftv_sec
    282 	deadlineNsecs := (*ctime.Timespec)(unsafe.Pointer(pAbsTime)).Ftv_nsec
    283 	deadline := time.Unix(int64(deadlineSecs), int64(deadlineNsecs))
    284 	d := deadline.Sub(time.Now())
    285 	switch {
    286 	case d <= 0:
    287 		return errno.ETIMEDOUT
    288 	default:
    289 		to := time.After(d)
    290 		mu.Unlock()
    291 
    292 		defer mu.Lock()
    293 
    294 		select {
    295 		case <-t.wait:
    296 			return 0
    297 		case <-to:
    298 			cond.Lock()
    299 
    300 			defer cond.Unlock()
    301 
    302 			delete(cond.waiters, t)
    303 			return errno.ETIMEDOUT
    304 		}
    305 	}
    306 }
    307 
    308 // Go side data of pthread_mutex_t
    309 type mutex struct {
    310 	sync.Mutex
    311 	typ  int // PTHREAD_MUTEX_NORMAL, ...
    312 	wait sync.Mutex
    313 
    314 	id  int32 // owner's t.ID
    315 	cnt int32
    316 
    317 	robust bool
    318 }
    319 
    320 func newMutex(typ int) *mutex {
    321 	return &mutex{
    322 		typ: typ,
    323 	}
    324 }
    325 
    326 func (m *mutex) lock(id int32) int32 {
    327 	if m.robust {
    328 		panic(todo(""))
    329 	}
    330 
    331 	// If successful, the pthread_mutex_lock() and pthread_mutex_unlock() functions
    332 	// shall return zero; otherwise, an error number shall be returned to indicate
    333 	// the error.
    334 	switch m.typ {
    335 	case pthread.PTHREAD_MUTEX_NORMAL:
    336 		// If the mutex type is PTHREAD_MUTEX_NORMAL, deadlock detection shall not be
    337 		// provided. Attempting to relock the mutex causes deadlock. If a thread
    338 		// attempts to unlock a mutex that it has not locked or a mutex which is
    339 		// unlocked, undefined behavior results.
    340 		m.Lock()
    341 		m.id = id
    342 		return 0
    343 	case pthread.PTHREAD_MUTEX_RECURSIVE:
    344 		for {
    345 			m.Lock()
    346 			switch m.id {
    347 			case 0:
    348 				m.cnt = 1
    349 				m.id = id
    350 				m.wait.Lock()
    351 				m.Unlock()
    352 				return 0
    353 			case id:
    354 				m.cnt++
    355 				m.Unlock()
    356 				return 0
    357 			}
    358 
    359 			m.Unlock()
    360 			m.wait.Lock()
    361 			m.wait.Unlock()
    362 		}
    363 	default:
    364 		panic(todo("", m.typ))
    365 	}
    366 }
    367 
    368 func (m *mutex) tryLock(id int32) int32 {
    369 	if m.robust {
    370 		panic(todo(""))
    371 	}
    372 
    373 	switch m.typ {
    374 	case pthread.PTHREAD_MUTEX_NORMAL:
    375 		return errno.EBUSY
    376 	case pthread.PTHREAD_MUTEX_RECURSIVE:
    377 		m.Lock()
    378 		switch m.id {
    379 		case 0:
    380 			m.cnt = 1
    381 			m.id = id
    382 			m.wait.Lock()
    383 			m.Unlock()
    384 			return 0
    385 		case id:
    386 			m.cnt++
    387 			m.Unlock()
    388 			return 0
    389 		}
    390 
    391 		m.Unlock()
    392 		return errno.EBUSY
    393 	default:
    394 		panic(todo("", m.typ))
    395 	}
    396 }
    397 
    398 func (m *mutex) unlock() int32 {
    399 	if m.robust {
    400 		panic(todo(""))
    401 	}
    402 
    403 	// If successful, the pthread_mutex_lock() and pthread_mutex_unlock() functions
    404 	// shall return zero; otherwise, an error number shall be returned to indicate
    405 	// the error.
    406 	switch m.typ {
    407 	case pthread.PTHREAD_MUTEX_NORMAL:
    408 		// If the mutex type is PTHREAD_MUTEX_NORMAL, deadlock detection shall not be
    409 		// provided. Attempting to relock the mutex causes deadlock. If a thread
    410 		// attempts to unlock a mutex that it has not locked or a mutex which is
    411 		// unlocked, undefined behavior results.
    412 		m.id = 0
    413 		m.Unlock()
    414 		return 0
    415 	case pthread.PTHREAD_MUTEX_RECURSIVE:
    416 		m.Lock()
    417 		m.cnt--
    418 		if m.cnt == 0 {
    419 			m.id = 0
    420 			m.wait.Unlock()
    421 		}
    422 		m.Unlock()
    423 		return 0
    424 	default:
    425 		panic(todo("", m.typ))
    426 	}
    427 }
    428 
    429 // int pthread_mutex_destroy(pthread_mutex_t *mutex);
    430 func Xpthread_mutex_destroy(t *TLS, pMutex uintptr) int32 {
    431 	mutexesMu.Lock()
    432 
    433 	defer mutexesMu.Unlock()
    434 
    435 	delete(mutexes, pMutex)
    436 	return 0
    437 }
    438 
    439 // int pthread_mutex_lock(pthread_mutex_t *mutex);
    440 func Xpthread_mutex_lock(t *TLS, pMutex uintptr) int32 {
    441 	mutexesMu.Lock()
    442 	mu := mutexes[pMutex]
    443 	if mu == nil { // static initialized mutexes are valid
    444 		mu = newMutex(int(X__ccgo_getMutexType(t, pMutex)))
    445 		mutexes[pMutex] = mu
    446 	}
    447 	mutexesMu.Unlock()
    448 	return mu.lock(t.ID)
    449 }
    450 
    451 // int pthread_mutex_trylock(pthread_mutex_t *mutex);
    452 func Xpthread_mutex_trylock(t *TLS, pMutex uintptr) int32 {
    453 	mutexesMu.Lock()
    454 	mu := mutexes[pMutex]
    455 	if mu == nil { // static initialized mutexes are valid
    456 		mu = newMutex(int(X__ccgo_getMutexType(t, pMutex)))
    457 		mutexes[pMutex] = mu
    458 	}
    459 	mutexesMu.Unlock()
    460 	return mu.tryLock(t.ID)
    461 }
    462 
    463 // int pthread_mutex_unlock(pthread_mutex_t *mutex);
    464 func Xpthread_mutex_unlock(t *TLS, pMutex uintptr) int32 {
    465 	mutexesMu.Lock()
    466 
    467 	defer mutexesMu.Unlock()
    468 
    469 	return mutexes[pMutex].unlock()
    470 }
    471 
    472 // int pthread_key_create(pthread_key_t *key, void (*destructor)(void*));
    473 func Xpthread_key_create(t *TLS, pKey, destructor uintptr) int32 {
    474 	threadsKeysMu.Lock()
    475 
    476 	defer threadsKeysMu.Unlock()
    477 
    478 	threadKey++
    479 	r := threadKey
    480 	if destructor != 0 {
    481 		threadKeyDestructors[r] = append(threadKeyDestructors[r], destructor)
    482 	}
    483 	*(*pthread.Pthread_key_t)(unsafe.Pointer(pKey)) = pthread.Pthread_key_t(r)
    484 	return 0
    485 }
    486 
    487 // int pthread_key_delete(pthread_key_t key);
    488 func Xpthread_key_delete(t *TLS, key pthread.Pthread_key_t) int32 {
    489 	if _, ok := t.kv[key]; ok {
    490 		delete(t.kv, key)
    491 		return 0
    492 	}
    493 
    494 	panic(todo(""))
    495 
    496 }
    497 
    498 // void *pthread_getspecific(pthread_key_t key);
    499 func Xpthread_getspecific(t *TLS, key pthread.Pthread_key_t) uintptr {
    500 	return t.kv[key]
    501 }
    502 
    503 // int pthread_setspecific(pthread_key_t key, const void *value);
    504 func Xpthread_setspecific(t *TLS, key pthread.Pthread_key_t, value uintptr) int32 {
    505 	if t.kv == nil {
    506 		t.kv = map[pthread.Pthread_key_t]uintptr{}
    507 	}
    508 	t.kv[key] = value
    509 	return 0
    510 }
    511 
    512 // int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
    513 func Xpthread_create(t *TLS, pThread, pAttr, startRoutine, arg uintptr) int32 {
    514 	fn := (*struct {
    515 		f func(*TLS, uintptr) uintptr
    516 	})(unsafe.Pointer(&struct{ uintptr }{startRoutine})).f
    517 	detached := pAttr != 0 && X__ccgo_pthreadAttrGetDetachState(t, pAttr) == pthread.PTHREAD_CREATE_DETACHED
    518 	tls := newTLS(detached)
    519 	*(*pthread.Pthread_t)(unsafe.Pointer(pThread)) = pthread.Pthread_t(tls.ID)
    520 
    521 	go func() {
    522 		Xpthread_exit(tls, fn(tls, arg))
    523 	}()
    524 
    525 	return 0
    526 }
    527 
    528 // int pthread_detach(pthread_t thread);
    529 func Xpthread_detach(t *TLS, thread pthread.Pthread_t) int32 {
    530 	threadsMu.Lock()
    531 	threads[int32(thread)].detached = true
    532 	threadsMu.Unlock()
    533 	return 0
    534 }
    535 
    536 // int pthread_equal(pthread_t t1, pthread_t t2);
    537 func Xpthread_equal(t *TLS, t1, t2 pthread.Pthread_t) int32 {
    538 	return Bool32(t1 == t2)
    539 }
    540 
    541 // void pthread_exit(void *value_ptr);
    542 func Xpthread_exit(t *TLS, value uintptr) {
    543 	t.retVal = value
    544 
    545 	// At thread exit, if a key value has a non-NULL destructor pointer, and the
    546 	// thread has a non-NULL value associated with that key, the value of the key
    547 	// is set to NULL, and then the function pointed to is called with the
    548 	// previously associated value as its sole argument. The order of destructor
    549 	// calls is unspecified if more than one destructor exists for a thread when it
    550 	// exits.
    551 	for k, v := range t.kv {
    552 		if v == 0 {
    553 			continue
    554 		}
    555 
    556 		threadsKeysMu.Lock()
    557 		destructors := threadKeyDestructors[k]
    558 		threadsKeysMu.Unlock()
    559 
    560 		for _, destructor := range destructors {
    561 			delete(t.kv, k)
    562 			panic(todo("%#x", destructor)) //TODO call destructor(v)
    563 		}
    564 	}
    565 
    566 	switch {
    567 	case t.detached:
    568 		threadsMu.Lock()
    569 		delete(threads, t.ID)
    570 		threadsMu.Unlock()
    571 	default:
    572 		close(t.done)
    573 	}
    574 	runtime.Goexit()
    575 }
    576 
    577 // int pthread_join(pthread_t thread, void **value_ptr);
    578 func Xpthread_join(t *TLS, thread pthread.Pthread_t, pValue uintptr) int32 {
    579 	threadsMu.Lock()
    580 	tls := threads[int32(thread)]
    581 	delete(threads, int32(thread))
    582 	threadsMu.Unlock()
    583 	<-tls.done
    584 	if pValue != 0 {
    585 		*(*uintptr)(unsafe.Pointer(pValue)) = tls.retVal
    586 	}
    587 	return 0
    588 }
    589 
    590 // pthread_t pthread_self(void);
    591 func Xpthread_self(t *TLS) pthread.Pthread_t {
    592 	return pthread.Pthread_t(t.ID)
    593 }