source: mainline/uspace/app/trace/ipcp.c@ 503ffce

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

Return IPC_CALLID_* in call data instead of callid

Callid will be replaced by capability handles soon so the API needs
to be cleanup up and any flags passed together with callid must be
passed using some other way.

  • 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>
[7354b5e]37#include <inttypes.h>
[d9c8c81]38#include <adt/hash_table.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{
[abf3564]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
[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
177void ipcp_call_out(int phone, ipc_call_t *call, ipc_callid_t hash)
178{
179 pending_call_t *pcall;
180 proto_t *proto;
[1643855]181 oper_t *oper;
[96b02eb9]182 sysarg_t *args;
[abf3564]183 int i;
[9a1b20c]184
185 if (have_conn[phone]) proto = connections[phone].proto;
186 else proto = NULL;
187
[abf3564]188 args = call->args;
189
[1643855]190 if ((display_mask & DM_IPC) != 0) {
[7e752b2]191 printf("Call ID: %p, phone: %d, proto: %s, method: ",
192 (void *) hash, phone,
193 (proto ? proto->name : "n/a"));
[228e490]194 ipc_m_print(proto, IPC_GET_IMETHOD(*call));
[7e752b2]195 printf(" args: (%" PRIun ", %" PRIun ", %" PRIun ", "
196 "%" PRIun ", %" PRIun ")\n",
197 args[1], args[2], args[3], args[4], args[5]);
[1643855]198 }
199
200
201 if ((display_mask & DM_USER) != 0) {
202
203 if (proto != NULL) {
[228e490]204 oper = proto_get_oper(proto, IPC_GET_IMETHOD(*call));
[1643855]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
[abf3564]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');
[1643855]231 }
[abf3564]232 } else {
233 oper = NULL;
[1643855]234 }
[9a1b20c]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;
[abf3564]242 pcall->oper = oper;
[9a1b20c]243
[062d900]244 hash_table_insert(&pending_calls, &pcall->link);
[9a1b20c]245}
246
[1643855]247static void parse_answer(ipc_callid_t hash, pending_call_t *pcall,
248 ipc_call_t *answer)
[9a1b20c]249{
[96b02eb9]250 sysarg_t phone;
251 sysarg_t method;
252 sysarg_t service;
253 sysarg_t retval;
[9a1b20c]254 proto_t *proto;
255 int cphone;
[79ae36dd]256
[96b02eb9]257 sysarg_t *resp;
[abf3564]258 oper_t *oper;
259 int i;
[79ae36dd]260
[9a1b20c]261 phone = pcall->phone_hash;
[228e490]262 method = IPC_GET_IMETHOD(pcall->question);
[9a1b20c]263 retval = IPC_GET_RETVAL(*answer);
[79ae36dd]264
[abf3564]265 resp = answer->args;
[79ae36dd]266
[1643855]267 if ((display_mask & DM_IPC) != 0) {
[7e752b2]268 printf("Response to %p: retval=%" PRIdn ", args = (%" PRIun ", "
269 "%" PRIun ", %" PRIun ", %" PRIun ", %" PRIun ")\n",
270 (void *) hash, retval, IPC_GET_ARG1(*answer),
[1ccafee]271 IPC_GET_ARG2(*answer), IPC_GET_ARG3(*answer),
272 IPC_GET_ARG4(*answer), IPC_GET_ARG5(*answer));
[1643855]273 }
[79ae36dd]274
[1643855]275 if ((display_mask & DM_USER) != 0) {
[abf3564]276 oper = pcall->oper;
[79ae36dd]277
278 if ((oper != NULL) &&
279 ((oper->rv_type != V_VOID) || (oper->respc > 0))) {
[abf3564]280 printf("->");
[79ae36dd]281
[abf3564]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) {
[79ae36dd]291 if (i > 1)
292 printf(", ");
[abf3564]293 val_print(resp[i], oper->resp_type[i - 1]);
294 }
295 putchar(')');
296 }
[79ae36dd]297
[abf3564]298 putchar('\n');
299 }
[1643855]300 }
[79ae36dd]301
302 if ((phone == PHONE_NS) && (method == IPC_M_CONNECT_ME_TO) &&
303 (retval == 0)) {
[9a1b20c]304 /* Connected to a service (through NS) */
[2133e02]305 service = IPC_GET_ARG2(pcall->question);
[9a1b20c]306 proto = proto_get_by_srv(service);
[79ae36dd]307 if (proto == NULL)
308 proto = proto_unknown;
309
[9a1b20c]310 cphone = IPC_GET_ARG5(*answer);
[1643855]311 if ((display_mask & DM_SYSTEM) != 0) {
312 printf("Registering connection (phone %d, protocol: %s)\n", cphone,
[79ae36dd]313 proto->name);
[1643855]314 }
[79ae36dd]315
[9a1b20c]316 ipcp_connection_set(cphone, 0, proto);
317 }
318}
319
320void ipcp_call_in(ipc_call_t *call, ipc_callid_t hash)
321{
[062d900]322 ht_link_t *item;
[9a1b20c]323 pending_call_t *pcall;
[79ae36dd]324
[503ffce]325 if ((call->flags & IPC_CALLID_ANSWERED) == 0 &&
326 hash != IPCP_CALLID_SYNC) {
[9a1b20c]327 /* Not a response */
[1643855]328 if ((display_mask & DM_IPC) != 0) {
[7e752b2]329 printf("Not a response (hash %p)\n", (void *) hash);
[1643855]330 }
[9a1b20c]331 return;
332 }
[79ae36dd]333
[062d900]334 item = hash_table_find(&pending_calls, &hash);
[79ae36dd]335 if (item == NULL)
336 return; /* No matching question found */
337
[1643855]338 /*
339 * Response matched to question.
340 */
[9a1b20c]341
[062d900]342 pcall = hash_table_get_inst(item, pending_call_t, link);
343 hash_table_remove(&pending_calls, &hash);
[79ae36dd]344
[1643855]345 parse_answer(hash, pcall, call);
[9a1b20c]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{
[1643855]357 if ((display_mask & DM_SYSTEM) != 0) {
358 printf("Hang phone %d up -> %d\n", phone, rc);
359 ipcp_connection_clear(phone);
360 }
[9a1b20c]361}
362
363/** @}
364 */
Note: See TracBrowser for help on using the repository browser.