1 // Copyright 2016 The Fuchsia Authors
2 //
3 // Use of this source code is governed by a MIT-style
4 // license that can be found in the LICENSE file or at
5 // https://opensource.org/licenses/MIT
6
7 #include <err.h>
8 #include <inttypes.h>
9 #include <trace.h>
10
11 #include <kernel/event.h>
12 #include <kernel/lockdep.h>
13 #include <kernel/thread.h>
14 #include <platform.h>
15
16 #include <lib/ktrace.h>
17 #include <lib/user_copy/user_ptr.h>
18
19 #include <object/handle.h>
20 #include <object/port_dispatcher.h>
21 #include <object/process_dispatcher.h>
22 #include <object/wait_state_observer.h>
23
24 #include <fbl/inline_array.h>
25 #include <fbl/ref_ptr.h>
26
27 #include <zircon/types.h>
28
29 #include "priv.h"
30
31 #define LOCAL_TRACE 0
32
33 // TODO(ZX-1349) Re-lower this to 8.
34 constexpr uint32_t kMaxWaitHandleCount = 16u;
35
36 // ensure public headers agree
37 static_assert(ZX_WAIT_MANY_MAX_ITEMS == kMaxWaitHandleCount, "");
38
39 // zx_status_t zx_object_wait_one
sys_object_wait_one(zx_handle_t handle_value,zx_signals_t signals,zx_time_t deadline,user_out_ptr<zx_signals_t> observed)40 zx_status_t sys_object_wait_one(zx_handle_t handle_value,
41 zx_signals_t signals,
42 zx_time_t deadline,
43 user_out_ptr<zx_signals_t> observed) {
44 LTRACEF("handle %x\n", handle_value);
45
46 Event event;
47
48 zx_status_t result;
49 WaitStateObserver wait_state_observer;
50
51 auto up = ProcessDispatcher::GetCurrent();
52 {
53 Guard<fbl::Mutex> guard{up->handle_table_lock()};
54
55 Handle* handle = up->GetHandleLocked(handle_value);
56 if (!handle)
57 return ZX_ERR_BAD_HANDLE;
58 if (!handle->HasRights(ZX_RIGHT_WAIT))
59 return ZX_ERR_ACCESS_DENIED;
60
61 result = wait_state_observer.Begin(&event, handle, signals);
62 if (result != ZX_OK)
63 return result;
64 }
65
66 auto koid = static_cast<uint32_t>(up->GetKoidForHandle(handle_value));
67 ktrace(TAG_WAIT_ONE, koid, signals, (uint32_t)deadline, (uint32_t)(deadline >> 32));
68
69 const TimerSlack slack = up->GetTimerSlackPolicy();
70
71 // event_wait() will return ZX_OK if already signaled,
72 // even if the deadline has passed. It will return ZX_ERR_TIMED_OUT
73 // after the deadline passes if the event has not been
74 // signaled.
75 {
76 ThreadDispatcher::AutoBlocked by(ThreadDispatcher::Blocked::WAIT_ONE);
77 result = event.Wait(deadline, slack);
78 }
79
80 // Regardless of wait outcome, we must call End().
81 auto signals_state = wait_state_observer.End();
82
83 ktrace(TAG_WAIT_ONE_DONE, koid, signals_state, result, 0);
84
85 if (observed) {
86 zx_status_t status = observed.copy_to_user(signals_state);
87 if (status != ZX_OK)
88 return status;
89 }
90
91 if (signals_state & ZX_SIGNAL_HANDLE_CLOSED)
92 return ZX_ERR_CANCELED;
93
94 return result;
95 }
96
97 // zx_status_t zx_object_wait_many
sys_object_wait_many(user_inout_ptr<zx_wait_item_t> user_items,size_t count,zx_time_t deadline)98 zx_status_t sys_object_wait_many(user_inout_ptr<zx_wait_item_t> user_items, size_t count, zx_time_t deadline) {
99 LTRACEF("count %zu\n", count);
100
101 if (!count) {
102 // TODO(maniscalco): Replace this call with a call to thread_sleep_etc using the timer slack
103 // from the job policy (ZX-931).
104 zx_status_t result = thread_sleep_interruptable(deadline);
105 if (result != ZX_OK)
106 return result;
107 return ZX_ERR_TIMED_OUT;
108 }
109
110 if (count > kMaxWaitHandleCount)
111 return ZX_ERR_OUT_OF_RANGE;
112
113 zx_wait_item_t items[kMaxWaitHandleCount];
114 if (user_items.copy_array_from_user(items, count) != ZX_OK)
115 return ZX_ERR_INVALID_ARGS;
116
117 WaitStateObserver wait_state_observers[kMaxWaitHandleCount];
118 Event event;
119
120 auto up = ProcessDispatcher::GetCurrent();
121
122 // We may need to unwind (which can be done outside the lock).
123 zx_status_t result = ZX_OK;
124 size_t num_added = 0;
125 {
126 Guard<fbl::Mutex> guard{up->handle_table_lock()};
127
128 for (; num_added != count; ++num_added) {
129 Handle* handle = up->GetHandleLocked(items[num_added].handle);
130 if (!handle) {
131 result = ZX_ERR_BAD_HANDLE;
132 break;
133 }
134 if (!handle->HasRights(ZX_RIGHT_WAIT)) {
135 result = ZX_ERR_ACCESS_DENIED;
136 break;
137 }
138
139 result = wait_state_observers[num_added].Begin(&event, handle, items[num_added].waitfor);
140 if (result != ZX_OK)
141 break;
142 }
143 }
144 if (result != ZX_OK) {
145 for (size_t ix = 0; ix < num_added; ++ix)
146 wait_state_observers[ix].End();
147 return result;
148 }
149
150 const TimerSlack slack = up->GetTimerSlackPolicy();
151
152 // event_wait() will return ZX_OK if already signaled,
153 // even if deadline has passed. It will return ZX_ERR_TIMED_OUT
154 // after the deadline passes if the event has not been
155 // signaled.
156 {
157 ThreadDispatcher::AutoBlocked by(ThreadDispatcher::Blocked::WAIT_MANY);
158 result = event.Wait(deadline, slack);
159 }
160
161 // Regardless of wait outcome, we must call End().
162 zx_signals_t combined = 0;
163 for (size_t ix = 0; ix != count; ++ix) {
164 combined |= (items[ix].pending = wait_state_observers[ix].End());
165 }
166
167 if (user_items.copy_array_to_user(items, count) != ZX_OK)
168 return ZX_ERR_INVALID_ARGS;
169
170 if (combined & ZX_SIGNAL_HANDLE_CLOSED)
171 return ZX_ERR_CANCELED;
172
173 return result;
174 }
175
176 // zx_status_t zx_object_wait_async
sys_object_wait_async(zx_handle_t handle_value,zx_handle_t port_handle,uint64_t key,zx_signals_t signals,uint32_t options)177 zx_status_t sys_object_wait_async(zx_handle_t handle_value, zx_handle_t port_handle,
178 uint64_t key, zx_signals_t signals, uint32_t options) {
179 LTRACEF("handle %x\n", handle_value);
180
181 auto up = ProcessDispatcher::GetCurrent();
182
183 fbl::RefPtr<PortDispatcher> port;
184 auto status = up->GetDispatcherWithRights(port_handle, ZX_RIGHT_WRITE, &port);
185 if (status != ZX_OK)
186 return status;
187
188 {
189 Guard<fbl::Mutex> guard{up->handle_table_lock()};
190 Handle* handle = up->GetHandleLocked(handle_value);
191 if (!handle)
192 return ZX_ERR_BAD_HANDLE;
193 if (!handle->HasRights(ZX_RIGHT_WAIT))
194 return ZX_ERR_ACCESS_DENIED;
195
196 return port->MakeObserver(options, handle, key, signals);
197 }
198 }
199