source: mainline/uspace/lib/graph/graph.c@ 492377a

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 492377a was 984a9ba, checked in by Martin Decky <martin@…>, 7 years ago

do not expose the call capability handler from the async framework

Keep the call capability handler encapsulated within the async framework
and do not expose it explicitly via its API. Use the pointer to
ipc_call_t as the sole object identifying an IPC call in the code that
uses the async framework.

This plugs a major leak in the abstraction and also simplifies both the
async framework (slightly) and all IPC servers.

  • Property mode set to 100644
File size: 14.2 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_set(&vs->ref_cnt, 0);
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 atomic_set(&rnd->ref_cnt, 0);
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 fibril_mutex_unlock(&renderer_list_mtx);
176
177 return rnd;
178}
179
180errno_t graph_unregister_visualizer(visualizer_t *vs)
181{
182 fibril_mutex_lock(&visualizer_list_mtx);
183 errno_t rc = loc_service_unregister(vs->reg_svc_handle);
184 list_remove(&vs->link);
185 fibril_mutex_unlock(&visualizer_list_mtx);
186
187 return rc;
188}
189
190errno_t graph_unregister_renderer(renderer_t *rnd)
191{
192 fibril_mutex_lock(&renderer_list_mtx);
193 errno_t rc = loc_service_unregister(rnd->reg_svc_handle);
194 list_remove(&rnd->link);
195 fibril_mutex_unlock(&renderer_list_mtx);
196
197 return rc;
198}
199
200void graph_destroy_visualizer(visualizer_t *vs)
201{
202 assert(atomic_get(&vs->ref_cnt) == 0);
203 assert(vs->notif_sess == NULL);
204 assert(!fibril_mutex_is_locked(&vs->mode_mtx));
205 assert(list_empty(&vs->modes));
206 assert(vs->mode_set == false);
207 assert(vs->cells.data == NULL);
208 assert(vs->dev_ctx == NULL);
209
210 free(vs);
211}
212
213void graph_destroy_renderer(renderer_t *rnd)
214{
215 // TODO
216 assert(atomic_get(&rnd->ref_cnt) == 0);
217
218 free(rnd);
219}
220
221errno_t graph_notify_mode_change(async_sess_t *sess, sysarg_t handle, sysarg_t mode_idx)
222{
223 async_exch_t *exch = async_exchange_begin(sess);
224 errno_t ret = async_req_2_0(exch, VISUALIZER_MODE_CHANGE, handle, mode_idx);
225 async_exchange_end(exch);
226
227 return ret;
228}
229
230errno_t graph_notify_disconnect(async_sess_t *sess, sysarg_t handle)
231{
232 async_exch_t *exch = async_exchange_begin(sess);
233 errno_t ret = async_req_1_0(exch, VISUALIZER_DISCONNECT, handle);
234 async_exchange_end(exch);
235
236 async_hangup(sess);
237
238 return ret;
239}
240
241static void vs_claim(visualizer_t *vs, ipc_call_t *icall)
242{
243 vs->client_side_handle = IPC_GET_ARG1(*icall);
244 errno_t rc = vs->ops.claim(vs);
245 async_answer_0(icall, rc);
246}
247
248static void vs_yield(visualizer_t *vs, ipc_call_t *icall)
249{
250 /* Deallocate resources for the current mode. */
251 if (vs->mode_set) {
252 if (vs->cells.data != NULL) {
253 as_area_destroy((void *) vs->cells.data);
254 vs->cells.data = NULL;
255 }
256 }
257
258 /* Driver might also deallocate resources for the current mode. */
259 errno_t rc = vs->ops.yield(vs);
260
261 /*
262 * Now that the driver was given a chance to deallocate resources,
263 * current mode can be unset.
264 */
265 if (vs->mode_set)
266 vs->mode_set = false;
267
268 async_answer_0(icall, rc);
269}
270
271static void vs_enumerate_modes(visualizer_t *vs, ipc_call_t *icall)
272{
273 size_t len;
274
275 ipc_call_t call;
276 if (!async_data_read_receive(&call, &len)) {
277 async_answer_0(&call, EREFUSED);
278 async_answer_0(icall, EREFUSED);
279 return;
280 }
281
282 fibril_mutex_lock(&vs->mode_mtx);
283 link_t *link = list_nth(&vs->modes, IPC_GET_ARG1(*icall));
284
285 if (link != NULL) {
286 vslmode_list_element_t *mode_elem =
287 list_get_instance(link, vslmode_list_element_t, link);
288
289 errno_t rc = async_data_read_finalize(&call, &mode_elem->mode, len);
290 async_answer_0(icall, rc);
291 } else {
292 async_answer_0(&call, ENOENT);
293 async_answer_0(icall, ENOENT);
294 }
295
296 fibril_mutex_unlock(&vs->mode_mtx);
297}
298
299static void vs_get_default_mode(visualizer_t *vs, ipc_call_t *icall)
300{
301 ipc_call_t call;
302 size_t len;
303 if (!async_data_read_receive(&call, &len)) {
304 async_answer_0(&call, EREFUSED);
305 async_answer_0(icall, EREFUSED);
306 return;
307 }
308
309 fibril_mutex_lock(&vs->mode_mtx);
310 vslmode_list_element_t *mode_elem = NULL;
311
312 list_foreach(vs->modes, link, vslmode_list_element_t, cur) {
313 if (cur->mode.index == vs->def_mode_idx) {
314 mode_elem = cur;
315 break;
316 }
317 }
318
319 if (mode_elem != NULL) {
320 errno_t rc = async_data_read_finalize(&call, &mode_elem->mode, len);
321 async_answer_0(icall, rc);
322 } else {
323 fibril_mutex_unlock(&vs->mode_mtx);
324 async_answer_0(&call, ENOENT);
325 async_answer_0(icall, ENOENT);
326 }
327
328 fibril_mutex_unlock(&vs->mode_mtx);
329}
330
331static void vs_get_current_mode(visualizer_t *vs, ipc_call_t *icall)
332{
333 ipc_call_t call;
334 size_t len;
335 if (!async_data_read_receive(&call, &len)) {
336 async_answer_0(&call, EREFUSED);
337 async_answer_0(icall, EREFUSED);
338 return;
339 }
340
341 if (vs->mode_set) {
342 errno_t rc = async_data_read_finalize(&call, &vs->cur_mode, len);
343 async_answer_0(icall, rc);
344 } else {
345 async_answer_0(&call, ENOENT);
346 async_answer_0(icall, ENOENT);
347 }
348}
349
350static void vs_get_mode(visualizer_t *vs, ipc_call_t *icall)
351{
352 ipc_call_t call;
353 size_t len;
354 if (!async_data_read_receive(&call, &len)) {
355 async_answer_0(&call, EREFUSED);
356 async_answer_0(icall, EREFUSED);
357 return;
358 }
359
360 sysarg_t mode_idx = IPC_GET_ARG1(*icall);
361
362 fibril_mutex_lock(&vs->mode_mtx);
363 vslmode_list_element_t *mode_elem = NULL;
364
365 list_foreach(vs->modes, link, vslmode_list_element_t, cur) {
366 if (cur->mode.index == mode_idx) {
367 mode_elem = cur;
368 break;
369 }
370 }
371
372 if (mode_elem != NULL) {
373 errno_t rc = async_data_read_finalize(&call, &mode_elem->mode, len);
374 async_answer_0(icall, rc);
375 } else {
376 async_answer_0(&call, ENOENT);
377 async_answer_0(icall, ENOENT);
378 }
379
380 fibril_mutex_unlock(&vs->mode_mtx);
381}
382
383static void vs_set_mode(visualizer_t *vs, ipc_call_t *icall)
384{
385 ipc_call_t call;
386 size_t size;
387 unsigned int flags;
388
389 /* Retrieve the shared cell storage for the new mode. */
390 if (!async_share_out_receive(&call, &size, &flags)) {
391 async_answer_0(&call, EREFUSED);
392 async_answer_0(icall, EREFUSED);
393 return;
394 }
395
396 /* Retrieve mode index and version. */
397 sysarg_t mode_idx = IPC_GET_ARG1(*icall);
398 sysarg_t mode_version = IPC_GET_ARG2(*icall);
399
400 /* Find mode in the list. */
401 fibril_mutex_lock(&vs->mode_mtx);
402 vslmode_list_element_t *mode_elem = NULL;
403
404 list_foreach(vs->modes, link, vslmode_list_element_t, cur) {
405 if (cur->mode.index == mode_idx) {
406 mode_elem = cur;
407 break;
408 }
409 }
410
411 if (mode_elem == NULL) {
412 fibril_mutex_unlock(&vs->mode_mtx);
413 async_answer_0(&call, ENOENT);
414 async_answer_0(icall, ENOENT);
415 return;
416 }
417
418 /* Extract mode description from the list node. */
419 vslmode_t new_mode = mode_elem->mode;
420 fibril_mutex_unlock(&vs->mode_mtx);
421
422 /* Check whether the mode is still up-to-date. */
423 if (new_mode.version != mode_version) {
424 async_answer_0(&call, EINVAL);
425 async_answer_0(icall, EINVAL);
426 return;
427 }
428
429 void *new_cell_storage;
430 errno_t rc = async_share_out_finalize(&call, &new_cell_storage);
431 if ((rc != EOK) || (new_cell_storage == AS_MAP_FAILED)) {
432 async_answer_0(icall, ENOMEM);
433 return;
434 }
435
436 /* Change device internal state. */
437 rc = vs->ops.change_mode(vs, new_mode);
438
439 /* Device driver could not establish new mode. Rollback. */
440 if (rc != EOK) {
441 as_area_destroy(new_cell_storage);
442 async_answer_0(icall, ENOMEM);
443 return;
444 }
445
446 /*
447 * Because resources for the new mode were successfully
448 * claimed, it is finally possible to free resources
449 * allocated for the old mode.
450 */
451 if (vs->mode_set) {
452 if (vs->cells.data != NULL) {
453 as_area_destroy((void *) vs->cells.data);
454 vs->cells.data = NULL;
455 }
456 }
457
458 /* Insert new mode into the visualizer. */
459 vs->cells.width = new_mode.screen_width;
460 vs->cells.height = new_mode.screen_height;
461 vs->cells.data = (pixel_t *) new_cell_storage;
462 vs->cur_mode = new_mode;
463 vs->mode_set = true;
464
465 async_answer_0(icall, EOK);
466}
467
468static void vs_update_damaged_region(visualizer_t *vs, ipc_call_t *icall)
469{
470 sysarg_t x_offset = (IPC_GET_ARG5(*icall) >> 16);
471 sysarg_t y_offset = (IPC_GET_ARG5(*icall) & 0x0000ffff);
472
473 errno_t rc = vs->ops.handle_damage(vs,
474 IPC_GET_ARG1(*icall), IPC_GET_ARG2(*icall),
475 IPC_GET_ARG3(*icall), IPC_GET_ARG4(*icall),
476 x_offset, y_offset);
477 async_answer_0(icall, rc);
478}
479
480static void vs_suspend(visualizer_t *vs, ipc_call_t *icall)
481{
482 errno_t rc = vs->ops.suspend(vs);
483 async_answer_0(icall, rc);
484}
485
486static void vs_wakeup(visualizer_t *vs, ipc_call_t *icall)
487{
488 errno_t rc = vs->ops.wakeup(vs);
489 async_answer_0(icall, rc);
490}
491
492void graph_visualizer_connection(visualizer_t *vs, ipc_call_t *icall, void *arg)
493{
494 /* Claim the visualizer. */
495 if (!cas(&vs->ref_cnt, 0, 1)) {
496 async_answer_0(icall, ELIMIT);
497 return;
498 }
499
500 /* Accept the connection. */
501 async_answer_0(icall, EOK);
502
503 /* Establish callback session. */
504 ipc_call_t call;
505 async_get_call(&call);
506 vs->notif_sess = async_callback_receive_start(EXCHANGE_SERIALIZE, &call);
507 if (vs->notif_sess != NULL)
508 async_answer_0(&call, EOK);
509 else
510 async_answer_0(&call, ELIMIT);
511
512 /* Enter command loop. */
513 while (true) {
514 async_get_call(&call);
515
516 if (!IPC_GET_IMETHOD(call)) {
517 async_answer_0(&call, EINVAL);
518 break;
519 }
520
521 switch (IPC_GET_IMETHOD(call)) {
522 case VISUALIZER_CLAIM:
523 vs_claim(vs, &call);
524 break;
525 case VISUALIZER_YIELD:
526 vs_yield(vs, &call);
527 goto terminate;
528 case VISUALIZER_ENUMERATE_MODES:
529 vs_enumerate_modes(vs, &call);
530 break;
531 case VISUALIZER_GET_DEFAULT_MODE:
532 vs_get_default_mode(vs, &call);
533 break;
534 case VISUALIZER_GET_CURRENT_MODE:
535 vs_get_current_mode(vs, &call);
536 break;
537 case VISUALIZER_GET_MODE:
538 vs_get_mode(vs, &call);
539 break;
540 case VISUALIZER_SET_MODE:
541 vs_set_mode(vs, &call);
542 break;
543 case VISUALIZER_UPDATE_DAMAGED_REGION:
544 vs_update_damaged_region(vs, &call);
545 break;
546 case VISUALIZER_SUSPEND:
547 vs_suspend(vs, &call);
548 break;
549 case VISUALIZER_WAKE_UP:
550 vs_wakeup(vs, &call);
551 break;
552 default:
553 async_answer_0(&call, EINVAL);
554 goto terminate;
555 }
556 }
557
558terminate:
559 async_hangup(vs->notif_sess);
560 vs->notif_sess = NULL;
561 atomic_set(&vs->ref_cnt, 0);
562}
563
564void graph_renderer_connection(renderer_t *rnd, ipc_call_t *icall, void *arg)
565{
566 // TODO
567
568 /* Accept the connection. */
569 atomic_inc(&rnd->ref_cnt);
570 async_answer_0(icall, EOK);
571
572 /* Enter command loop. */
573 while (true) {
574 ipc_call_t call;
575 async_get_call(&call);
576
577 if (!IPC_GET_IMETHOD(call)) {
578 async_answer_0(&call, EINVAL);
579 break;
580 }
581
582 switch (IPC_GET_IMETHOD(call)) {
583 default:
584 async_answer_0(&call, EINVAL);
585 goto terminate;
586 }
587 }
588
589terminate:
590 atomic_dec(&rnd->ref_cnt);
591}
592
593void graph_client_connection(ipc_call_t *icall, void *arg)
594{
595 /* Find the visualizer or renderer with the given service ID. */
596 visualizer_t *vs = graph_get_visualizer(IPC_GET_ARG2(*icall));
597 renderer_t *rnd = graph_get_renderer(IPC_GET_ARG2(*icall));
598
599 if (vs != NULL)
600 graph_visualizer_connection(vs, icall, arg);
601 else if (rnd != NULL)
602 graph_renderer_connection(rnd, icall, arg);
603 else
604 async_answer_0(icall, ENOENT);
605}
606
607/** @}
608 */
Note: See TracBrowser for help on using the repository browser.