medfall

A super great game engine
Log | Files | Refs

pthread.hpp (14515B)


      1 /*  Relacy Race Detector
      2  *  Copyright (c) 2008-2013, Dmitry S. Vyukov
      3  *  All rights reserved.
      4  *  This software is provided AS-IS with no warranty, either express or implied.
      5  *  This software is distributed under a license and may not be copied,
      6  *  modified or distributed except as expressly authorized under the
      7  *  terms of the license contained in the file LICENSE in this distribution.
      8  */
      9 
     10 #ifndef RL_PTHREAD_HPP
     11 #define RL_PTHREAD_HPP
     12 #ifdef _MSC_VER
     13 #   pragma once
     14 #endif
     15 
     16 #include "mutex.hpp"
     17 #include "condition_variable.hpp"
     18 #include "semaphore.hpp"
     19 
     20 
     21 namespace rl
     22 {
     23 
     24 enum RL_POSIX_ERROR_CODE
     25 {
     26     RL_SUCCESS,
     27     RL_EINVAL,
     28     RL_ETIMEDOUT,
     29     RL_EBUSY,
     30     RL_EINTR,
     31     RL_EAGAIN,
     32     RL_EWOULDBLOCK,
     33 };
     34 
     35 
     36 inline void rl_sched_yield(debug_info_param info)
     37 {
     38     yield(1, info);
     39 }
     40 
     41 
     42 typedef win_waitable_object* rl_pthread_t;
     43 typedef void* rl_pthread_attr_t;
     44 
     45 inline int rl_pthread_create(rl_pthread_t* th, rl_pthread_attr_t* attr, void* (*func) (void*), void* arg, debug_info_param info)
     46 {
     47     (void)attr;
     48     (void)info;//!!!
     49     RL_VERIFY(th && func);
     50     th[0] = ctx().create_thread(func, arg);
     51     return 0;
     52 }
     53 
     54 inline int rl_pthread_join(rl_pthread_t th, void** res, debug_info_param info)
     55 {
     56     RL_VERIFY(th && res);
     57     res[0] = 0; //!!!
     58     th->wait(false, false, info);
     59     return 0;
     60 }
     61 
     62 
     63 
     64 
     65 struct sem_tag_pthread;
     66 typedef semaphore<sem_tag_pthread> rl_sem_t;
     67 
     68 inline int rl_sem_init(rl_sem_t* sema, int /*pshared*/, unsigned int initial_count, debug_info_param info)
     69 {
     70     RL_VERIFY(initial_count >= 0);
     71     sema->init(true, initial_count, INT_MAX, info);
     72     return 0;
     73 }
     74 
     75 inline int rl_sem_destroy(rl_sem_t* sema, debug_info_param info)
     76 {
     77     sema->deinit(info);
     78     return 0;
     79 }
     80 
     81 inline int rl_sem_wait(rl_sem_t* sema, debug_info_param info)
     82 {
     83     sema_wakeup_reason reason = sema->wait(false, false, info);
     84     if (reason == sema_wakeup_reason_success)
     85         return 0;
     86     if (reason == sema_wakeup_reason_spurious)
     87     {
     88         set_errno(RL_EINTR);
     89         return -1;
     90     }
     91     RL_VERIFY(false);
     92     return -1;
     93 }
     94 
     95 inline int rl_sem_trywait(rl_sem_t* sema, debug_info_param info)
     96 {
     97     sema_wakeup_reason reason = sema->wait(true, false, info);
     98     if (sema_wakeup_reason_success == reason)
     99         return 0;
    100     if (sema_wakeup_reason_failed == reason)
    101     {
    102         set_errno(RL_EAGAIN);
    103         return -1;
    104     }
    105     if (sema_wakeup_reason_spurious == reason)
    106     {
    107         set_errno(RL_EINTR);
    108         return -1;
    109     }
    110     RL_VERIFY(false);
    111     return -1;
    112 }
    113 
    114 inline int rl_sem_post(rl_sem_t* sema, debug_info_param info)
    115 {
    116     unsigned prev_cout = 0;
    117     bool result = sema->post(1, prev_cout, info);
    118     RL_VERIFY(result);
    119     (void)result;
    120     return 0;
    121 }
    122 
    123 inline int rl_sem_getvalue(rl_sem_t* sema, int* value, debug_info_param info)
    124 {
    125     RL_VERIFY(value);
    126     if (value)
    127         value[0] = sema->get_value(info);
    128     return 0;
    129 }
    130 
    131 
    132 
    133 
    134 struct mutex_tag_pthread_mtx;
    135 typedef generic_mutex<mutex_tag_pthread_mtx> rl_pthread_mutex_t;
    136 
    137 struct rl_pthread_mutexattr_t
    138 {
    139     bool is_recursive_;
    140 };
    141 
    142 enum RL_PTHREAD_MUTEX_TYPE
    143 {
    144     RL_PTHREAD_MUTEX_NORMAL,
    145     RL_PTHREAD_MUTEX_ERRORCHECK,
    146     RL_PTHREAD_MUTEX_RECURSIVE,
    147     RL_PTHREAD_MUTEX_DEFAULT,
    148 };
    149 
    150 inline int rl_pthread_mutexattr_init(rl_pthread_mutexattr_t* attr, debug_info_param info)
    151 {
    152     (void)info;
    153     if (0 == attr)
    154         return RL_EINVAL;
    155     attr->is_recursive_ = false;
    156     return 0;
    157 }
    158 
    159 inline int rl_pthread_mutexattr_destroy(rl_pthread_mutexattr_t* attr, debug_info_param info)
    160 {
    161     (void)info;
    162     if (0 == attr)
    163         return RL_EINVAL;
    164     return 0;
    165 }
    166 
    167 inline int rl_pthread_mutexattr_settype(rl_pthread_mutexattr_t* attr, int type, debug_info_param info)
    168 {
    169     (void)info;
    170     if (0 == attr)
    171         return RL_EINVAL;
    172     if (RL_PTHREAD_MUTEX_RECURSIVE == type)
    173         attr->is_recursive_ = true;
    174     return 0;
    175 }
    176 
    177 inline int rl_pthread_mutex_init(rl_pthread_mutex_t* m, rl_pthread_mutexattr_t const* attr, debug_info_param info)
    178 {
    179     bool is_recursive = attr && attr->is_recursive_;
    180     m->init(false, is_recursive, false, false, info);
    181     return 0;
    182 }
    183 
    184 inline int rl_pthread_mutex_destroy(rl_pthread_mutex_t* m, debug_info_param info)
    185 {
    186     m->deinit(info);
    187     return 0;
    188 }
    189 
    190 inline int rl_pthread_mutex_lock(rl_pthread_mutex_t* m, debug_info_param info)
    191 {
    192     m->lock_exclusive(info);
    193     return 0;
    194 }
    195 
    196 inline int rl_pthread_mutex_timedlock(rl_pthread_mutex_t* m, const void* abs_timeout, debug_info_param info)
    197 {
    198     (void)abs_timeout;
    199     bool rv = m->lock_exclusive_timed(info);
    200     return rv ? 0 : RL_ETIMEDOUT;
    201 }
    202 
    203 inline int rl_pthread_mutex_try_lock(rl_pthread_mutex_t* m, debug_info_param info)
    204 {
    205     return m->try_lock_exclusive(info) ? 0 : 1;
    206 }
    207 
    208 inline int rl_pthread_mutex_unlock(rl_pthread_mutex_t* m, debug_info_param info)
    209 {
    210     m->unlock_exclusive(info);
    211     return 0;
    212 }
    213 
    214 
    215 
    216 struct mutex_tag_pthread_rwlock;
    217 typedef generic_mutex<mutex_tag_pthread_rwlock> rl_pthread_rwlock_t;
    218 
    219 inline int rl_pthread_rwlock_init(rl_pthread_rwlock_t* lock, void const* /*attr*/, debug_info_param info)
    220 {
    221     lock->init(true, false, true, false, info);
    222     return 0;
    223 }
    224 
    225 inline int rl_pthread_rwlock_destroy(rl_pthread_rwlock_t* lock, debug_info_param info)
    226 {
    227     lock->deinit(info);
    228     return 0;
    229 }
    230 
    231 inline int rl_pthread_rwlock_rdlock(rl_pthread_rwlock_t* lock, debug_info_param info)
    232 {
    233     lock->lock_shared(info);
    234     return 0;
    235 }
    236 
    237 inline int rl_pthread_rwlock_tryrdlock(rl_pthread_rwlock_t* lock, debug_info_param info)
    238 {
    239     bool res = lock->try_lock_shared(info);
    240     return res ? 0 : RL_EBUSY;
    241 }
    242 
    243 inline int rl_pthread_rwlock_wrlock(rl_pthread_rwlock_t* lock, debug_info_param info)
    244 {
    245     lock->lock_exclusive(info);
    246     return 0;
    247 }
    248 
    249 inline int rl_pthread_rwlock_trywrlock(rl_pthread_rwlock_t* lock, debug_info_param info)
    250 {
    251     bool res = lock->try_lock_exclusive(info);
    252     return res ? 0 : RL_EBUSY;
    253 }
    254 
    255 inline int rl_pthread_rwlock_unlock(rl_pthread_rwlock_t* lock, debug_info_param info)
    256 {
    257     lock->unlock_exclusive_or_shared(info);
    258     return 0;
    259 }
    260 
    261 
    262 
    263 
    264 struct condvar_tag_pthread;
    265 typedef condvar<condvar_tag_pthread> rl_pthread_cond_t;
    266 typedef int rl_pthread_condattr_t;
    267 
    268 inline int rl_pthread_cond_init(rl_pthread_cond_t* cv, rl_pthread_condattr_t* /*condattr*/, debug_info_param info)
    269 {
    270     cv->init(true, info);
    271     return 0;
    272 }
    273 
    274 inline int rl_pthread_cond_destroy(rl_pthread_cond_t* cv, debug_info_param info)
    275 {
    276     cv->deinit(info);
    277     return 0;
    278 }
    279 
    280 inline int rl_pthread_cond_broadcast(rl_pthread_cond_t* cv, debug_info_param info)
    281 {
    282     cv->notify_all(info);
    283     return 0;
    284 }
    285 
    286 inline int rl_pthread_cond_signal(rl_pthread_cond_t* cv, debug_info_param info)
    287 {
    288     cv->notify_one(info);
    289     return 0;
    290 }
    291 
    292 inline int rl_pthread_cond_timedwait(rl_pthread_cond_t* cv, rl_pthread_mutex_t* m, void const* /*timespec*/, debug_info_param info)
    293 {
    294     sema_wakeup_reason res = cv->wait(*m, true, info);
    295     if (res == sema_wakeup_reason_success)
    296         return 0;
    297     else if (res == sema_wakeup_reason_timeout)
    298         return RL_ETIMEDOUT;
    299     else if (res == sema_wakeup_reason_spurious)
    300         return RL_EINTR;
    301     else 
    302         return RL_EINVAL;
    303 }
    304 
    305 inline int rl_pthread_cond_wait(rl_pthread_cond_t* cv, rl_pthread_mutex_t* m, debug_info_param info)
    306 {
    307     sema_wakeup_reason res = cv->wait(*m, false, info);
    308     if (res == sema_wakeup_reason_success)
    309         return 0;
    310     else if (res == sema_wakeup_reason_spurious)
    311         return RL_EINTR;
    312     else 
    313         return RL_EINVAL;
    314 }
    315 
    316 	
    317 	
    318 	
    319 enum RL_FUTEX_OP
    320 {
    321     RL_FUTEX_WAIT,
    322     RL_FUTEX_WAKE,
    323 };
    324 
    325 inline int rl_int_futex_impl(context& c,
    326                     atomic<int>* uaddr,
    327                     int op,
    328                     int val,
    329                     struct timespec const* timeout,
    330                     atomic<int>* uaddr2,
    331                     int val3,
    332                     debug_info_param info)
    333 {
    334     (void)uaddr2;
    335     (void)val3;
    336     if (op == RL_FUTEX_WAIT)
    337     {
    338         c.sched();
    339         c.atomic_thread_fence_seq_cst();
    340         int v0;
    341         {
    342             preemption_disabler pd (c);
    343             v0 = uaddr->load(mo_acquire, info);
    344         }
    345 	if (v0 != val)
    346             return RL_EWOULDBLOCK;
    347         unpark_reason reason = uaddr->wait(c, timeout != 0, true, info);
    348         if (reason == unpark_reason_normal)
    349             return 0;
    350         else if (reason == unpark_reason_timeout)
    351             return RL_ETIMEDOUT;
    352         else if (reason == unpark_reason_spurious)
    353             return RL_EINTR;
    354         RL_VERIFY(false);
    355         return RL_EINVAL;
    356     }
    357     else if (op == RL_FUTEX_WAKE)
    358     {
    359         if (val <= 0)
    360             return 0;
    361 
    362         c.sched();
    363         c.atomic_thread_fence_seq_cst();
    364         return uaddr->wake(c, val, info);
    365     }
    366     else
    367     {
    368         return RL_EINVAL;
    369     }
    370 }
    371 
    372     struct futex_event
    373     {
    374         void* addr_;
    375         int   op_;
    376         int   val_;
    377         bool  timeout_;
    378         int   res_;
    379 
    380         void output(std::ostream& s) const
    381         {
    382             s << "<" << std::hex << addr_ << std::dec << "> futex("
    383               << (op_ == RL_FUTEX_WAIT ? "FUTEX_WAIT" : op_ == RL_FUTEX_WAKE ? "FUTEX_WAKE" : "UNSUPPORTED") << ", "
    384               << val_ << ", " << timeout_ << ") = ";
    385             if (op_ == RL_FUTEX_WAKE)
    386                 s << res_;
    387             else
    388                 s << (res_ == RL_EWOULDBLOCK ? "EWOULDBLOCK" : res_ == RL_ETIMEDOUT ? "ETIMEDOUT" : res_ == RL_EINTR ? "EINTR" : "UNKNOWN");
    389         }
    390     };
    391 	
    392 inline int rl_futex(atomic<int>* uaddr,
    393                     int op,
    394                     int val,
    395                     struct timespec const* timeout,
    396                     atomic<int>* uaddr2,
    397                     int val3,
    398                     debug_info_param info)
    399 {
    400     context& c = ctx();
    401     int res = rl_int_futex_impl(c, uaddr, op, val, timeout, uaddr2, val3, info);
    402     RL_HIST(futex_event) {uaddr, op, val, timeout != 0, res} RL_HIST_END();
    403     return res;    
    404 }
    405 
    406 }
    407 
    408 
    409 
    410 #ifdef EINVAL
    411 #   undef EINVAL
    412 #endif
    413 #define EINVAL                  rl::RL_EINVAL
    414 
    415 #ifdef ETIMEDOUT
    416 #   undef ETIMEDOUT
    417 #endif
    418 #define ETIMEDOUT               rl::RL_ETIMEDOUT
    419 
    420 #ifdef EBUSY
    421 #   undef EBUSY
    422 #endif
    423 #define EBUSY                   rl::RL_EBUSY
    424 
    425 #ifdef EINTR
    426 #   undef EINTR
    427 #endif
    428 #define EINTR                   rl::RL_EINTR
    429 
    430 #ifdef EAGAIN
    431 #   undef EAGAIN
    432 #endif
    433 #define EAGAIN                  rl::RL_EAGAIN
    434 
    435 #ifdef EWOULDBLOCK
    436 #   undef EWOULDBLOCK
    437 #endif
    438 #define EWOULDBLOCK                  rl::RL_EWOULDBLOCK
    439 
    440 #define sched_yield() \
    441  rl::rl_sched_yield($)
    442 
    443 #define pthread_yield() \
    444  rl::rl_sched_yield($)
    445 
    446 
    447 
    448 #define pthread_t rl::rl_pthread_t
    449 #define pthread_attr_t rl::rl_pthread_attr_t
    450 
    451 #define pthread_create(th, attr, func, arg) \
    452  rl::rl_pthread_create(th, attr, func, arg, $)
    453 
    454 #define pthread_join(th, res) \
    455  rl::rl_pthread_join(th, res, $)
    456 
    457 
    458 
    459 
    460 #define sem_t rl::rl_sem_t
    461 
    462 #define sem_init(sema, pshared, initial_count)\
    463  rl::rl_sem_init(sema, pshared, initial_count, $)
    464 
    465 #define sem_destroy(sema)\
    466  rl::rl_sem_destroy(sema, $)
    467 
    468 #define sem_wait(sema)\
    469  rl::rl_sem_wait(sema, $)
    470 
    471 #define sem_trywait(sema)\
    472  rl::rl_sem_trywait(sema, $)
    473 
    474 #define sem_post(sema)\
    475 rl::rl_sem_post(sema, $)
    476 
    477 #define sem_getvalue(sema, pvalue)\
    478  rl::rl_sem_getvalue(sema, pvalue, $)
    479 
    480 
    481 
    482 
    483 
    484 #define pthread_mutex_t             rl::rl_pthread_mutex_t
    485 #define pthread_mutexattr_t         rl::rl_pthread_mutexattr_t
    486 
    487 #ifdef PTHREAD_MUTEX_NORMAL
    488 #   undef PTHREAD_MUTEX_NORMAL
    489 #   undef PTHREAD_MUTEX_ERRORCHECK
    490 #   undef PTHREAD_MUTEX_RECURSIVE
    491 #   undef PTHREAD_MUTEX_DEFAULT
    492 #endif
    493 
    494 #define PTHREAD_MUTEX_NORMAL        rl::RL_PTHREAD_MUTEX_NORMAL
    495 #define PTHREAD_MUTEX_ERRORCHECK    rl::RL_PTHREAD_MUTEX_ERRORCHECK
    496 #define PTHREAD_MUTEX_RECURSIVE     rl::RL_PTHREAD_MUTEX_RECURSIVE
    497 #define PTHREAD_MUTEX_DEFAULT       rl::RL_PTHREAD_MUTEX_DEFAULT
    498 
    499 #define pthread_mutexattr_init(attr) \
    500  rl::rl_pthread_mutexattr_init(attr, $)
    501 
    502 #define pthread_mutexattr_destroy(attr) \
    503  rl::rl_pthread_mutexattr_destroy(attr, $)
    504 
    505 #define pthread_mutexattr_settype(attr, type) \
    506  rl::rl_pthread_mutexattr_settype(attr, type, $)
    507 
    508 #define pthread_mutex_init(m, attr) \
    509  rl::rl_pthread_mutex_init(m, attr, $)
    510 
    511 #define pthread_mutex_destroy(m) \
    512  rl::rl_pthread_mutex_destroy(m, $)
    513 
    514 #define pthread_mutex_lock(m) \
    515  rl::rl_pthread_mutex_lock(m, $)
    516 
    517 #define pthread_mutex_timedlock(m, abs_timeout) \
    518  rl::rl_pthread_mutex_timedlock(m, abs_timeout, $)
    519 
    520 #define pthread_mutex_try_lock(m) \
    521  rl::rl_pthread_mutex_try_lock(m, $)
    522 
    523 #define pthread_mutex_unlock(m) \
    524  rl::rl_pthread_mutex_unlock(m, $)
    525 
    526 #define pthread_rwlock_t rl::rl_pthread_rwlock_t
    527 
    528 #define pthread_rwlock_init(lock, attr) \
    529  rl::rl_pthread_rwlock_init(lock, attr, $)
    530 
    531 #define pthread_rwlock_destroy(lock) \
    532  rl::rl_pthread_rwlock_destroy(lock, $)
    533 
    534 #define pthread_rwlock_rdlock(lock) \
    535  rl::rl_pthread_rwlock_rdlock(lock, $)
    536 
    537 #define pthread_rwlock_tryrdlock(lock) \
    538  rl::rl_pthread_rwlock_tryrdlock(lock, $)
    539 
    540 #define pthread_rwlock_wrlock(lock) \
    541  rl::rl_pthread_rwlock_wrlock(lock, $)
    542 
    543 #define pthread_rwlock_trywrlock(lock) \
    544  rl::rl_pthread_rwlock_trywrlock(lock, $)
    545 
    546 #define pthread_rwlock_unlock(lock) \
    547  rl::rl_pthread_rwlock_unlock(lock, $)
    548 
    549 
    550 
    551 
    552 #define pthread_cond_t rl::rl_pthread_cond_t
    553 #define pthread_condattr_t rl::rl_pthread_condattr_t
    554 
    555 #define pthread_cond_init(cv, condattr) \
    556  rl::rl_pthread_cond_init(cv, condattr, $)
    557 
    558 #define pthread_cond_destroy(cv) \
    559  rl::rl_pthread_cond_destroy(cv, $)
    560 
    561 #define pthread_cond_broadcast(cv) \
    562  rl::rl_pthread_cond_broadcast(cv, $)
    563 
    564 #define pthread_cond_signal(cv) \
    565  rl::rl_pthread_cond_signal(cv, $)
    566 
    567 #define pthread_cond_timedwait(cv, m, timespec) \
    568  rl::rl_pthread_cond_timedwait(cv, m, timespec, $)
    569 
    570 #define pthread_cond_wait(cv, m) \
    571  rl::rl_pthread_cond_wait(cv, m, $)
    572 
    573 
    574 
    575 #ifdef FUTEX_WAKE
    576 #   undef FUTEX_WAKE
    577 #endif
    578 #define FUTEX_WAKE                  rl::RL_FUTEX_WAKE
    579 
    580 #ifdef FUTEX_WAIT
    581 #   undef FUTEX_WAIT
    582 #endif
    583 #define FUTEX_WAIT                  rl::RL_FUTEX_WAIT
    584 
    585 #define futex(uaddr, op, val, timeout, uaddr2, val3) \
    586  rl::rl_futex(uaddr, op, val, timeout, uaddr2, val3, $)
    587 
    588 #endif
    589 
    590