wrappers.odin 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. #+build linux
  2. package linux
  3. /// Low 8 bits of the exit code
  4. /// Only retrieve the exit code if WIFEXITED(s) = true
  5. WEXITSTATUS :: #force_inline proc "contextless" (s: u32) -> u32 {
  6. return (s & 0xff00) >> 8
  7. }
  8. /// Termination signal
  9. /// Only retrieve the code if WIFSIGNALED(s) = true
  10. WTERMSIG :: #force_inline proc "contextless" (s: u32) -> u32 {
  11. return s & 0x7f
  12. }
  13. /// The signal that stopped the child
  14. /// Only retrieve if WIFSTOPPED(s) = true
  15. WSTOPSIG :: #force_inline proc "contextless" (s: u32) -> u32 {
  16. return WEXITSTATUS(s)
  17. }
  18. /// Check if the process terminated normally (via exit.2)
  19. WIFEXITED :: #force_inline proc "contextless" (s: u32) -> bool {
  20. return WTERMSIG(s) == 0
  21. }
  22. /// Check if the process signaled
  23. WIFSIGNALED :: #force_inline proc "contextless" (s: u32) -> bool {
  24. return cast(i8)(((s) & 0x7f) + 1) >> 1 > 0
  25. }
  26. /// Check if the process has stopped
  27. WIFSTOPPED :: #force_inline proc "contextless" (s: u32) -> bool {
  28. return (s & 0xff) == 0x7f
  29. }
  30. /// Check if the process is continued by the tracee
  31. WIFCONTINUED :: #force_inline proc "contextless" (s: u32) -> bool {
  32. return s == 0xffff
  33. }
  34. /// Check if the process dumped core
  35. WCOREDUMP :: #force_inline proc "contextless" (s: u32) -> bool {
  36. return s & 0x80 == 0x80
  37. }
  38. @private _sigmask :: proc "contextless" (sig: Signal) -> (uint) {
  39. return 1 << ((cast(uint)(sig) - 1) % (8*size_of(uint)))
  40. }
  41. @private _sigword :: proc "contextless" (sig: Signal) -> (uint) {
  42. return (cast(uint)sig - 1) / (8*size_of(uint))
  43. }
  44. // TODO: sigaddset etc
  45. /*
  46. Iterate the results of `getdents()`.
  47. This procedure extracts a directory entry from `buf` at the offset `offs`.
  48. `offs` will be modified to store an offset to the possible next directory entry
  49. in `buf`. The procedure only iterates as much data as loaded in the buffer and
  50. does not automatically make a request for the buffer to be refilled.
  51. Inputs:
  52. - buf: A byte buffer with data from `getdents()`
  53. - offs: An offset to the next possible directory entry in `buf`
  54. Returns:
  55. - A pointer to a directory entry in `buf`, or `nil`
  56. - A bool value denoting if a valid directory entry is returned
  57. Example:
  58. import "core:fmt"
  59. import "core:sys/linux"
  60. print_names :: proc(dirfd: linux.Fd) {
  61. // Get dirents into a buffer.
  62. buf: [128]u8
  63. // Loop until there are no more entries.
  64. for {
  65. written, err := linux.getdents(dirfd, buf[:])
  66. if err != .NONE || written == 0 {
  67. break
  68. }
  69. // Print the names of the files.
  70. offset : int
  71. for dir in linux.dirent_iterate_buf(buf[:written], &offset) {
  72. name := linux.dirent_name(dir)
  73. fmt.println(name)
  74. }
  75. }
  76. }
  77. */
  78. dirent_iterate_buf :: proc "contextless" (buf: []u8, offs: ^int) -> (d: ^Dirent, cont: bool) {
  79. // Stopped iterating when there's no space left
  80. if offs^ >= len(buf) {
  81. return nil, false
  82. }
  83. // Retrieve dirent form the current offset
  84. dirent := cast(^Dirent) &buf[offs^]
  85. // Add the stride of dirent struct to the current offset
  86. offs^ += cast(int) dirent.reclen
  87. return dirent, true
  88. }
  89. /*
  90. Obtain the name of dirent as a string.
  91. The lifetime of the returned string is bound to the lifetime of the provided dirent structure.
  92. Inputs:
  93. - dirent: A directory entry
  94. Returns:
  95. - A name of the entry
  96. */
  97. dirent_name :: proc "contextless" (dirent: ^Dirent) -> string #no_bounds_check {
  98. str := ([^]u8)(&dirent.name)
  99. // Dirents are aligned to 8 bytes, so there is guaranteed to be a null
  100. // terminator in the last 8 bytes.
  101. str_size := int(dirent.reclen) - cast(int)offset_of(Dirent, name)
  102. trunc := min(str_size, 8)
  103. str_size -= trunc
  104. for _ in 0..<trunc {
  105. if str[str_size] == 0 {
  106. break
  107. }
  108. str_size += 1
  109. }
  110. return string(str[:str_size])
  111. }
  112. /// Constructor for the `futex_op` argument of a FUTEX_WAKE_OP call
  113. futex_op :: proc "contextless" (arg_op: Futex_Arg_Op, cmp_op: Futex_Cmp_Op, op_arg: u32, cmp_arg: u32) -> u32 {
  114. arg_op := cast(u32) arg_op
  115. cmp_op := cast(u32) cmp_op
  116. return (arg_op << 28) | (cmp_op << 24) | ((op_arg & 0xfff) << 12) | (cmp_arg & 0xfff)
  117. }
  118. /// Helper function for constructing the config for caches
  119. perf_cache_config :: #force_inline proc "contextless" (id: Perf_Hardware_Cache_Id,
  120. op: Perf_Hardware_Cache_Op_Id,
  121. res: Perf_Hardware_Cache_Result_Id) -> u64 {
  122. return u64(id) | (u64(op) << 8) | (u64(res) << 16)
  123. }