btrfs: [] on the end of a struct field is a variable length array.
[haiku.git] / headers / private / kernel / syscall_restart.h
blob88ac6aaafc4393c971032d83811e4f83d85bd590
1 /*
2 * Copyright 2008-2013, 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
9 #include <OS.h>
11 #include <thread.h>
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.
19 static inline void
20 syscall_restart_handle_timeout_pre(bigtime_t& timeout)
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;
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.
41 static inline void
42 syscall_restart_handle_timeout_pre(uint32& flags, bigtime_t& timeout)
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;
60 flags = (flags & ~B_RELATIVE_TIMEOUT) | B_ABSOLUTE_TIMEOUT;
66 static inline status_t
67 syscall_restart_handle_timeout_post(status_t error, bigtime_t timeout)
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);
76 return error;
80 static inline status_t
81 syscall_restart_handle_post(status_t error)
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);
89 return error;
93 static inline bool
94 syscall_restart_is_restarted()
96 Thread* thread = thread_get_current_thread();
98 return (thread->flags & THREAD_FLAGS_SYSCALL) != 0
99 && (thread->flags & THREAD_FLAGS_SYSCALL_RESTARTED) != 0;
103 /*! Returns whether or not a function has been called via a syscall. The flag
104 to determine this is currently only used where actually needed, such as
105 ioctl().
107 TODO: this function is actually needed as part of the public API for ioctl()
109 static inline bool
110 is_called_via_syscall(void)
112 Thread* thread = thread_get_current_thread();
113 return (thread->flags & THREAD_FLAGS_SYSCALL) != 0;
117 struct SyscallFlagUnsetter {
118 SyscallFlagUnsetter()
120 fThread = thread_get_current_thread();
121 fWasSyscall = (atomic_and(&fThread->flags, ~THREAD_FLAGS_SYSCALL)
122 & THREAD_FLAGS_SYSCALL) != 0;
125 ~SyscallFlagUnsetter()
127 if (fWasSyscall)
128 atomic_or(&fThread->flags, THREAD_FLAGS_SYSCALL);
131 private:
132 Thread* fThread;
133 bool fWasSyscall;
137 template<typename Type>
138 struct SyscallRestartWrapper {
139 SyscallRestartWrapper(Type initialValue = 0)
140 : fResult(initialValue)
142 fThread = thread_get_current_thread();
143 atomic_or(&fThread->flags, THREAD_FLAGS_SYSCALL);
146 ~SyscallRestartWrapper()
148 if (fResult == B_INTERRUPTED) {
149 // interrupted -- set flag for syscall restart
150 atomic_or(&fThread->flags, THREAD_FLAGS_RESTART_SYSCALL);
153 atomic_and(&fThread->flags, ~THREAD_FLAGS_SYSCALL);
156 SyscallRestartWrapper<Type>& operator=(const Type& other)
158 fResult = other;
159 return *this;
162 operator Type() const { return fResult; }
164 private:
165 Type fResult;
166 Thread* fThread;
170 #endif // _KERNEL_SYSCALL_RESTART_H