2 * Copyright 2008-2013, Haiku Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
5 #ifndef _KERNEL_SYSCALL_RESTART_H
6 #define _KERNEL_SYSCALL_RESTART_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.
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();
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
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) {
55 timeout
+= system_time();
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
);
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
);
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
107 TODO: this function is actually needed as part of the public API for ioctl()
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()
128 atomic_or(&fThread
->flags
, THREAD_FLAGS_SYSCALL
);
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
)
162 operator Type() const { return fResult
; }
170 #endif // _KERNEL_SYSCALL_RESTART_H