source: mainline/kernel/generic/src/ipc/kbox.c@ f1380b7

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since f1380b7 was a35b458, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

  • Property mode set to 100644
File size: 7.3 KB
Line 
1/*
2 * Copyright (c) 2008 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup genericipc
30 * @{
31 */
32/** @file
33 */
34
35#include <synch/spinlock.h>
36#include <synch/mutex.h>
37#include <ipc/ipc.h>
38#include <abi/ipc/methods.h>
39#include <ipc/ipcrsc.h>
40#include <arch.h>
41#include <errno.h>
42#include <debug.h>
43#include <udebug/udebug_ipc.h>
44#include <ipc/kbox.h>
45#include <print.h>
46#include <proc/thread.h>
47
48void ipc_kbox_cleanup(void)
49{
50 /*
51 * Not really needed, just to be consistent with the meaning of
52 * answerbox_t.active.
53 */
54 irq_spinlock_lock(&TASK->kb.box.lock, true);
55 TASK->kb.box.active = false;
56 irq_spinlock_unlock(&TASK->kb.box.lock, true);
57
58 /*
59 * Only hold kb.cleanup_lock while setting kb.finished -
60 * this is enough.
61 */
62 mutex_lock(&TASK->kb.cleanup_lock);
63 TASK->kb.finished = true;
64 mutex_unlock(&TASK->kb.cleanup_lock);
65
66 bool have_kb_thread = (TASK->kb.thread != NULL);
67
68 /*
69 * From now on nobody will try to connect phones or attach
70 * kbox threads
71 */
72
73 /*
74 * Disconnect all phones connected to our kbox. Passing true for
75 * notify_box causes a HANGUP message to be inserted for each
76 * disconnected phone. This ensures the kbox thread is going to
77 * wake up and terminate.
78 */
79 ipc_answerbox_slam_phones(&TASK->kb.box, have_kb_thread);
80
81 /*
82 * If the task was being debugged, clean up debugging session.
83 * This is necessarry as slamming the phones won't force
84 * kbox thread to clean it up since sender != debugger.
85 */
86 mutex_lock(&TASK->udebug.lock);
87 udebug_task_cleanup(TASK);
88 mutex_unlock(&TASK->udebug.lock);
89
90 if (have_kb_thread) {
91 LOG("Join kb.thread.");
92 thread_join(TASK->kb.thread);
93 thread_detach(TASK->kb.thread);
94 LOG("...join done.");
95 TASK->kb.thread = NULL;
96 }
97
98 /* Answer all messages in 'calls' and 'dispatched_calls' queues. */
99 ipc_cleanup_call_list(&TASK->kb.box, &TASK->kb.box.calls);
100 ipc_cleanup_call_list(&TASK->kb.box, &TASK->kb.box.dispatched_calls);
101}
102
103/** Handle hangup message in kbox.
104 *
105 * @param call The IPC_M_PHONE_HUNGUP call structure.
106 * @param last Output, the function stores @c true here if
107 * this was the last phone, @c false otherwise.
108 *
109 */
110static void kbox_proc_phone_hungup(call_t *call, bool *last)
111{
112 /* Was it our debugger, who hung up? */
113 if (call->sender == TASK->udebug.debugger) {
114 /* Terminate debugging session (if any). */
115 LOG("Terminate debugging session.");
116 mutex_lock(&TASK->udebug.lock);
117 udebug_task_cleanup(TASK);
118 mutex_unlock(&TASK->udebug.lock);
119 } else {
120 LOG("Was not debugger.");
121 }
122
123 LOG("Continue with hangup message.");
124 IPC_SET_RETVAL(call->data, 0);
125 ipc_answer(&TASK->kb.box, call);
126
127 mutex_lock(&TASK->kb.cleanup_lock);
128
129 irq_spinlock_lock(&TASK->lock, true);
130 irq_spinlock_lock(&TASK->kb.box.lock, false);
131 if (list_empty(&TASK->kb.box.connected_phones)) {
132 /*
133 * Last phone has been disconnected. Detach this thread so it
134 * gets freed and signal to the caller.
135 */
136
137 /* Only detach kbox thread unless already terminating. */
138 if (TASK->kb.finished == false) {
139 /* Detach kbox thread so it gets freed from memory. */
140 thread_detach(TASK->kb.thread);
141 TASK->kb.thread = NULL;
142 }
143
144 LOG("Phone list is empty.");
145 *last = true;
146 } else
147 *last = false;
148
149 irq_spinlock_unlock(&TASK->kb.box.lock, false);
150 irq_spinlock_unlock(&TASK->lock, true);
151
152 mutex_unlock(&TASK->kb.cleanup_lock);
153}
154
155/** Implementing function for the kbox thread.
156 *
157 * This function listens for debug requests. It terminates
158 * when all phones are disconnected from the kbox.
159 *
160 * @param arg Ignored.
161 *
162 */
163static void kbox_thread_proc(void *arg)
164{
165 (void) arg;
166 LOG("Starting.");
167 bool done = false;
168
169 while (!done) {
170 call_t *call = ipc_wait_for_call(&TASK->kb.box, SYNCH_NO_TIMEOUT,
171 SYNCH_FLAGS_NONE);
172
173 if (call == NULL)
174 continue; /* Try again. */
175
176 switch (IPC_GET_IMETHOD(call->data)) {
177
178 case IPC_M_DEBUG:
179 /* Handle debug call. */
180 udebug_call_receive(call);
181 break;
182
183 case IPC_M_PHONE_HUNGUP:
184 /*
185 * Process the hangup call. If this was the last
186 * phone, done will be set to true and the
187 * while loop will terminate.
188 */
189 kbox_proc_phone_hungup(call, &done);
190 break;
191
192 default:
193 /* Ignore */
194 break;
195 }
196 }
197
198 LOG("Exiting.");
199}
200
201/** Connect phone to a task kernel-box specified by id.
202 *
203 * Note that this is not completely atomic. For optimisation reasons, the task
204 * might start cleaning up kbox after the phone has been connected and before
205 * a kbox thread has been created. This must be taken into account in the
206 * cleanup code.
207 *
208 * @param[out] out_phone Phone capability handle on success.
209 * @return Error code.
210 *
211 */
212errno_t ipc_connect_kbox(task_id_t taskid, cap_handle_t *out_phone)
213{
214 irq_spinlock_lock(&tasks_lock, true);
215
216 task_t *task = task_find_by_id(taskid);
217 if (task == NULL) {
218 irq_spinlock_unlock(&tasks_lock, true);
219 return ENOENT;
220 }
221
222 atomic_inc(&task->refcount);
223
224 irq_spinlock_unlock(&tasks_lock, true);
225
226 mutex_lock(&task->kb.cleanup_lock);
227
228 if (atomic_predec(&task->refcount) == 0) {
229 mutex_unlock(&task->kb.cleanup_lock);
230 task_destroy(task);
231 return ENOENT;
232 }
233
234 if (task->kb.finished) {
235 mutex_unlock(&task->kb.cleanup_lock);
236 return EINVAL;
237 }
238
239 /* Create a kbox thread if necessary. */
240 if (task->kb.thread == NULL) {
241 thread_t *kb_thread = thread_create(kbox_thread_proc, NULL, task,
242 THREAD_FLAG_NONE, "kbox");
243
244 if (!kb_thread) {
245 mutex_unlock(&task->kb.cleanup_lock);
246 return ENOMEM;
247 }
248
249 task->kb.thread = kb_thread;
250 thread_ready(kb_thread);
251 }
252
253 /* Allocate a new phone. */
254 cap_handle_t phone_handle;
255 errno_t rc = phone_alloc(TASK, &phone_handle);
256 if (rc != EOK) {
257 mutex_unlock(&task->kb.cleanup_lock);
258 return rc;
259 }
260
261 kobject_t *phone_obj = kobject_get(TASK, phone_handle,
262 KOBJECT_TYPE_PHONE);
263 /* Connect the newly allocated phone to the kbox */
264 /* Hand over phone_obj's reference to ipc_phone_connect() */
265 (void) ipc_phone_connect(phone_obj->phone, &task->kb.box);
266
267 mutex_unlock(&task->kb.cleanup_lock);
268 *out_phone = phone_handle;
269 return EOK;
270}
271
272/** @}
273 */
Note: See TracBrowser for help on using the repository browser.