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

Last change on this file was 0db0df2, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 3 months ago

Hash table improvements

Implement hash_table_foreach macro, analogous to list_foreach.

Remove superfluous argument to hash_table_find_next().
(If the user needs to recheck the part of the list already
checked by hash_table_find(), they can just rerun that function.)

Add hash argument to hash_table_ops_t::key_equal.
The big change here is that users with big keys can store the hash
value alongside key in their entries, and for the low low cost of
sizeof(size_t) bytes eliminate a bunch of expensive key comparisons.

Also added a hash function for strings and arbitrary data.
Found this one by asking ChatGPT, because the latency of accesses
to my book collection is currently a couple of hours.

+ Some drive-by unused #include removal.

  • Property mode set to 100644
File size: 8.8 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>
[c1694b6b]37#include <str_error.h>
[7354b5e]38#include <inttypes.h>
[d9c8c81]39#include <adt/hash_table.h>
[c0699467]40#include <abi/ipc/methods.h>
[062d900]41#include <macros.h>
[9a1b20c]42#include "ipc_desc.h"
43#include "proto.h"
[1643855]44#include "trace.h"
[9a1b20c]45#include "ipcp.h"
46
47typedef struct {
[eadaeae8]48 cap_phone_handle_t phone_handle;
[9a1b20c]49 ipc_call_t question;
[abf3564]50 oper_t *oper;
[9a1b20c]51
[eadaeae8]52 cap_call_handle_t call_handle;
[9a1b20c]53
[062d900]54 ht_link_t link;
[9a1b20c]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
[062d900]66static hash_table_t pending_calls;
[9a1b20c]67
[8c125ad]68/*
69 * Pseudo-protocols
70 */
71proto_t *proto_system; /**< Protocol describing system IPC methods. */
72proto_t *proto_unknown; /**< Protocol with no known methods. */
73
[5e801dc]74static size_t pending_call_key_hash(const void *key)
[9a1b20c]75{
[5e801dc]76 const cap_call_handle_t *chandle = key;
[bb97118]77 return cap_handle_raw(*chandle);
[9a1b20c]78}
79
[062d900]80static size_t pending_call_hash(const ht_link_t *item)
[9a1b20c]81{
[062d900]82 pending_call_t *hs = hash_table_get_inst(item, pending_call_t, link);
[bb97118]83 return cap_handle_raw(hs->call_handle);
[9a1b20c]84}
85
[0db0df2]86static bool pending_call_key_equal(const void *key, size_t hash, const ht_link_t *item)
[9a1b20c]87{
[5e801dc]88 const cap_call_handle_t *chandle = key;
[062d900]89 pending_call_t *hs = hash_table_get_inst(item, pending_call_t, link);
90
[eadaeae8]91 return *chandle == hs->call_handle;
[9a1b20c]92}
93
[61eb2ce2]94static const hash_table_ops_t pending_call_ops = {
[062d900]95 .hash = pending_call_hash,
96 .key_hash = pending_call_key_hash,
97 .key_equal = pending_call_key_equal,
[4e00f87]98 .equal = NULL,
99 .remove_callback = NULL
[062d900]100};
101
[eadaeae8]102void ipcp_connection_set(cap_phone_handle_t phone, int server, proto_t *proto)
[9a1b20c]103{
[eadaeae8]104 // XXX: there is no longer a limit on the number of phones as phones are
105 // now handled using capabilities
[bb97118]106 if (cap_handle_raw(phone) < 0 || cap_handle_raw(phone) >= MAX_PHONE)
[1433ecda]107 return;
[bb97118]108 connections[cap_handle_raw(phone)].server = server;
109 connections[cap_handle_raw(phone)].proto = proto;
110 have_conn[cap_handle_raw(phone)] = 1;
[9a1b20c]111}
112
[eadaeae8]113void ipcp_connection_clear(cap_phone_handle_t phone)
[9a1b20c]114{
[bb97118]115 have_conn[cap_handle_raw(phone)] = 0;
116 connections[cap_handle_raw(phone)].server = 0;
117 connections[cap_handle_raw(phone)].proto = NULL;
[9a1b20c]118}
119
[96b02eb9]120static void ipc_m_print(proto_t *proto, sysarg_t method)
[9a1b20c]121{
122 oper_t *oper;
123
[8c125ad]124 /* Try system methods first */
125 oper = proto_get_oper(proto_system, method);
[9a1b20c]126
[8c125ad]127 if (oper == NULL && proto != NULL) {
128 /* Not a system method, try the user protocol. */
129 oper = proto_get_oper(proto, method);
[9a1b20c]130 }
131
[8c125ad]132 if (oper != NULL) {
[7e752b2]133 printf("%s (%" PRIun ")", oper->name, method);
[8c125ad]134 return;
[9a1b20c]135 }
136
[7e752b2]137 printf("%" PRIun, method);
[9a1b20c]138}
139
140void ipcp_init(void)
141{
[abf3564]142 val_type_t arg_def[OPER_MAX_ARGS] = {
143 V_INTEGER,
144 V_INTEGER,
145 V_INTEGER,
146 V_INTEGER,
[40fd6f0]147 V_INTEGER
[abf3564]148 };
149
[8c125ad]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
[a3b339b4]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);
[8c125ad]165 }
166
[062d900]167 bool ok = hash_table_create(&pending_calls, 0, 0, &pending_call_ops);
168 assert(ok);
[9a1b20c]169}
170
171void ipcp_cleanup(void)
172{
[8c125ad]173 proto_delete(proto_system);
[9a1b20c]174 hash_table_destroy(&pending_calls);
175}
176
[eadaeae8]177void ipcp_call_out(cap_phone_handle_t phandle, ipc_call_t *call,
178 cap_call_handle_t chandle)
[9a1b20c]179{
180 pending_call_t *pcall;
181 proto_t *proto;
[1643855]182 oper_t *oper;
[96b02eb9]183 sysarg_t *args;
[abf3564]184 int i;
[9a1b20c]185
[bb97118]186 if (have_conn[cap_handle_raw(phandle)])
187 proto = connections[cap_handle_raw(phandle)].proto;
[eadaeae8]188 else
189 proto = NULL;
[9a1b20c]190
[abf3564]191 args = call->args;
192
[1643855]193 if ((display_mask & DM_IPC) != 0) {
[eed4139]194 printf("Call handle: %p, phone: %p, proto: %s, method: ",
[eadaeae8]195 chandle, phandle, (proto ? proto->name : "n/a"));
[fafb8e5]196 ipc_m_print(proto, ipc_get_imethod(call));
[7e752b2]197 printf(" args: (%" PRIun ", %" PRIun ", %" PRIun ", "
198 "%" PRIun ", %" PRIun ")\n",
199 args[1], args[2], args[3], args[4], args[5]);
[1643855]200 }
201
202 if ((display_mask & DM_USER) != 0) {
203
204 if (proto != NULL) {
[fafb8e5]205 oper = proto_get_oper(proto, ipc_get_imethod(call));
[1643855]206 } else {
207 oper = NULL;
208 }
209
210 if (oper != NULL) {
211
[eadaeae8]212 printf("%s(%p).%s", (proto ? proto->name : "n/a"),
213 phandle, (oper ? oper->name : "unknown"));
[1643855]214
[abf3564]215 putchar('(');
216 for (i = 1; i <= oper->argc; ++i) {
[1433ecda]217 if (i > 1)
218 printf(", ");
[abf3564]219 val_print(args[i], oper->arg_type[i - 1]);
220 }
221 putchar(')');
222
223 if (oper->rv_type == V_VOID && oper->respc == 0) {
224 /*
225 * No response data (typically the task will
226 * not be interested in the response).
227 * We will not display response.
228 */
229 putchar('.');
230 }
231
232 putchar('\n');
[1643855]233 }
[abf3564]234 } else {
235 oper = NULL;
[1643855]236 }
[9a1b20c]237
238 /* Store call in hash table for response matching */
239
240 pcall = malloc(sizeof(pending_call_t));
[eadaeae8]241 pcall->phone_handle = phandle;
[9a1b20c]242 pcall->question = *call;
[eadaeae8]243 pcall->call_handle = chandle;
[abf3564]244 pcall->oper = oper;
[9a1b20c]245
[062d900]246 hash_table_insert(&pending_calls, &pcall->link);
[9a1b20c]247}
248
[eadaeae8]249static void parse_answer(cap_call_handle_t call_handle, pending_call_t *pcall,
[1643855]250 ipc_call_t *answer)
[9a1b20c]251{
[eadaeae8]252 cap_phone_handle_t phone;
[96b02eb9]253 sysarg_t method;
254 sysarg_t service;
[b7fd2a0]255 errno_t retval;
[9a1b20c]256 proto_t *proto;
[eadaeae8]257 cap_phone_handle_t cphone;
[a35b458]258
[96b02eb9]259 sysarg_t *resp;
[abf3564]260 oper_t *oper;
261 int i;
[a35b458]262
[eadaeae8]263 phone = pcall->phone_handle;
[fafb8e5]264 method = ipc_get_imethod(&pcall->question);
265 retval = ipc_get_retval(answer);
[a35b458]266
[abf3564]267 resp = answer->args;
[a35b458]268
[1643855]269 if ((display_mask & DM_IPC) != 0) {
[eadaeae8]270 printf("Response to %p: retval=%s, args = (%" PRIun ", "
[7e752b2]271 "%" PRIun ", %" PRIun ", %" PRIun ", %" PRIun ")\n",
[fafb8e5]272 call_handle, str_error_name(retval), ipc_get_arg1(answer),
273 ipc_get_arg2(answer), ipc_get_arg3(answer),
274 ipc_get_arg4(answer), ipc_get_arg5(answer));
[1643855]275 }
[a35b458]276
[1643855]277 if ((display_mask & DM_USER) != 0) {
[abf3564]278 oper = pcall->oper;
[a35b458]279
[79ae36dd]280 if ((oper != NULL) &&
281 ((oper->rv_type != V_VOID) || (oper->respc > 0))) {
[abf3564]282 printf("->");
[a35b458]283
[abf3564]284 if (oper->rv_type != V_VOID) {
285 putchar(' ');
[1569a9b]286 val_print((sysarg_t) retval, oper->rv_type);
[abf3564]287 }
[a35b458]288
[abf3564]289 if (oper->respc > 0) {
290 putchar(' ');
291 putchar('(');
292 for (i = 1; i <= oper->respc; ++i) {
[79ae36dd]293 if (i > 1)
294 printf(", ");
[abf3564]295 val_print(resp[i], oper->resp_type[i - 1]);
296 }
297 putchar(')');
298 }
[a35b458]299
[abf3564]300 putchar('\n');
301 }
[1643855]302 }
[a35b458]303
[79ae36dd]304 if ((phone == PHONE_NS) && (method == IPC_M_CONNECT_ME_TO) &&
305 (retval == 0)) {
[9a1b20c]306 /* Connected to a service (through NS) */
[fafb8e5]307 service = ipc_get_arg2(&pcall->question);
[9a1b20c]308 proto = proto_get_by_srv(service);
[79ae36dd]309 if (proto == NULL)
310 proto = proto_unknown;
[a35b458]311
[fafb8e5]312 cphone = (cap_phone_handle_t) ipc_get_arg5(answer);
[1643855]313 if ((display_mask & DM_SYSTEM) != 0) {
[eadaeae8]314 printf("Registering connection (phone %p, protocol: %s)\n", cphone,
[1433ecda]315 proto->name);
[1643855]316 }
[a35b458]317
[9a1b20c]318 ipcp_connection_set(cphone, 0, proto);
319 }
320}
321
[eadaeae8]322void ipcp_call_in(ipc_call_t *call, cap_call_handle_t chandle)
[9a1b20c]323{
[062d900]324 ht_link_t *item;
[9a1b20c]325 pending_call_t *pcall;
[a35b458]326
[40fd6f0]327 if ((call->flags & IPC_CALL_ANSWERED) == 0) {
[9a1b20c]328 /* Not a response */
[1643855]329 if ((display_mask & DM_IPC) != 0) {
[eadaeae8]330 printf("Not a response (handle %p)\n", chandle);
[1643855]331 }
[9a1b20c]332 return;
333 }
[a35b458]334
[eadaeae8]335 item = hash_table_find(&pending_calls, &chandle);
[79ae36dd]336 if (item == NULL)
337 return; /* No matching question found */
[a35b458]338
[1643855]339 /*
340 * Response matched to question.
341 */
[a35b458]342
[062d900]343 pcall = hash_table_get_inst(item, pending_call_t, link);
[eadaeae8]344 hash_table_remove(&pending_calls, &chandle);
[a35b458]345
[eadaeae8]346 parse_answer(chandle, pcall, call);
[9a1b20c]347 free(pcall);
348}
349
[eadaeae8]350void ipcp_hangup(cap_phone_handle_t phone, errno_t rc)
[9a1b20c]351{
[1643855]352 if ((display_mask & DM_SYSTEM) != 0) {
[eadaeae8]353 printf("Hang up phone %p -> %s\n", phone, str_error_name(rc));
[1643855]354 ipcp_connection_clear(phone);
355 }
[9a1b20c]356}
357
358/** @}
359 */
Note: See TracBrowser for help on using the repository browser.