1 /* 2 * Copyright 2008, Haiku Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 */ 5 #ifndef _KERNEL_SYSCALL_RESTART_H 6 #define _KERNEL_SYSCALL_RESTART_H 7 8 #include <OS.h> 9 10 #include <thread.h> 11 12 13 /*! Helper function for syscalls with relative timeout. 14 Converts the given relative timeout to an absolute timeout or retrieves 15 the value from the syscall restart parameters, if the syscall has been 16 restarted. A negative value means infinite timeout. 17 */ 18 static inline void 19 syscall_restart_handle_timeout_pre(bigtime_t& timeout) 20 { 21 // If restarted, get the timeout from the restart parameters. Otherwise 22 // convert relative timeout to an absolute one. 23 struct thread* thread = thread_get_current_thread(); 24 if ((thread->flags & THREAD_FLAGS_SYSCALL_RESTARTED) != 0) 25 timeout = *(bigtime_t*)thread->syscall_restart.parameters; 26 else if (timeout >= 0) { 27 timeout += system_time(); 28 // deal with overflow 29 if (timeout < 0) 30 timeout = B_INFINITE_TIMEOUT; 31 } 32 } 33 34 35 /*! Helper function for syscalls with flags + timeout. 36 If necessary converts the given timeout to an absolute timeout or retrieves 37 the value from the syscall restart parameters, if the syscall has been 38 restarted. 39 */ 40 static inline void 41 syscall_restart_handle_timeout_pre(uint32& flags, bigtime_t& timeout) 42 { 43 // If restarted, get the timeout from the restart parameters. Otherwise 44 // convert relative timeout to an absolute one. Note that we preserve 45 // relative 0 us timeouts, so that the syscall can still decide whether to 46 // return B_WOULD_BLOCK instead of B_TIMED_OUT. 47 struct thread* thread = thread_get_current_thread(); 48 if ((thread->flags & THREAD_FLAGS_SYSCALL_RESTARTED) != 0) { 49 timeout = *(bigtime_t*)thread->syscall_restart.parameters; 50 if (timeout > 0 && (flags & B_RELATIVE_TIMEOUT) != 0) 51 flags = (flags & ~B_RELATIVE_TIMEOUT) | B_ABSOLUTE_TIMEOUT; 52 } else if ((flags & B_RELATIVE_TIMEOUT) != 0) { 53 if (timeout > 0) { 54 timeout += system_time(); 55 // deal with overflow 56 if (timeout < 0) 57 timeout = B_INFINITE_TIMEOUT; 58 59 flags = (flags & ~B_RELATIVE_TIMEOUT) | B_ABSOLUTE_TIMEOUT; 60 } 61 } 62 } 63 64 65 static inline status_t 66 syscall_restart_handle_timeout_post(status_t error, bigtime_t timeout) 67 { 68 if (error == B_INTERRUPTED) { 69 // interrupted -- store timeout and set flag for syscall restart 70 struct thread* thread = thread_get_current_thread(); 71 *(bigtime_t*)thread->syscall_restart.parameters = timeout; 72 atomic_or(&thread->flags, THREAD_FLAGS_RESTART_SYSCALL); 73 } 74 75 return error; 76 } 77 78 79 static inline status_t 80 syscall_restart_handle_post(status_t error) 81 { 82 if (error == B_INTERRUPTED) { 83 // interrupted -- set flag for syscall restart 84 struct thread* thread = thread_get_current_thread(); 85 atomic_or(&thread->flags, THREAD_FLAGS_RESTART_SYSCALL); 86 } 87 88 return error; 89 } 90 91 92 static inline bool 93 syscall_restart_is_restarted() 94 { 95 struct thread* thread = thread_get_current_thread(); 96 97 return (thread->flags & THREAD_FLAGS_SYSCALL) != 0 98 && (thread->flags & THREAD_FLAGS_SYSCALL_RESTARTED) != 0; 99 } 100 101 102 struct SyscallFlagUnsetter { 103 SyscallFlagUnsetter() 104 { 105 fThread = thread_get_current_thread(); 106 fWasSyscall = (atomic_and(&fThread->flags, ~THREAD_FLAGS_SYSCALL) 107 & THREAD_FLAGS_SYSCALL) != 0; 108 } 109 110 ~SyscallFlagUnsetter() 111 { 112 if (fWasSyscall) 113 atomic_or(&fThread->flags, THREAD_FLAGS_SYSCALL); 114 } 115 116 private: 117 struct thread* fThread; 118 bool fWasSyscall; 119 }; 120 121 122 template<typename Type> 123 struct SyscallRestartWrapper { 124 SyscallRestartWrapper(Type initialValue = 0) 125 : fResult(initialValue) 126 { 127 fThread = thread_get_current_thread(); 128 atomic_or(&fThread->flags, THREAD_FLAGS_SYSCALL); 129 } 130 131 ~SyscallRestartWrapper() 132 { 133 if (fResult == B_INTERRUPTED) { 134 // interrupted -- set flag for syscall restart 135 atomic_or(&fThread->flags, THREAD_FLAGS_RESTART_SYSCALL); 136 } 137 138 atomic_and(&fThread->flags, ~THREAD_FLAGS_SYSCALL); 139 } 140 141 SyscallRestartWrapper<Type>& operator=(const Type& other) 142 { 143 fResult = other; 144 return *this; 145 } 146 147 operator Type() const { return fResult; } 148 149 private: 150 Type fResult; 151 struct thread* fThread; 152 }; 153 154 155 #endif // _KERNEL_SYSCALL_RESTART_H 156