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

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

Use NULL instead of 0 as a hash_table_ops_t member initializer.

  • Property mode set to 100644
File size: 8.5 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>
[062d900]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
[062d900]55 ht_link_t link;
[9a1b20c]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
[062d900]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
[9a1b20c]75
[062d900]76static size_t pending_call_key_hash(void *key)
[9a1b20c]77{
[062d900]78 ipc_callid_t *call_id = (ipc_callid_t *)key;
79 return *call_id;
[9a1b20c]80}
81
[062d900]82static size_t pending_call_hash(const ht_link_t *item)
[9a1b20c]83{
[062d900]84 pending_call_t *hs = hash_table_get_inst(item, pending_call_t, link);
85 return hs->call_hash;
[9a1b20c]86}
87
[062d900]88static bool pending_call_key_equal(void *key, const ht_link_t *item)
[9a1b20c]89{
[062d900]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;
[9a1b20c]94}
95
[062d900]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,
[4e00f87]100 .equal = NULL,
101 .remove_callback = NULL
[062d900]102};
103
[9a1b20c]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
[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{
[8c125ad]142 ipc_m_desc_t *desc;
143 oper_t *oper;
144
[abf3564]145 val_type_t arg_def[OPER_MAX_ARGS] = {
146 V_INTEGER,
147 V_INTEGER,
148 V_INTEGER,
149 V_INTEGER,
150 V_INTEGER
151 };
152
[8c125ad]153 /*
154 * Create a pseudo-protocol 'unknown' that has no known methods.
155 */
156 proto_unknown = proto_new("unknown");
157
158 /*
159 * Create a pseudo-protocol 'system' defining names of system IPC
160 * methods.
161 */
162 proto_system = proto_new("system");
163
164 desc = ipc_methods;
165 while (desc->number != 0) {
[abf3564]166 oper = oper_new(desc->name, OPER_MAX_ARGS, arg_def, V_INTEGER,
167 OPER_MAX_ARGS, arg_def);
[8c125ad]168 proto_add_oper(proto_system, desc->number, oper);
169
170 ++desc;
171 }
172
[062d900]173 bool ok = hash_table_create(&pending_calls, 0, 0, &pending_call_ops);
174 assert(ok);
[9a1b20c]175}
176
177void ipcp_cleanup(void)
178{
[8c125ad]179 proto_delete(proto_system);
[9a1b20c]180 hash_table_destroy(&pending_calls);
181}
182
183void ipcp_call_out(int phone, ipc_call_t *call, ipc_callid_t hash)
184{
185 pending_call_t *pcall;
186 proto_t *proto;
[1643855]187 oper_t *oper;
[96b02eb9]188 sysarg_t *args;
[abf3564]189 int i;
[9a1b20c]190
191 if (have_conn[phone]) proto = connections[phone].proto;
192 else proto = NULL;
193
[abf3564]194 args = call->args;
195
[1643855]196 if ((display_mask & DM_IPC) != 0) {
[7e752b2]197 printf("Call ID: %p, phone: %d, proto: %s, method: ",
198 (void *) hash, phone,
199 (proto ? proto->name : "n/a"));
[228e490]200 ipc_m_print(proto, IPC_GET_IMETHOD(*call));
[7e752b2]201 printf(" args: (%" PRIun ", %" PRIun ", %" PRIun ", "
202 "%" PRIun ", %" PRIun ")\n",
203 args[1], args[2], args[3], args[4], args[5]);
[1643855]204 }
205
206
207 if ((display_mask & DM_USER) != 0) {
208
209 if (proto != NULL) {
[228e490]210 oper = proto_get_oper(proto, IPC_GET_IMETHOD(*call));
[1643855]211 } else {
212 oper = NULL;
213 }
214
215 if (oper != NULL) {
216
217 printf("%s(%d).%s", (proto ? proto->name : "n/a"),
218 phone, (oper ? oper->name : "unknown"));
219
[abf3564]220 putchar('(');
221 for (i = 1; i <= oper->argc; ++i) {
222 if (i > 1) printf(", ");
223 val_print(args[i], oper->arg_type[i - 1]);
224 }
225 putchar(')');
226
227 if (oper->rv_type == V_VOID && oper->respc == 0) {
228 /*
229 * No response data (typically the task will
230 * not be interested in the response).
231 * We will not display response.
232 */
233 putchar('.');
234 }
235
236 putchar('\n');
[1643855]237 }
[abf3564]238 } else {
239 oper = NULL;
[1643855]240 }
[9a1b20c]241
242 /* Store call in hash table for response matching */
243
244 pcall = malloc(sizeof(pending_call_t));
245 pcall->phone_hash = phone;
246 pcall->question = *call;
247 pcall->call_hash = hash;
[abf3564]248 pcall->oper = oper;
[9a1b20c]249
[062d900]250 hash_table_insert(&pending_calls, &pcall->link);
[9a1b20c]251}
252
[1643855]253static void parse_answer(ipc_callid_t hash, pending_call_t *pcall,
254 ipc_call_t *answer)
[9a1b20c]255{
[96b02eb9]256 sysarg_t phone;
257 sysarg_t method;
258 sysarg_t service;
259 sysarg_t retval;
[9a1b20c]260 proto_t *proto;
261 int cphone;
[79ae36dd]262
[96b02eb9]263 sysarg_t *resp;
[abf3564]264 oper_t *oper;
265 int i;
[79ae36dd]266
[9a1b20c]267 phone = pcall->phone_hash;
[228e490]268 method = IPC_GET_IMETHOD(pcall->question);
[9a1b20c]269 retval = IPC_GET_RETVAL(*answer);
[79ae36dd]270
[abf3564]271 resp = answer->args;
[79ae36dd]272
[1643855]273 if ((display_mask & DM_IPC) != 0) {
[7e752b2]274 printf("Response to %p: retval=%" PRIdn ", args = (%" PRIun ", "
275 "%" PRIun ", %" PRIun ", %" PRIun ", %" PRIun ")\n",
276 (void *) hash, retval, IPC_GET_ARG1(*answer),
[1ccafee]277 IPC_GET_ARG2(*answer), IPC_GET_ARG3(*answer),
278 IPC_GET_ARG4(*answer), IPC_GET_ARG5(*answer));
[1643855]279 }
[79ae36dd]280
[1643855]281 if ((display_mask & DM_USER) != 0) {
[abf3564]282 oper = pcall->oper;
[79ae36dd]283
284 if ((oper != NULL) &&
285 ((oper->rv_type != V_VOID) || (oper->respc > 0))) {
[abf3564]286 printf("->");
[79ae36dd]287
[abf3564]288 if (oper->rv_type != V_VOID) {
289 putchar(' ');
290 val_print(retval, oper->rv_type);
291 }
292
293 if (oper->respc > 0) {
294 putchar(' ');
295 putchar('(');
296 for (i = 1; i <= oper->respc; ++i) {
[79ae36dd]297 if (i > 1)
298 printf(", ");
[abf3564]299 val_print(resp[i], oper->resp_type[i - 1]);
300 }
301 putchar(')');
302 }
[79ae36dd]303
[abf3564]304 putchar('\n');
305 }
[1643855]306 }
[79ae36dd]307
308 if ((phone == PHONE_NS) && (method == IPC_M_CONNECT_ME_TO) &&
309 (retval == 0)) {
[9a1b20c]310 /* Connected to a service (through NS) */
311 service = IPC_GET_ARG1(pcall->question);
312 proto = proto_get_by_srv(service);
[79ae36dd]313 if (proto == NULL)
314 proto = proto_unknown;
315
[9a1b20c]316 cphone = IPC_GET_ARG5(*answer);
[1643855]317 if ((display_mask & DM_SYSTEM) != 0) {
318 printf("Registering connection (phone %d, protocol: %s)\n", cphone,
[79ae36dd]319 proto->name);
[1643855]320 }
[79ae36dd]321
[9a1b20c]322 ipcp_connection_set(cphone, 0, proto);
323 }
324}
325
326void ipcp_call_in(ipc_call_t *call, ipc_callid_t hash)
327{
[062d900]328 ht_link_t *item;
[9a1b20c]329 pending_call_t *pcall;
[79ae36dd]330
[9a1b20c]331 if ((hash & IPC_CALLID_ANSWERED) == 0 && hash != IPCP_CALLID_SYNC) {
332 /* Not a response */
[1643855]333 if ((display_mask & DM_IPC) != 0) {
[7e752b2]334 printf("Not a response (hash %p)\n", (void *) hash);
[1643855]335 }
[9a1b20c]336 return;
337 }
[79ae36dd]338
[9a1b20c]339 hash = hash & ~IPC_CALLID_ANSWERED;
[79ae36dd]340
[062d900]341 item = hash_table_find(&pending_calls, &hash);
[79ae36dd]342 if (item == NULL)
343 return; /* No matching question found */
344
[1643855]345 /*
346 * Response matched to question.
347 */
[9a1b20c]348
[062d900]349 pcall = hash_table_get_inst(item, pending_call_t, link);
350 hash_table_remove(&pending_calls, &hash);
[79ae36dd]351
[1643855]352 parse_answer(hash, pcall, call);
[9a1b20c]353 free(pcall);
354}
355
356void ipcp_call_sync(int phone, ipc_call_t *call, ipc_call_t *answer)
357{
358 ipcp_call_out(phone, call, IPCP_CALLID_SYNC);
359 ipcp_call_in(answer, IPCP_CALLID_SYNC);
360}
361
362void ipcp_hangup(int phone, int rc)
363{
[1643855]364 if ((display_mask & DM_SYSTEM) != 0) {
365 printf("Hang phone %d up -> %d\n", phone, rc);
366 ipcp_connection_clear(phone);
367 }
[9a1b20c]368}
369
370/** @}
371 */
Note: See TracBrowser for help on using the repository browser.