futex.c 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. #define _GNU_SOURCE
  2. #include <asm/prctl.h>
  3. #include <assert.h>
  4. #include <linux/futex.h>
  5. #include <malloc.h>
  6. #include <sched.h>
  7. #include <signal.h>
  8. #include <stdio.h>
  9. #include <sys/syscall.h>
  10. #include <sys/types.h>
  11. #include <sys/wait.h>
  12. #include <unistd.h>
  13. #include <errno.h>
  14. #include <pthread.h>
  15. // 64kB stack
  16. #define FIBER_STACK (1024 * 64)
  17. #define THREADS 2
  18. static int myfutex = 0;
  19. static int futex(int* uaddr, int futex_op, int val, const struct timespec* timeout, int* uaddr2,
  20. int val3) {
  21. return syscall(SYS_futex, uaddr, futex_op, val, timeout, uaddr, val3);
  22. }
  23. void* thread_function(void* argument) {
  24. int* ptr = (int*)argument;
  25. int rv;
  26. // Sleep on the futex
  27. rv = futex(&myfutex, FUTEX_WAIT_BITSET, 0, NULL, NULL, *ptr);
  28. assert(rv == 0);
  29. // printf("child thread %d awakened\n", getpid());
  30. return NULL;
  31. }
  32. int main(int argc, const char** argv) {
  33. pthread_t thread[THREADS];
  34. static int varx[THREADS];
  35. for (int i = 0; i < THREADS; i++) {
  36. varx[i] = (1 << i);
  37. int ret = pthread_create(&thread[i], NULL, &thread_function, &varx[i]);
  38. if (ret) {
  39. errno = ret;
  40. perror("pthread_create");
  41. _exit(2);
  42. }
  43. }
  44. printf("Waking up kiddos\n");
  45. /* Wake in reverse order */
  46. for (int i = THREADS - 1; i >= 0; i--) {
  47. int rv;
  48. int var = (1 << i);
  49. // Wake up the thread
  50. do {
  51. rv = futex(&myfutex, FUTEX_WAKE_BITSET, 1, NULL, NULL, var);
  52. if (rv == 0) {
  53. // the thread of thread_function() may not reach
  54. // futex(FUTEX_WAIT_BITSET) yet.
  55. // Wait for the thread to sleep and try again.
  56. // Since synchronization primitive, futex, is being tested,
  57. // futex can't be used here. resort to use sleep.
  58. sleep(1);
  59. }
  60. } while (rv == 0);
  61. printf("FUTEX_WAKE_BITSET i = %d rv = %d\n", i, rv);
  62. assert(rv == 1);
  63. // Wait for the child thread to exit
  64. int ret = pthread_join(thread[i], NULL);
  65. if (ret) {
  66. errno = ret;
  67. perror("pthread_join");
  68. _exit(3);
  69. }
  70. }
  71. printf("Woke all kiddos\n");
  72. return 0;
  73. }