source: mainline/uspace/app/trace/ipcp.c@ 01c3bb4

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

Convert call-handling syscalls to capabilities

This commit modifies the behavior of sys_ipc_wait_for_call() to return a
capability handle for requests. This capability handle can be used
either by sys_ipc_answer*() to answer the call or by sys_ipc_forward*()
to forward it further along. Answering or forwarding the call results in
destruction of the respective capability. For requests and
notifications, sys_ipc_wait_for_call() returns CAP_NIL and sets call
flags accordingly.

  • Property mode set to 100644
File size: 8.5 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 trace
30 * @{
31 */
32/** @file
33 */
34
35#include <stdio.h>
36#include <stdlib.h>
37#include <inttypes.h>
38#include <adt/hash_table.h>
39#include <abi/ipc/methods.h>
40#include <macros.h>
41#include "ipc_desc.h"
42#include "proto.h"
43#include "trace.h"
44#include "ipcp.h"
45
46#define IPCP_CALLID_SYNC 0
47
48typedef struct {
49 sysarg_t phone_hash;
50 ipc_call_t question;
51 oper_t *oper;
52
53 ipc_callid_t call_hash;
54
55 ht_link_t link;
56} pending_call_t;
57
58typedef struct {
59 int server;
60 proto_t *proto;
61} connection_t;
62
63#define MAX_PHONE 64
64connection_t connections[MAX_PHONE];
65int have_conn[MAX_PHONE];
66
67static hash_table_t pending_calls;
68
69/*
70 * Pseudo-protocols
71 */
72proto_t *proto_system; /**< Protocol describing system IPC methods. */
73proto_t *proto_unknown; /**< Protocol with no known methods. */
74
75
76static size_t pending_call_key_hash(void *key)
77{
78 ipc_callid_t *call_id = (ipc_callid_t *)key;
79 return *call_id;
80}
81
82static size_t pending_call_hash(const ht_link_t *item)
83{
84 pending_call_t *hs = hash_table_get_inst(item, pending_call_t, link);
85 return hs->call_hash;
86}
87
88static bool pending_call_key_equal(void *key, const ht_link_t *item)
89{
90 ipc_callid_t *call_id = (ipc_callid_t *)key;
91 pending_call_t *hs = hash_table_get_inst(item, pending_call_t, link);
92
93 return *call_id == hs->call_hash;
94}
95
96static hash_table_ops_t pending_call_ops = {
97 .hash = pending_call_hash,
98 .key_hash = pending_call_key_hash,
99 .key_equal = pending_call_key_equal,
100 .equal = NULL,
101 .remove_callback = NULL
102};
103
104
105void ipcp_connection_set(int phone, int server, proto_t *proto)
106{
107 if (phone <0 || phone >= MAX_PHONE) return;
108 connections[phone].server = server;
109 connections[phone].proto = proto;
110 have_conn[phone] = 1;
111}
112
113void ipcp_connection_clear(int phone)
114{
115 have_conn[phone] = 0;
116 connections[phone].server = 0;
117 connections[phone].proto = NULL;
118}
119
120static void ipc_m_print(proto_t *proto, sysarg_t method)
121{
122 oper_t *oper;
123
124 /* Try system methods first */
125 oper = proto_get_oper(proto_system, method);
126
127 if (oper == NULL && proto != NULL) {
128 /* Not a system method, try the user protocol. */
129 oper = proto_get_oper(proto, method);
130 }
131
132 if (oper != NULL) {
133 printf("%s (%" PRIun ")", oper->name, method);
134 return;
135 }
136
137 printf("%" PRIun, method);
138}
139
140void ipcp_init(void)
141{
142 val_type_t arg_def[OPER_MAX_ARGS] = {
143 V_INTEGER,
144 V_INTEGER,
145 V_INTEGER,
146 V_INTEGER,
147 V_INTEGER
148 };
149
150 /*
151 * Create a pseudo-protocol 'unknown' that has no known methods.
152 */
153 proto_unknown = proto_new("unknown");
154
155 /*
156 * Create a pseudo-protocol 'system' defining names of system IPC
157 * methods.
158 */
159 proto_system = proto_new("system");
160
161 for (size_t i = 0; i < ipc_methods_len; i++) {
162 oper_t *oper = oper_new(ipc_methods[i].name, OPER_MAX_ARGS,
163 arg_def, V_INTEGER, OPER_MAX_ARGS, arg_def);
164 proto_add_oper(proto_system, ipc_methods[i].number, oper);
165 }
166
167 bool ok = hash_table_create(&pending_calls, 0, 0, &pending_call_ops);
168 assert(ok);
169}
170
171void ipcp_cleanup(void)
172{
173 proto_delete(proto_system);
174 hash_table_destroy(&pending_calls);
175}
176
177void ipcp_call_out(int phone, ipc_call_t *call, ipc_callid_t hash)
178{
179 pending_call_t *pcall;
180 proto_t *proto;
181 oper_t *oper;
182 sysarg_t *args;
183 int i;
184
185 if (have_conn[phone]) proto = connections[phone].proto;
186 else proto = NULL;
187
188 args = call->args;
189
190 if ((display_mask & DM_IPC) != 0) {
191 printf("Call ID: %d, phone: %d, proto: %s, method: ",
192 hash, phone,
193 (proto ? proto->name : "n/a"));
194 ipc_m_print(proto, IPC_GET_IMETHOD(*call));
195 printf(" args: (%" PRIun ", %" PRIun ", %" PRIun ", "
196 "%" PRIun ", %" PRIun ")\n",
197 args[1], args[2], args[3], args[4], args[5]);
198 }
199
200
201 if ((display_mask & DM_USER) != 0) {
202
203 if (proto != NULL) {
204 oper = proto_get_oper(proto, IPC_GET_IMETHOD(*call));
205 } else {
206 oper = NULL;
207 }
208
209 if (oper != NULL) {
210
211 printf("%s(%d).%s", (proto ? proto->name : "n/a"),
212 phone, (oper ? oper->name : "unknown"));
213
214 putchar('(');
215 for (i = 1; i <= oper->argc; ++i) {
216 if (i > 1) printf(", ");
217 val_print(args[i], oper->arg_type[i - 1]);
218 }
219 putchar(')');
220
221 if (oper->rv_type == V_VOID && oper->respc == 0) {
222 /*
223 * No response data (typically the task will
224 * not be interested in the response).
225 * We will not display response.
226 */
227 putchar('.');
228 }
229
230 putchar('\n');
231 }
232 } else {
233 oper = NULL;
234 }
235
236 /* Store call in hash table for response matching */
237
238 pcall = malloc(sizeof(pending_call_t));
239 pcall->phone_hash = phone;
240 pcall->question = *call;
241 pcall->call_hash = hash;
242 pcall->oper = oper;
243
244 hash_table_insert(&pending_calls, &pcall->link);
245}
246
247static void parse_answer(ipc_callid_t hash, pending_call_t *pcall,
248 ipc_call_t *answer)
249{
250 sysarg_t phone;
251 sysarg_t method;
252 sysarg_t service;
253 sysarg_t retval;
254 proto_t *proto;
255 int cphone;
256
257 sysarg_t *resp;
258 oper_t *oper;
259 int i;
260
261 phone = pcall->phone_hash;
262 method = IPC_GET_IMETHOD(pcall->question);
263 retval = IPC_GET_RETVAL(*answer);
264
265 resp = answer->args;
266
267 if ((display_mask & DM_IPC) != 0) {
268 printf("Response to %d: retval=%" PRIdn ", args = (%" PRIun ", "
269 "%" PRIun ", %" PRIun ", %" PRIun ", %" PRIun ")\n",
270 hash, retval, IPC_GET_ARG1(*answer),
271 IPC_GET_ARG2(*answer), IPC_GET_ARG3(*answer),
272 IPC_GET_ARG4(*answer), IPC_GET_ARG5(*answer));
273 }
274
275 if ((display_mask & DM_USER) != 0) {
276 oper = pcall->oper;
277
278 if ((oper != NULL) &&
279 ((oper->rv_type != V_VOID) || (oper->respc > 0))) {
280 printf("->");
281
282 if (oper->rv_type != V_VOID) {
283 putchar(' ');
284 val_print(retval, oper->rv_type);
285 }
286
287 if (oper->respc > 0) {
288 putchar(' ');
289 putchar('(');
290 for (i = 1; i <= oper->respc; ++i) {
291 if (i > 1)
292 printf(", ");
293 val_print(resp[i], oper->resp_type[i - 1]);
294 }
295 putchar(')');
296 }
297
298 putchar('\n');
299 }
300 }
301
302 if ((phone == PHONE_NS) && (method == IPC_M_CONNECT_ME_TO) &&
303 (retval == 0)) {
304 /* Connected to a service (through NS) */
305 service = IPC_GET_ARG2(pcall->question);
306 proto = proto_get_by_srv(service);
307 if (proto == NULL)
308 proto = proto_unknown;
309
310 cphone = IPC_GET_ARG5(*answer);
311 if ((display_mask & DM_SYSTEM) != 0) {
312 printf("Registering connection (phone %d, protocol: %s)\n", cphone,
313 proto->name);
314 }
315
316 ipcp_connection_set(cphone, 0, proto);
317 }
318}
319
320void ipcp_call_in(ipc_call_t *call, ipc_callid_t hash)
321{
322 ht_link_t *item;
323 pending_call_t *pcall;
324
325 if ((call->flags & IPC_CALLID_ANSWERED) == 0 &&
326 hash != IPCP_CALLID_SYNC) {
327 /* Not a response */
328 if ((display_mask & DM_IPC) != 0) {
329 printf("Not a response (hash %d)\n", hash);
330 }
331 return;
332 }
333
334 item = hash_table_find(&pending_calls, &hash);
335 if (item == NULL)
336 return; /* No matching question found */
337
338 /*
339 * Response matched to question.
340 */
341
342 pcall = hash_table_get_inst(item, pending_call_t, link);
343 hash_table_remove(&pending_calls, &hash);
344
345 parse_answer(hash, pcall, call);
346 free(pcall);
347}
348
349void ipcp_call_sync(int phone, ipc_call_t *call, ipc_call_t *answer)
350{
351 ipcp_call_out(phone, call, IPCP_CALLID_SYNC);
352 ipcp_call_in(answer, IPCP_CALLID_SYNC);
353}
354
355void ipcp_hangup(int phone, int rc)
356{
357 if ((display_mask & DM_SYSTEM) != 0) {
358 printf("Hang phone %d up -> %d\n", phone, rc);
359 ipcp_connection_clear(phone);
360 }
361}
362
363/** @}
364 */
Note: See TracBrowser for help on using the repository browser.