thread-linux.c 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. // Copyright 2009 The Go 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. #include "runtime.h"
  5. #include "defs.h"
  6. #include "signal_unix.h"
  7. // Linux futex.
  8. //
  9. // futexsleep(uint32 *addr, uint32 val)
  10. // futexwakeup(uint32 *addr)
  11. //
  12. // Futexsleep atomically checks if *addr == val and if so, sleeps on addr.
  13. // Futexwakeup wakes up threads sleeping on addr.
  14. // Futexsleep is allowed to wake up spuriously.
  15. #include <errno.h>
  16. #include <string.h>
  17. #include <time.h>
  18. #include <sys/types.h>
  19. #include <sys/stat.h>
  20. #include <fcntl.h>
  21. #include <unistd.h>
  22. #include <syscall.h>
  23. #include <linux/futex.h>
  24. typedef struct timespec Timespec;
  25. // Atomically,
  26. // if(*addr == val) sleep
  27. // Might be woken up spuriously; that's allowed.
  28. // Don't sleep longer than ns; ns < 0 means forever.
  29. void
  30. runtime_futexsleep(uint32 *addr, uint32 val, int64 ns)
  31. {
  32. Timespec ts;
  33. int32 nsec;
  34. // Some Linux kernels have a bug where futex of
  35. // FUTEX_WAIT returns an internal error code
  36. // as an errno. Libpthread ignores the return value
  37. // here, and so can we: as it says a few lines up,
  38. // spurious wakeups are allowed.
  39. if(ns < 0) {
  40. syscall(__NR_futex, addr, FUTEX_WAIT, val, nil, nil, 0);
  41. return;
  42. }
  43. ts.tv_sec = runtime_timediv(ns, 1000000000LL, &nsec);
  44. ts.tv_nsec = nsec;
  45. syscall(__NR_futex, addr, FUTEX_WAIT, val, &ts, nil, 0);
  46. }
  47. // If any procs are sleeping on addr, wake up at most cnt.
  48. void
  49. runtime_futexwakeup(uint32 *addr, uint32 cnt)
  50. {
  51. int64 ret;
  52. ret = syscall(__NR_futex, addr, FUTEX_WAKE, cnt, nil, nil, 0);
  53. if(ret >= 0)
  54. return;
  55. // I don't know that futex wakeup can return
  56. // EAGAIN or EINTR, but if it does, it would be
  57. // safe to loop and call futex again.
  58. runtime_printf("futexwakeup addr=%p returned %D\n", addr, ret);
  59. *(int32*)0x1006 = 0x1006;
  60. }
  61. void
  62. runtime_osinit(void)
  63. {
  64. runtime_ncpu = getproccount();
  65. }
  66. void
  67. runtime_goenvs(void)
  68. {
  69. runtime_goenvs_unix();
  70. }