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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 03a8a8e was 03a8a8e, checked in by Jakub Jermar <jakub@…>, 13 years ago

Link each phone to its containing task.

This makes it possible to set the call's sender reliably using just the
info stored in the phone used to make the call.

  • Property mode set to 100644
File size: 7.0 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
47void ipc_kbox_cleanup(void)
48{
49 /*
50 * Not really needed, just to be consistent with the meaning of
51 * answerbox_t.active.
52 */
53 irq_spinlock_lock(&TASK->kb.box.lock, true);
54 TASK->kb.box.active = false;
55 irq_spinlock_unlock(&TASK->kb.box.lock, true);
56
57 /*
58 * Only hold kb.cleanup_lock while setting kb.finished -
59 * this is enough.
60 */
61 mutex_lock(&TASK->kb.cleanup_lock);
62 TASK->kb.finished = true;
63 mutex_unlock(&TASK->kb.cleanup_lock);
64
65 bool have_kb_thread = (TASK->kb.thread != NULL);
66
67 /*
68 * From now on nobody will try to connect phones or attach
69 * kbox threads
70 */
71
72 /*
73 * Disconnect all phones connected to our kbox. Passing true for
74 * notify_box causes a HANGUP message to be inserted for each
75 * disconnected phone. This ensures the kbox thread is going to
76 * wake up and terminate.
77 */
78 ipc_answerbox_slam_phones(&TASK->kb.box, have_kb_thread);
79
80 /*
81 * If the task was being debugged, clean up debugging session.
82 * This is necessarry as slamming the phones won't force
83 * kbox thread to clean it up since sender != debugger.
84 */
85 mutex_lock(&TASK->udebug.lock);
86 udebug_task_cleanup(TASK);
87 mutex_unlock(&TASK->udebug.lock);
88
89 if (have_kb_thread) {
90 LOG("Join kb.thread.");
91 thread_join(TASK->kb.thread);
92 thread_detach(TASK->kb.thread);
93 LOG("...join done.");
94 TASK->kb.thread = NULL;
95 }
96
97 /* Answer all messages in 'calls' and 'dispatched_calls' queues. */
98 ipc_cleanup_call_list(&TASK->kb.box, &TASK->kb.box.dispatched_calls);
99 ipc_cleanup_call_list(&TASK->kb.box, &TASK->kb.box.calls);
100}
101
102/** Handle hangup message in kbox.
103 *
104 * @param call The IPC_M_PHONE_HUNGUP call structure.
105 * @param last Output, the function stores @c true here if
106 * this was the last phone, @c false otherwise.
107 *
108 */
109static void kbox_proc_phone_hungup(call_t *call, bool *last)
110{
111 /* Was it our debugger, who hung up? */
112 if (call->sender == TASK->udebug.debugger) {
113 /* Terminate debugging session (if any). */
114 LOG("Terminate debugging session.");
115 mutex_lock(&TASK->udebug.lock);
116 udebug_task_cleanup(TASK);
117 mutex_unlock(&TASK->udebug.lock);
118 } else {
119 LOG("Was not debugger.");
120 }
121
122 LOG("Continue with hangup message.");
123 IPC_SET_RETVAL(call->data, 0);
124 ipc_answer(&TASK->kb.box, call);
125
126 mutex_lock(&TASK->kb.cleanup_lock);
127
128 irq_spinlock_lock(&TASK->lock, true);
129 irq_spinlock_lock(&TASK->kb.box.lock, false);
130 if (list_empty(&TASK->kb.box.connected_phones)) {
131 /*
132 * Last phone has been disconnected. Detach this thread so it
133 * gets freed and signal to the caller.
134 */
135
136 /* Only detach kbox thread unless already terminating. */
137 if (TASK->kb.finished == false) {
138 /* Detach kbox thread so it gets freed from memory. */
139 thread_detach(TASK->kb.thread);
140 TASK->kb.thread = NULL;
141 }
142
143 LOG("Phone list is empty.");
144 *last = true;
145 } else
146 *last = false;
147
148 irq_spinlock_unlock(&TASK->kb.box.lock, false);
149 irq_spinlock_unlock(&TASK->lock, true);
150
151 mutex_unlock(&TASK->kb.cleanup_lock);
152}
153
154/** Implementing function for the kbox thread.
155 *
156 * This function listens for debug requests. It terminates
157 * when all phones are disconnected from the kbox.
158 *
159 * @param arg Ignored.
160 *
161 */
162static void kbox_thread_proc(void *arg)
163{
164 (void) arg;
165 LOG("Starting.");
166 bool done = false;
167
168 while (!done) {
169 call_t *call = ipc_wait_for_call(&TASK->kb.box, SYNCH_NO_TIMEOUT,
170 SYNCH_FLAGS_NONE);
171
172 if (call == NULL)
173 continue; /* Try again. */
174
175 switch (IPC_GET_IMETHOD(call->data)) {
176
177 case IPC_M_DEBUG:
178 /* Handle debug call. */
179 udebug_call_receive(call);
180 break;
181
182 case IPC_M_PHONE_HUNGUP:
183 /*
184 * Process the hangup call. If this was the last
185 * phone, done will be set to true and the
186 * while loop will terminate.
187 */
188 kbox_proc_phone_hungup(call, &done);
189 break;
190
191 default:
192 /* Ignore */
193 break;
194 }
195 }
196
197 LOG("Exiting.");
198}
199
200/** Connect phone to a task kernel-box specified by id.
201 *
202 * Note that this is not completely atomic. For optimisation reasons, the task
203 * might start cleaning up kbox after the phone has been connected and before
204 * a kbox thread has been created. This must be taken into account in the
205 * cleanup code.
206 *
207 * @return Phone id on success, or negative error code.
208 *
209 */
210int ipc_connect_kbox(task_id_t taskid)
211{
212 irq_spinlock_lock(&tasks_lock, true);
213
214 task_t *task = task_find_by_id(taskid);
215 if (task == NULL) {
216 irq_spinlock_unlock(&tasks_lock, true);
217 return ENOENT;
218 }
219
220 atomic_inc(&task->refcount);
221
222 irq_spinlock_unlock(&tasks_lock, true);
223
224 mutex_lock(&task->kb.cleanup_lock);
225
226 if (atomic_predec(&task->refcount) == 0) {
227 mutex_unlock(&task->kb.cleanup_lock);
228 task_destroy(task);
229 return ENOENT;
230 }
231
232 if (task->kb.finished != false) {
233 mutex_unlock(&task->kb.cleanup_lock);
234 return EINVAL;
235 }
236
237 int newphid = phone_alloc(TASK);
238 if (newphid < 0) {
239 mutex_unlock(&task->kb.cleanup_lock);
240 return ELIMIT;
241 }
242
243 /* Connect the newly allocated phone to the kbox */
244 (void) ipc_phone_connect(&TASK->phones[newphid], &task->kb.box);
245
246 if (task->kb.thread != NULL) {
247 mutex_unlock(&task->kb.cleanup_lock);
248 return newphid;
249 }
250
251 /* Create a kbox thread */
252 thread_t *kb_thread = thread_create(kbox_thread_proc, NULL, task,
253 THREAD_FLAG_NONE, "kbox");
254 if (!kb_thread) {
255 mutex_unlock(&task->kb.cleanup_lock);
256 return ENOMEM;
257 }
258
259 task->kb.thread = kb_thread;
260 thread_ready(kb_thread);
261
262 mutex_unlock(&task->kb.cleanup_lock);
263
264 return newphid;
265}
266
267/** @}
268 */
Note: See TracBrowser for help on using the repository browser.