source: mainline/uspace/app/trace/ipcp.c@ 2732c94

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 2732c94 was 0ca7286, checked in by Adam Hraska <adam.hraska+hos@…>, 13 years ago

Added resizing to user space (single-threaded) hash_table. Resizes in a way to mitigate effects of bad hash functions. Change of interface affected many files.

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