source: mainline/uspace/lib/graph/graph.c@ eec201d

Last change on this file since eec201d was f5837524, checked in by Jakub Jermar <jakub@…>, 7 years ago

Use user-defined labels instead of phone hashes

This commit changes the way how the async framework maps incomming calls
to connections. Instead of abusing the kernel addresses of attached
phones as identifiers, the IPC_M_CONNECT_TO_ME and IPC_M_CONNECT_ME_TO
messages allow the server to specify an arbitrary label which is
remembered in the connected phone and consequently imprinted on each
call which is routed through this phone.

The async framework uses the address of the connection structure as the
label. This removes the need for a connection hash table because each
incoming call already remembers the connection in its label.

To disambiguate this new label and the other user-defined label used for
answers, the call structure now has the request_label member for the
former and answer_label member for the latter.

This commit also moves the kernel definition of ipc_data_t to abi/ and
removes the uspace redefinition thereof. Finally, when forwarding the
IPC_M_CONNECT_TO_ME call, the phone capability and the kernel object
allocated in request_process are now correctly disposed of.

  • Property mode set to 100644
File size: 14.3 KB
Line 
1/*
2 * Copyright (c) 2011 Petr Koupy
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 graph
30 * @{
31 */
32/**
33 * @file
34 */
35
36#include <assert.h>
37#include <errno.h>
38#include <inttypes.h>
39#include <stdio.h>
40#include <as.h>
41#include <stdlib.h>
42#include "graph.h"
43
44#define NAMESPACE "graphemu"
45#define VISUALIZER_NAME "vsl"
46#define RENDERER_NAME "rnd"
47
48static sysarg_t namespace_idx = 0;
49static sysarg_t visualizer_idx = 0;
50static sysarg_t renderer_idx = 0;
51
52static LIST_INITIALIZE(visualizer_list);
53static LIST_INITIALIZE(renderer_list);
54
55static FIBRIL_MUTEX_INITIALIZE(visualizer_list_mtx);
56static FIBRIL_MUTEX_INITIALIZE(renderer_list_mtx);
57
58visualizer_t *graph_alloc_visualizer(void)
59{
60 return ((visualizer_t *) malloc(sizeof(visualizer_t)));
61}
62
63renderer_t *graph_alloc_renderer(void)
64{
65 // TODO
66 return ((renderer_t *) malloc(sizeof(renderer_t)));
67}
68
69void graph_init_visualizer(visualizer_t *vs)
70{
71 link_initialize(&vs->link);
72 atomic_flag_clear(&vs->claimed);
73 vs->notif_sess = NULL;
74 fibril_mutex_initialize(&vs->mode_mtx);
75 list_initialize(&vs->modes);
76 vs->mode_set = false;
77 vs->cells.data = NULL;
78 vs->dev_ctx = NULL;
79}
80
81void graph_init_renderer(renderer_t *rnd)
82{
83 // TODO
84 link_initialize(&rnd->link);
85 refcount_init(&rnd->ref_cnt);
86}
87
88errno_t graph_register_visualizer(visualizer_t *vs)
89{
90 char node[LOC_NAME_MAXLEN + 1];
91 snprintf(node, LOC_NAME_MAXLEN, "%s%zu/%s%zu", NAMESPACE,
92 namespace_idx, VISUALIZER_NAME, visualizer_idx++);
93
94 category_id_t cat;
95 errno_t rc = loc_category_get_id("visualizer", &cat, 0);
96 if (rc != EOK)
97 return rc;
98
99 rc = loc_service_register(node, &vs->reg_svc_handle);
100 if (rc != EOK)
101 return rc;
102
103 rc = loc_service_add_to_cat(vs->reg_svc_handle, cat);
104 if (rc != EOK) {
105 loc_service_unregister(vs->reg_svc_handle);
106 return rc;
107 }
108
109 fibril_mutex_lock(&visualizer_list_mtx);
110 list_append(&vs->link, &visualizer_list);
111 fibril_mutex_unlock(&visualizer_list_mtx);
112
113 return rc;
114}
115
116errno_t graph_register_renderer(renderer_t *rnd)
117{
118 char node[LOC_NAME_MAXLEN + 1];
119 snprintf(node, LOC_NAME_MAXLEN, "%s%zu/%s%zu", NAMESPACE,
120 namespace_idx, RENDERER_NAME, renderer_idx++);
121
122 category_id_t cat;
123 errno_t rc = loc_category_get_id("renderer", &cat, 0);
124 if (rc != EOK)
125 return rc;
126
127 rc = loc_service_register(node, &rnd->reg_svc_handle);
128 if (rc != EOK)
129 return rc;
130
131 rc = loc_service_add_to_cat(rnd->reg_svc_handle, cat);
132 if (rc != EOK) {
133 loc_service_unregister(rnd->reg_svc_handle);
134 return rc;
135 }
136
137 fibril_mutex_lock(&renderer_list_mtx);
138 list_append(&rnd->link, &renderer_list);
139 fibril_mutex_unlock(&renderer_list_mtx);
140
141 return rc;
142}
143
144visualizer_t *graph_get_visualizer(sysarg_t handle)
145{
146 visualizer_t *vs = NULL;
147
148 fibril_mutex_lock(&visualizer_list_mtx);
149
150 list_foreach(visualizer_list, link, visualizer_t, vcur) {
151 if (vcur->reg_svc_handle == handle) {
152 vs = vcur;
153 break;
154 }
155 }
156
157 fibril_mutex_unlock(&visualizer_list_mtx);
158
159 return vs;
160}
161
162renderer_t *graph_get_renderer(sysarg_t handle)
163{
164 renderer_t *rnd = NULL;
165
166 fibril_mutex_lock(&renderer_list_mtx);
167
168 list_foreach(renderer_list, link, renderer_t, rcur) {
169 if (rcur->reg_svc_handle == handle) {
170 rnd = rcur;
171 break;
172 }
173 }
174
175 if (rnd)
176 refcount_up(&rnd->ref_cnt);
177
178 fibril_mutex_unlock(&renderer_list_mtx);
179
180 return rnd;
181}
182
183errno_t graph_unregister_visualizer(visualizer_t *vs)
184{
185 fibril_mutex_lock(&visualizer_list_mtx);
186 errno_t rc = loc_service_unregister(vs->reg_svc_handle);
187 list_remove(&vs->link);
188 fibril_mutex_unlock(&visualizer_list_mtx);
189
190 return rc;
191}
192
193errno_t graph_unregister_renderer(renderer_t *rnd)
194{
195 fibril_mutex_lock(&renderer_list_mtx);
196 errno_t rc = loc_service_unregister(rnd->reg_svc_handle);
197 list_remove(&rnd->link);
198 fibril_mutex_unlock(&renderer_list_mtx);
199
200 return rc;
201}
202
203void graph_destroy_visualizer(visualizer_t *vs)
204{
205 assert(!atomic_flag_test_and_set(&vs->claimed));
206 assert(vs->notif_sess == NULL);
207 assert(!fibril_mutex_is_locked(&vs->mode_mtx));
208 assert(list_empty(&vs->modes));
209 assert(vs->mode_set == false);
210 assert(vs->cells.data == NULL);
211 assert(vs->dev_ctx == NULL);
212
213 free(vs);
214}
215
216void graph_destroy_renderer(renderer_t *rnd)
217{
218 // TODO
219 if (refcount_down(&rnd->ref_cnt))
220 free(rnd);
221}
222
223errno_t graph_notify_mode_change(async_sess_t *sess, sysarg_t handle, sysarg_t mode_idx)
224{
225 async_exch_t *exch = async_exchange_begin(sess);
226 errno_t ret = async_req_2_0(exch, VISUALIZER_MODE_CHANGE, handle, mode_idx);
227 async_exchange_end(exch);
228
229 return ret;
230}
231
232errno_t graph_notify_disconnect(async_sess_t *sess, sysarg_t handle)
233{
234 async_exch_t *exch = async_exchange_begin(sess);
235 errno_t ret = async_req_1_0(exch, VISUALIZER_DISCONNECT, handle);
236 async_exchange_end(exch);
237
238 async_hangup(sess);
239
240 return ret;
241}
242
243static void vs_claim(visualizer_t *vs, ipc_call_t *icall)
244{
245 vs->client_side_handle = IPC_GET_ARG1(*icall);
246 errno_t rc = vs->ops.claim(vs);
247 async_answer_0(icall, rc);
248}
249
250static void vs_yield(visualizer_t *vs, ipc_call_t *icall)
251{
252 /* Deallocate resources for the current mode. */
253 if (vs->mode_set) {
254 if (vs->cells.data != NULL) {
255 as_area_destroy((void *) vs->cells.data);
256 vs->cells.data = NULL;
257 }
258 }
259
260 /* Driver might also deallocate resources for the current mode. */
261 errno_t rc = vs->ops.yield(vs);
262
263 /*
264 * Now that the driver was given a chance to deallocate resources,
265 * current mode can be unset.
266 */
267 if (vs->mode_set)
268 vs->mode_set = false;
269
270 async_answer_0(icall, rc);
271}
272
273static void vs_enumerate_modes(visualizer_t *vs, ipc_call_t *icall)
274{
275 size_t len;
276
277 ipc_call_t call;
278 if (!async_data_read_receive(&call, &len)) {
279 async_answer_0(&call, EREFUSED);
280 async_answer_0(icall, EREFUSED);
281 return;
282 }
283
284 fibril_mutex_lock(&vs->mode_mtx);
285 link_t *link = list_nth(&vs->modes, IPC_GET_ARG1(*icall));
286
287 if (link != NULL) {
288 vslmode_list_element_t *mode_elem =
289 list_get_instance(link, vslmode_list_element_t, link);
290
291 errno_t rc = async_data_read_finalize(&call, &mode_elem->mode, len);
292 async_answer_0(icall, rc);
293 } else {
294 async_answer_0(&call, ENOENT);
295 async_answer_0(icall, ENOENT);
296 }
297
298 fibril_mutex_unlock(&vs->mode_mtx);
299}
300
301static void vs_get_default_mode(visualizer_t *vs, ipc_call_t *icall)
302{
303 ipc_call_t call;
304 size_t len;
305 if (!async_data_read_receive(&call, &len)) {
306 async_answer_0(&call, EREFUSED);
307 async_answer_0(icall, EREFUSED);
308 return;
309 }
310
311 fibril_mutex_lock(&vs->mode_mtx);
312 vslmode_list_element_t *mode_elem = NULL;
313
314 list_foreach(vs->modes, link, vslmode_list_element_t, cur) {
315 if (cur->mode.index == vs->def_mode_idx) {
316 mode_elem = cur;
317 break;
318 }
319 }
320
321 if (mode_elem != NULL) {
322 errno_t rc = async_data_read_finalize(&call, &mode_elem->mode, len);
323 async_answer_0(icall, rc);
324 } else {
325 fibril_mutex_unlock(&vs->mode_mtx);
326 async_answer_0(&call, ENOENT);
327 async_answer_0(icall, ENOENT);
328 }
329
330 fibril_mutex_unlock(&vs->mode_mtx);
331}
332
333static void vs_get_current_mode(visualizer_t *vs, ipc_call_t *icall)
334{
335 ipc_call_t call;
336 size_t len;
337 if (!async_data_read_receive(&call, &len)) {
338 async_answer_0(&call, EREFUSED);
339 async_answer_0(icall, EREFUSED);
340 return;
341 }
342
343 if (vs->mode_set) {
344 errno_t rc = async_data_read_finalize(&call, &vs->cur_mode, len);
345 async_answer_0(icall, rc);
346 } else {
347 async_answer_0(&call, ENOENT);
348 async_answer_0(icall, ENOENT);
349 }
350}
351
352static void vs_get_mode(visualizer_t *vs, ipc_call_t *icall)
353{
354 ipc_call_t call;
355 size_t len;
356 if (!async_data_read_receive(&call, &len)) {
357 async_answer_0(&call, EREFUSED);
358 async_answer_0(icall, EREFUSED);
359 return;
360 }
361
362 sysarg_t mode_idx = IPC_GET_ARG1(*icall);
363
364 fibril_mutex_lock(&vs->mode_mtx);
365 vslmode_list_element_t *mode_elem = NULL;
366
367 list_foreach(vs->modes, link, vslmode_list_element_t, cur) {
368 if (cur->mode.index == mode_idx) {
369 mode_elem = cur;
370 break;
371 }
372 }
373
374 if (mode_elem != NULL) {
375 errno_t rc = async_data_read_finalize(&call, &mode_elem->mode, len);
376 async_answer_0(icall, rc);
377 } else {
378 async_answer_0(&call, ENOENT);
379 async_answer_0(icall, ENOENT);
380 }
381
382 fibril_mutex_unlock(&vs->mode_mtx);
383}
384
385static void vs_set_mode(visualizer_t *vs, ipc_call_t *icall)
386{
387 ipc_call_t call;
388 size_t size;
389 unsigned int flags;
390
391 /* Retrieve the shared cell storage for the new mode. */
392 if (!async_share_out_receive(&call, &size, &flags)) {
393 async_answer_0(&call, EREFUSED);
394 async_answer_0(icall, EREFUSED);
395 return;
396 }
397
398 /* Retrieve mode index and version. */
399 sysarg_t mode_idx = IPC_GET_ARG1(*icall);
400 sysarg_t mode_version = IPC_GET_ARG2(*icall);
401
402 /* Find mode in the list. */
403 fibril_mutex_lock(&vs->mode_mtx);
404 vslmode_list_element_t *mode_elem = NULL;
405
406 list_foreach(vs->modes, link, vslmode_list_element_t, cur) {
407 if (cur->mode.index == mode_idx) {
408 mode_elem = cur;
409 break;
410 }
411 }
412
413 if (mode_elem == NULL) {
414 fibril_mutex_unlock(&vs->mode_mtx);
415 async_answer_0(&call, ENOENT);
416 async_answer_0(icall, ENOENT);
417 return;
418 }
419
420 /* Extract mode description from the list node. */
421 vslmode_t new_mode = mode_elem->mode;
422 fibril_mutex_unlock(&vs->mode_mtx);
423
424 /* Check whether the mode is still up-to-date. */
425 if (new_mode.version != mode_version) {
426 async_answer_0(&call, EINVAL);
427 async_answer_0(icall, EINVAL);
428 return;
429 }
430
431 void *new_cell_storage;
432 errno_t rc = async_share_out_finalize(&call, &new_cell_storage);
433 if ((rc != EOK) || (new_cell_storage == AS_MAP_FAILED)) {
434 async_answer_0(icall, ENOMEM);
435 return;
436 }
437
438 /* Change device internal state. */
439 rc = vs->ops.change_mode(vs, new_mode);
440
441 /* Device driver could not establish new mode. Rollback. */
442 if (rc != EOK) {
443 as_area_destroy(new_cell_storage);
444 async_answer_0(icall, ENOMEM);
445 return;
446 }
447
448 /*
449 * Because resources for the new mode were successfully
450 * claimed, it is finally possible to free resources
451 * allocated for the old mode.
452 */
453 if (vs->mode_set) {
454 if (vs->cells.data != NULL) {
455 as_area_destroy((void *) vs->cells.data);
456 vs->cells.data = NULL;
457 }
458 }
459
460 /* Insert new mode into the visualizer. */
461 vs->cells.width = new_mode.screen_width;
462 vs->cells.height = new_mode.screen_height;
463 vs->cells.data = (pixel_t *) new_cell_storage;
464 vs->cur_mode = new_mode;
465 vs->mode_set = true;
466
467 async_answer_0(icall, EOK);
468}
469
470static void vs_update_damaged_region(visualizer_t *vs, ipc_call_t *icall)
471{
472 sysarg_t x_offset = (IPC_GET_ARG5(*icall) >> 16);
473 sysarg_t y_offset = (IPC_GET_ARG5(*icall) & 0x0000ffff);
474
475 errno_t rc = vs->ops.handle_damage(vs,
476 IPC_GET_ARG1(*icall), IPC_GET_ARG2(*icall),
477 IPC_GET_ARG3(*icall), IPC_GET_ARG4(*icall),
478 x_offset, y_offset);
479 async_answer_0(icall, rc);
480}
481
482static void vs_suspend(visualizer_t *vs, ipc_call_t *icall)
483{
484 errno_t rc = vs->ops.suspend(vs);
485 async_answer_0(icall, rc);
486}
487
488static void vs_wakeup(visualizer_t *vs, ipc_call_t *icall)
489{
490 errno_t rc = vs->ops.wakeup(vs);
491 async_answer_0(icall, rc);
492}
493
494void graph_visualizer_connection(visualizer_t *vs, ipc_call_t *icall, void *arg)
495{
496 /* Claim the visualizer. */
497 if (atomic_flag_test_and_set(&vs->claimed)) {
498 async_answer_0(icall, ELIMIT);
499 return;
500 }
501
502 /* Accept the connection. */
503 async_answer_5(icall, EOK, 0, 0, 0, 0, async_get_label());
504
505 /* Establish callback session. */
506 ipc_call_t call;
507 async_get_call(&call);
508 vs->notif_sess = async_callback_receive_start(EXCHANGE_SERIALIZE, &call);
509 if (vs->notif_sess != NULL)
510 async_answer_0(&call, EOK);
511 else
512 async_answer_0(&call, ELIMIT);
513
514 /* Enter command loop. */
515 while (true) {
516 async_get_call(&call);
517
518 if (!IPC_GET_IMETHOD(call)) {
519 async_answer_0(&call, EOK);
520 break;
521 }
522
523 switch (IPC_GET_IMETHOD(call)) {
524 case VISUALIZER_CLAIM:
525 vs_claim(vs, &call);
526 break;
527 case VISUALIZER_YIELD:
528 vs_yield(vs, &call);
529 goto terminate;
530 case VISUALIZER_ENUMERATE_MODES:
531 vs_enumerate_modes(vs, &call);
532 break;
533 case VISUALIZER_GET_DEFAULT_MODE:
534 vs_get_default_mode(vs, &call);
535 break;
536 case VISUALIZER_GET_CURRENT_MODE:
537 vs_get_current_mode(vs, &call);
538 break;
539 case VISUALIZER_GET_MODE:
540 vs_get_mode(vs, &call);
541 break;
542 case VISUALIZER_SET_MODE:
543 vs_set_mode(vs, &call);
544 break;
545 case VISUALIZER_UPDATE_DAMAGED_REGION:
546 vs_update_damaged_region(vs, &call);
547 break;
548 case VISUALIZER_SUSPEND:
549 vs_suspend(vs, &call);
550 break;
551 case VISUALIZER_WAKE_UP:
552 vs_wakeup(vs, &call);
553 break;
554 default:
555 async_answer_0(&call, EINVAL);
556 goto terminate;
557 }
558 }
559
560terminate:
561 async_hangup(vs->notif_sess);
562 vs->notif_sess = NULL;
563 atomic_flag_clear(&vs->claimed);
564}
565
566void graph_renderer_connection(renderer_t *rnd, ipc_call_t *icall, void *arg)
567{
568 // TODO
569
570 /* Accept the connection. */
571 async_answer_5(icall, EOK, 0, 0, 0, 0, async_get_label());
572
573 /* Enter command loop. */
574 while (true) {
575 ipc_call_t call;
576 async_get_call(&call);
577
578 if (!IPC_GET_IMETHOD(call)) {
579 async_answer_0(&call, EOK);
580 break;
581 }
582
583 switch (IPC_GET_IMETHOD(call)) {
584 default:
585 async_answer_0(&call, EINVAL);
586 goto terminate;
587 }
588 }
589
590terminate:
591 graph_destroy_renderer(rnd);
592}
593
594void graph_client_connection(ipc_call_t *icall, void *arg)
595{
596 /* Find the visualizer or renderer with the given service ID. */
597 visualizer_t *vs = graph_get_visualizer(IPC_GET_ARG2(*icall));
598 renderer_t *rnd = graph_get_renderer(IPC_GET_ARG2(*icall));
599
600 if (vs != NULL)
601 graph_visualizer_connection(vs, icall, arg);
602 else if (rnd != NULL)
603 graph_renderer_connection(rnd, icall, arg);
604 else
605 async_answer_0(icall, ENOENT);
606}
607
608/** @}
609 */
Note: See TracBrowser for help on using the repository browser.