source: mainline/uspace/app/trace/ipcp.c@ b538ca5c

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since b538ca5c was c0699467, checked in by Martin Decky <martin@…>, 14 years ago

do not provide general access to kernel headers from uspace, only allow specific headers to be accessed or shared
externalize headers which serve as kernel/uspace API/ABI into a special tree

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