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