[822] | 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 | }
|
---|