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