source: mainline/kernel/generic/src/ipc/ipcrsc.c@ 2736ef9b

Last change on this file since 2736ef9b was 2736ef9b, checked in by Jakub Jermar <jakub@…>, 8 years ago

Remove dangerous assert

The task can manage to hangup the expected phone and use the capability
handle for another phone, which may be in arbitrary state. By removing
the assert, we still destroy the given capability but no longer panic.

  • Property mode set to 100644
File size: 7.4 KB
Line 
1/*
2 * Copyright (c) 2006 Ondrej Palkovsky
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/* IPC resources management
36 *
37 * The goal of this source code is to properly manage IPC resources and allow
38 * straight and clean clean-up procedure upon task termination.
39 *
40 * The pattern of usage of the resources is:
41 * - allocate empty phone capability slot, connect | deallocate slot
42 * - disconnect connected phone (some messages might be on the fly)
43 * - find phone in slot and send a message using phone
44 * - answer message to phone
45 * - hangup phone (the caller has hung up)
46 * - hangup phone (the answerbox is exiting)
47 *
48 * Locking strategy
49 *
50 * - To use a phone, disconnect a phone etc., the phone must be first locked and
51 * then checked that it is connected
52 * - To connect an allocated phone it need not be locked (assigning pointer is
53 * atomic on all platforms)
54 *
55 * - To find an empty phone capability slot, the TASK must be locked
56 * - To answer a message, the answerbox must be locked
57 * - The locking of phone and answerbox is done at the ipc_ level.
58 * It is perfectly correct to pass unconnected phone to these functions and
59 * proper reply will be generated.
60 *
61 * Locking order
62 *
63 * - first phone, then answerbox
64 * + Easy locking on calls
65 * - Very hard traversing list of phones when disconnecting because the phones
66 * may disconnect during traversal of list of connected phones. The only
67 * possibility is try_lock with restart of list traversal.
68 *
69 * Destroying is less frequent, this approach is taken.
70 *
71 * Phone call
72 *
73 * *** Connect_me_to ***
74 * The caller sends IPC_M_CONNECT_ME_TO to an answerbox. The server receives
75 * 'phoneid' of the connecting phone as an ARG5. If it answers with RETVAL=0,
76 * the phonecall is accepted, otherwise it is refused.
77 *
78 * *** Connect_to_me ***
79 * The caller sends IPC_M_CONNECT_TO_ME.
80 * The server receives an automatically opened phoneid. If it accepts
81 * (RETVAL=0), it can use the phoneid immediately. Possible race condition can
82 * arise, when the client receives messages from new connection before getting
83 * response for connect_to_me message. Userspace should implement handshake
84 * protocol that would control it.
85 *
86 * Phone hangup
87 *
88 * *** The caller hangs up (sys_ipc_hangup) ***
89 * - The phone is disconnected (no more messages can be sent over this phone),
90 * all in-progress messages are correctly handled. The answerbox receives
91 * IPC_M_PHONE_HUNGUP call from the phone that hung up. When all async calls
92 * are answered, the phone is deallocated.
93 *
94 * *** The answerbox hangs up (ipc_answer(EHANGUP))
95 * - The phone is disconnected. EHANGUP response code is sent to the calling
96 * task. All new calls through this phone get a EHUNGUP error code, the task
97 * is expected to send an sys_ipc_hangup after cleaning up its internal
98 * structures.
99 *
100 *
101 * Call forwarding
102 *
103 * The call can be forwarded, so that the answer to call is passed directly to
104 * the original sender. However, this poses special problems regarding routing
105 * of hangup messages.
106 *
107 * sys_ipc_hangup -> IPC_M_PHONE_HUNGUP
108 * - this message CANNOT be forwarded
109 *
110 * EHANGUP during forward
111 * - The *forwarding* phone will be closed, EFORWARD is sent to receiver.
112 *
113 * EHANGUP, ENOENT during forward
114 * - EFORWARD is sent to the receiver, ipc_forward returns error code EFORWARD
115 *
116 * Cleanup strategy
117 *
118 * 1) Disconnect all our phones ('ipc_phone_hangup').
119 *
120 * 2) Disconnect all phones connected to answerbox.
121 *
122 * 3) Answer all messages in 'calls' and 'dispatched_calls' queues with
123 * appropriate error code (EHANGUP, EFORWARD).
124 *
125 * 4) Wait for all async answers to arrive and dispose of them.
126 *
127 */
128
129#include <synch/spinlock.h>
130#include <ipc/ipc.h>
131#include <arch.h>
132#include <proc/task.h>
133#include <ipc/ipcrsc.h>
134#include <assert.h>
135#include <abi/errno.h>
136#include <cap/cap.h>
137#include <mm/slab.h>
138
139static void phone_destroy(void *arg)
140{
141 phone_t *phone = (phone_t *) arg;
142 slab_free(phone_cache, phone);
143}
144
145static kobject_ops_t phone_kobject_ops = {
146 .destroy = phone_destroy
147};
148
149
150/** Allocate new phone in the specified task.
151 *
152 * @param task Task for which to allocate a new phone.
153 *
154 * @param[out] out_handle New phone capability handle.
155 *
156 * @return An error code if a new capability cannot be allocated.
157 */
158errno_t phone_alloc(task_t *task, cap_handle_t *out_handle)
159{
160 cap_handle_t handle;
161 errno_t rc = cap_alloc(task, &handle);
162 if (rc == EOK) {
163 phone_t *phone = slab_alloc(phone_cache, FRAME_ATOMIC);
164 if (!phone) {
165 cap_free(TASK, handle);
166 return ENOMEM;
167 }
168 kobject_t *kobject = malloc(sizeof(kobject_t), FRAME_ATOMIC);
169 if (!kobject) {
170 cap_free(TASK, handle);
171 slab_free(phone_cache, phone);
172 return ENOMEM;
173 }
174
175 ipc_phone_init(phone, task);
176 phone->state = IPC_PHONE_CONNECTING;
177
178 kobject_initialize(kobject, KOBJECT_TYPE_PHONE, phone,
179 &phone_kobject_ops);
180 phone->kobject = kobject;
181
182 cap_publish(task, handle, kobject);
183
184 *out_handle = handle;
185 }
186 return rc;
187}
188
189/** Free slot from a disconnected phone.
190 *
191 * All already sent messages will be correctly processed.
192 *
193 * @param handle Phone capability handle of the phone to be freed.
194 *
195 */
196void phone_dealloc(cap_handle_t handle)
197{
198 kobject_t *kobj = cap_unpublish(TASK, handle, KOBJECT_TYPE_PHONE);
199 if (!kobj)
200 return;
201
202 kobject_put(kobj);
203 cap_free(TASK, handle);
204}
205
206/** Connect phone to a given answerbox.
207 *
208 * @param handle Capability handle of the phone to be connected.
209 * @param box Answerbox to which to connect the phone.
210 * @return True if the phone was connected, false otherwise.
211 */
212bool phone_connect(cap_handle_t handle, answerbox_t *box)
213{
214 kobject_t *phone_obj = kobject_get(TASK, handle, KOBJECT_TYPE_PHONE);
215 if (!phone_obj)
216 return false;
217
218 if (phone_obj->phone->state != IPC_PHONE_CONNECTING) {
219 /*
220 * This looks like another phone. The one we were expecting
221 * under this handle must be in the IPC_PHONE_CONNECTING state.
222 */
223 kobject_put(phone_obj);
224 return false;
225 }
226
227 /* Hand over phone_obj reference to the answerbox */
228 return ipc_phone_connect(phone_obj->phone, box);
229}
230
231/** @}
232 */
Note: See TracBrowser for help on using the repository browser.