source: mainline/uspace/lib/c/generic/loc.c@ 14b5c30f

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 14b5c30f was 01900b6, checked in by Martin Decky <martin@…>, 6 years ago

Use an optional output argument instead of errno to propagate the error

The use of errno is troublesome in all other than top-level library
functions since the value in errno might get overwritten by subsequent
inner calls on the error path (e.g. cleanup, deallocation, etc.). The
optional output argument makes it possible to explicitly ignore the
error code if it is not needed, but still to pass it reliably back to
the original caller.

This change affecs async_connect_me_to(),
async_connect_me_to_blocking(), async_connect_kbox(), service_connect(),
service_connect_blocking() and loader_connect().

  • Property mode set to 100644
File size: 19.9 KB
Line 
1/*
2 * Copyright (c) 2007 Josef Cejka
3 * Copyright (c) 2011 Jiri Svoboda
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include <str.h>
31#include <ipc/services.h>
32#include <ns.h>
33#include <ipc/loc.h>
34#include <loc.h>
35#include <fibril_synch.h>
36#include <async.h>
37#include <errno.h>
38#include <stdlib.h>
39#include <stdbool.h>
40
41static FIBRIL_MUTEX_INITIALIZE(loc_supp_block_mutex);
42static FIBRIL_MUTEX_INITIALIZE(loc_cons_block_mutex);
43
44static FIBRIL_MUTEX_INITIALIZE(loc_supplier_mutex);
45static FIBRIL_MUTEX_INITIALIZE(loc_consumer_mutex);
46
47static FIBRIL_MUTEX_INITIALIZE(loc_callback_mutex);
48static bool loc_callback_created = false;
49static loc_cat_change_cb_t cat_change_cb = NULL;
50static void *cat_change_arg = NULL;
51
52static async_sess_t *loc_supp_block_sess = NULL;
53static async_sess_t *loc_cons_block_sess = NULL;
54
55static async_sess_t *loc_supplier_sess = NULL;
56static async_sess_t *loc_consumer_sess = NULL;
57
58static void loc_cb_conn(ipc_call_t *icall, void *arg)
59{
60 while (true) {
61 ipc_call_t call;
62 async_get_call(&call);
63
64 if (!ipc_get_imethod(&call)) {
65 async_answer_0(&call, EOK);
66 return;
67 }
68
69 switch (ipc_get_imethod(&call)) {
70 case LOC_EVENT_CAT_CHANGE:
71 fibril_mutex_lock(&loc_callback_mutex);
72 loc_cat_change_cb_t cb_fun = cat_change_cb;
73 void *cb_arg = cat_change_arg;
74 fibril_mutex_unlock(&loc_callback_mutex);
75
76 async_answer_0(&call, EOK);
77
78 if (cb_fun != NULL)
79 (*cb_fun)(cb_arg);
80
81 break;
82 default:
83 async_answer_0(&call, ENOTSUP);
84 }
85 }
86}
87
88static void clone_session(fibril_mutex_t *mtx, async_sess_t *src,
89 async_sess_t **dst)
90{
91 fibril_mutex_lock(mtx);
92
93 if ((*dst == NULL) && (src != NULL))
94 *dst = src;
95
96 fibril_mutex_unlock(mtx);
97}
98
99/** Create callback
100 *
101 * Must be called with loc_callback_mutex locked.
102 *
103 * @return EOK on success.
104 *
105 */
106static errno_t loc_callback_create(void)
107{
108 if (!loc_callback_created) {
109 async_exch_t *exch =
110 loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
111
112 ipc_call_t answer;
113 aid_t req = async_send_0(exch, LOC_CALLBACK_CREATE, &answer);
114
115 port_id_t port;
116 errno_t rc = async_create_callback_port(exch, INTERFACE_LOC_CB, 0, 0,
117 loc_cb_conn, NULL, &port);
118
119 loc_exchange_end(exch);
120
121 if (rc != EOK)
122 return rc;
123
124 errno_t retval;
125 async_wait_for(req, &retval);
126 if (retval != EOK)
127 return retval;
128
129 loc_callback_created = true;
130 }
131
132 return EOK;
133}
134
135/** Start an async exchange on the loc session (blocking).
136 *
137 * @param iface Location service interface to choose
138 *
139 * @return New exchange.
140 *
141 */
142async_exch_t *loc_exchange_begin_blocking(iface_t iface)
143{
144 switch (iface) {
145 case INTERFACE_LOC_SUPPLIER:
146 fibril_mutex_lock(&loc_supp_block_mutex);
147
148 while (loc_supp_block_sess == NULL) {
149 clone_session(&loc_supplier_mutex, loc_supplier_sess,
150 &loc_supp_block_sess);
151
152 if (loc_supp_block_sess == NULL)
153 loc_supp_block_sess =
154 service_connect_blocking(SERVICE_LOC,
155 INTERFACE_LOC_SUPPLIER, 0, NULL);
156 }
157
158 fibril_mutex_unlock(&loc_supp_block_mutex);
159
160 clone_session(&loc_supplier_mutex, loc_supp_block_sess,
161 &loc_supplier_sess);
162
163 return async_exchange_begin(loc_supp_block_sess);
164 case INTERFACE_LOC_CONSUMER:
165 fibril_mutex_lock(&loc_cons_block_mutex);
166
167 while (loc_cons_block_sess == NULL) {
168 clone_session(&loc_consumer_mutex, loc_consumer_sess,
169 &loc_cons_block_sess);
170
171 if (loc_cons_block_sess == NULL)
172 loc_cons_block_sess =
173 service_connect_blocking(SERVICE_LOC,
174 INTERFACE_LOC_CONSUMER, 0, NULL);
175 }
176
177 fibril_mutex_unlock(&loc_cons_block_mutex);
178
179 clone_session(&loc_consumer_mutex, loc_cons_block_sess,
180 &loc_consumer_sess);
181
182 return async_exchange_begin(loc_cons_block_sess);
183 default:
184 return NULL;
185 }
186}
187
188/** Start an async exchange on the loc session.
189 *
190 * @param iface Location service interface to choose
191 *
192 * @return New exchange.
193 *
194 */
195async_exch_t *loc_exchange_begin(iface_t iface)
196{
197 switch (iface) {
198 case INTERFACE_LOC_SUPPLIER:
199 fibril_mutex_lock(&loc_supplier_mutex);
200
201 if (loc_supplier_sess == NULL)
202 loc_supplier_sess =
203 service_connect(SERVICE_LOC,
204 INTERFACE_LOC_SUPPLIER, 0, NULL);
205
206 fibril_mutex_unlock(&loc_supplier_mutex);
207
208 if (loc_supplier_sess == NULL)
209 return NULL;
210
211 return async_exchange_begin(loc_supplier_sess);
212 case INTERFACE_LOC_CONSUMER:
213 fibril_mutex_lock(&loc_consumer_mutex);
214
215 if (loc_consumer_sess == NULL)
216 loc_consumer_sess =
217 service_connect(SERVICE_LOC,
218 INTERFACE_LOC_CONSUMER, 0, NULL);
219
220 fibril_mutex_unlock(&loc_consumer_mutex);
221
222 if (loc_consumer_sess == NULL)
223 return NULL;
224
225 return async_exchange_begin(loc_consumer_sess);
226 default:
227 return NULL;
228 }
229}
230
231/** Finish an async exchange on the loc session.
232 *
233 * @param exch Exchange to be finished.
234 *
235 */
236void loc_exchange_end(async_exch_t *exch)
237{
238 async_exchange_end(exch);
239}
240
241/** Register new server with loc. */
242errno_t loc_server_register(const char *name)
243{
244 async_exch_t *exch = loc_exchange_begin_blocking(INTERFACE_LOC_SUPPLIER);
245
246 ipc_call_t answer;
247 aid_t req = async_send_2(exch, LOC_SERVER_REGISTER, 0, 0, &answer);
248 errno_t retval = async_data_write_start(exch, name, str_size(name));
249
250 if (retval != EOK) {
251 async_forget(req);
252 loc_exchange_end(exch);
253 return retval;
254 }
255
256 async_connect_to_me(exch, INTERFACE_ANY, 0, 0);
257
258 /*
259 * First wait for the answer and then end the exchange. The opposite
260 * order is generally wrong because it may lead to a deadlock under
261 * certain circumstances.
262 */
263 async_wait_for(req, &retval);
264 loc_exchange_end(exch);
265
266 return retval;
267}
268
269/** Register new service.
270 *
271 * @param fqsn Fully qualified service name
272 * @param[out] sid Service ID of new service
273 *
274 */
275errno_t loc_service_register(const char *fqsn, service_id_t *sid)
276{
277 async_exch_t *exch = loc_exchange_begin_blocking(INTERFACE_LOC_SUPPLIER);
278
279 ipc_call_t answer;
280 aid_t req = async_send_0(exch, LOC_SERVICE_REGISTER, &answer);
281 errno_t retval = async_data_write_start(exch, fqsn, str_size(fqsn));
282
283 if (retval != EOK) {
284 async_forget(req);
285 loc_exchange_end(exch);
286 return retval;
287 }
288
289 /*
290 * First wait for the answer and then end the exchange. The opposite
291 * order is generally wrong because it may lead to a deadlock under
292 * certain circumstances.
293 */
294 async_wait_for(req, &retval);
295 loc_exchange_end(exch);
296
297 if (retval != EOK) {
298 if (sid != NULL)
299 *sid = -1;
300
301 return retval;
302 }
303
304 if (sid != NULL)
305 *sid = (service_id_t) ipc_get_arg1(&answer);
306
307 return retval;
308}
309
310/** Unregister service.
311 *
312 * @param sid Service ID
313 */
314errno_t loc_service_unregister(service_id_t sid)
315{
316 async_exch_t *exch;
317 errno_t retval;
318
319 exch = loc_exchange_begin_blocking(INTERFACE_LOC_SUPPLIER);
320 retval = async_req_1_0(exch, LOC_SERVICE_UNREGISTER, sid);
321 loc_exchange_end(exch);
322
323 return (errno_t)retval;
324}
325
326errno_t loc_service_get_id(const char *fqdn, service_id_t *handle,
327 unsigned int flags)
328{
329 async_exch_t *exch;
330
331 if (flags & IPC_FLAG_BLOCKING)
332 exch = loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
333 else {
334 exch = loc_exchange_begin(INTERFACE_LOC_CONSUMER);
335 if (exch == NULL)
336 return errno;
337 }
338
339 ipc_call_t answer;
340 aid_t req = async_send_2(exch, LOC_SERVICE_GET_ID, flags, 0,
341 &answer);
342 errno_t retval = async_data_write_start(exch, fqdn, str_size(fqdn));
343
344 loc_exchange_end(exch);
345
346 if (retval != EOK) {
347 async_forget(req);
348 return retval;
349 }
350
351 async_wait_for(req, &retval);
352
353 if (retval != EOK) {
354 if (handle != NULL)
355 *handle = (service_id_t) -1;
356
357 return retval;
358 }
359
360 if (handle != NULL)
361 *handle = (service_id_t) ipc_get_arg1(&answer);
362
363 return retval;
364}
365
366/** Get object name.
367 *
368 * Provided ID of an object, return its name.
369 *
370 * @param method IPC method
371 * @param id Object ID
372 * @param name Place to store pointer to new string. Caller should
373 * free it using free().
374 * @return EOK on success or an error code
375 */
376static errno_t loc_get_name_internal(sysarg_t method, sysarg_t id, char **name)
377{
378 async_exch_t *exch;
379 char name_buf[LOC_NAME_MAXLEN + 1];
380 ipc_call_t dreply;
381 size_t act_size;
382 errno_t dretval;
383
384 *name = NULL;
385 exch = loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
386
387 ipc_call_t answer;
388 aid_t req = async_send_1(exch, method, id, &answer);
389 aid_t dreq = async_data_read(exch, name_buf, LOC_NAME_MAXLEN,
390 &dreply);
391 async_wait_for(dreq, &dretval);
392
393 loc_exchange_end(exch);
394
395 if (dretval != EOK) {
396 async_forget(req);
397 return dretval;
398 }
399
400 errno_t retval;
401 async_wait_for(req, &retval);
402
403 if (retval != EOK)
404 return retval;
405
406 act_size = ipc_get_arg2(&dreply);
407 assert(act_size <= LOC_NAME_MAXLEN);
408 name_buf[act_size] = '\0';
409
410 *name = str_dup(name_buf);
411 if (*name == NULL)
412 return ENOMEM;
413
414 return EOK;
415}
416
417/** Get category name.
418 *
419 * Provided ID of a service, return its name.
420 *
421 * @param cat_id Category ID
422 * @param name Place to store pointer to new string. Caller should
423 * free it using free().
424 * @return EOK on success or an error code
425 */
426errno_t loc_category_get_name(category_id_t cat_id, char **name)
427{
428 return loc_get_name_internal(LOC_CATEGORY_GET_NAME, cat_id, name);
429}
430
431/** Get service name.
432 *
433 * Provided ID of a service, return its name.
434 *
435 * @param svc_id Service ID
436 * @param name Place to store pointer to new string. Caller should
437 * free it using free().
438 * @return EOK on success or an error code
439 */
440errno_t loc_service_get_name(service_id_t svc_id, char **name)
441{
442 return loc_get_name_internal(LOC_SERVICE_GET_NAME, svc_id, name);
443}
444
445/** Get service server name.
446 *
447 * Provided ID of a service, return the name of its server.
448 *
449 * @param svc_id Service ID
450 * @param name Place to store pointer to new string. Caller should
451 * free it using free().
452 * @return EOK on success or an error code
453 */
454errno_t loc_service_get_server_name(service_id_t svc_id, char **name)
455{
456 return loc_get_name_internal(LOC_SERVICE_GET_SERVER_NAME, svc_id, name);
457}
458
459errno_t loc_namespace_get_id(const char *name, service_id_t *handle,
460 unsigned int flags)
461{
462 async_exch_t *exch;
463
464 if (flags & IPC_FLAG_BLOCKING)
465 exch = loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
466 else {
467 exch = loc_exchange_begin(INTERFACE_LOC_CONSUMER);
468 if (exch == NULL)
469 return errno;
470 }
471
472 ipc_call_t answer;
473 aid_t req = async_send_2(exch, LOC_NAMESPACE_GET_ID, flags, 0,
474 &answer);
475 errno_t retval = async_data_write_start(exch, name, str_size(name));
476
477 loc_exchange_end(exch);
478
479 if (retval != EOK) {
480 async_forget(req);
481 return retval;
482 }
483
484 async_wait_for(req, &retval);
485
486 if (retval != EOK) {
487 if (handle != NULL)
488 *handle = (service_id_t) -1;
489
490 return retval;
491 }
492
493 if (handle != NULL)
494 *handle = (service_id_t) ipc_get_arg1(&answer);
495
496 return retval;
497}
498
499/** Get category ID.
500 *
501 * Provided name of a category, return its ID.
502 *
503 * @param name Category name
504 * @param cat_id Place to store ID
505 * @param flags IPC_FLAG_BLOCKING to wait for location service to start
506 * @return EOK on success or an error code
507 */
508errno_t loc_category_get_id(const char *name, category_id_t *cat_id,
509 unsigned int flags)
510{
511 async_exch_t *exch;
512
513 if (flags & IPC_FLAG_BLOCKING)
514 exch = loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
515 else {
516 exch = loc_exchange_begin(INTERFACE_LOC_CONSUMER);
517 if (exch == NULL)
518 return errno;
519 }
520
521 ipc_call_t answer;
522 aid_t req = async_send_0(exch, LOC_CATEGORY_GET_ID,
523 &answer);
524 errno_t retval = async_data_write_start(exch, name, str_size(name));
525
526 loc_exchange_end(exch);
527
528 if (retval != EOK) {
529 async_forget(req);
530 return retval;
531 }
532
533 async_wait_for(req, &retval);
534
535 if (retval != EOK) {
536 if (cat_id != NULL)
537 *cat_id = (category_id_t) -1;
538
539 return retval;
540 }
541
542 if (cat_id != NULL)
543 *cat_id = (category_id_t) ipc_get_arg1(&answer);
544
545 return retval;
546}
547
548loc_object_type_t loc_id_probe(service_id_t handle)
549{
550 async_exch_t *exch = loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
551
552 sysarg_t type;
553 errno_t retval = async_req_1_1(exch, LOC_ID_PROBE, handle, &type);
554
555 loc_exchange_end(exch);
556
557 if (retval != EOK)
558 return LOC_OBJECT_NONE;
559
560 return (loc_object_type_t) type;
561}
562
563async_sess_t *loc_service_connect(service_id_t handle, iface_t iface,
564 unsigned int flags)
565{
566 async_sess_t *sess;
567
568 if (flags & IPC_FLAG_BLOCKING)
569 sess = service_connect_blocking(SERVICE_LOC, iface, handle, NULL);
570 else
571 sess = service_connect(SERVICE_LOC, iface, handle, NULL);
572
573 return sess;
574}
575
576/**
577 * @return ID of a new NULL device, or -1 if failed.
578 */
579int loc_null_create(void)
580{
581 async_exch_t *exch = loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
582
583 sysarg_t null_id;
584 errno_t retval = async_req_0_1(exch, LOC_NULL_CREATE, &null_id);
585
586 loc_exchange_end(exch);
587
588 if (retval != EOK)
589 return -1;
590
591 return (int) null_id;
592}
593
594void loc_null_destroy(int null_id)
595{
596 async_exch_t *exch = loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
597 async_req_1_0(exch, LOC_NULL_DESTROY, (sysarg_t) null_id);
598 loc_exchange_end(exch);
599}
600
601static size_t loc_count_namespaces_internal(async_exch_t *exch)
602{
603 sysarg_t count;
604 errno_t retval = async_req_0_1(exch, LOC_GET_NAMESPACE_COUNT, &count);
605 if (retval != EOK)
606 return 0;
607
608 return count;
609}
610
611/** Add service to category.
612 *
613 * @param svc_id Service ID
614 * @param cat_id Category ID
615 * @return EOK on success or an error code
616 */
617errno_t loc_service_add_to_cat(service_id_t svc_id, service_id_t cat_id)
618{
619 async_exch_t *exch;
620 errno_t retval;
621
622 exch = loc_exchange_begin_blocking(INTERFACE_LOC_SUPPLIER);
623 retval = async_req_2_0(exch, LOC_SERVICE_ADD_TO_CAT, svc_id, cat_id);
624 loc_exchange_end(exch);
625
626 return retval;
627}
628
629static size_t loc_count_services_internal(async_exch_t *exch,
630 service_id_t ns_handle)
631{
632 sysarg_t count;
633 errno_t retval = async_req_1_1(exch, LOC_GET_SERVICE_COUNT, ns_handle,
634 &count);
635 if (retval != EOK)
636 return 0;
637
638 return count;
639}
640
641size_t loc_count_namespaces(void)
642{
643 async_exch_t *exch = loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
644 size_t size = loc_count_namespaces_internal(exch);
645 loc_exchange_end(exch);
646
647 return size;
648}
649
650size_t loc_count_services(service_id_t ns_handle)
651{
652 async_exch_t *exch = loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
653 size_t size = loc_count_services_internal(exch, ns_handle);
654 loc_exchange_end(exch);
655
656 return size;
657}
658
659size_t loc_get_namespaces(loc_sdesc_t **data)
660{
661 /* Loop until read is succesful */
662 while (true) {
663 async_exch_t *exch = loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
664 size_t count = loc_count_namespaces_internal(exch);
665 loc_exchange_end(exch);
666
667 if (count == 0)
668 return 0;
669
670 loc_sdesc_t *devs = (loc_sdesc_t *) calloc(count, sizeof(loc_sdesc_t));
671 if (devs == NULL)
672 return 0;
673
674 exch = loc_exchange_begin(INTERFACE_LOC_CONSUMER);
675
676 ipc_call_t answer;
677 aid_t req = async_send_0(exch, LOC_GET_NAMESPACES, &answer);
678 errno_t rc = async_data_read_start(exch, devs, count * sizeof(loc_sdesc_t));
679
680 loc_exchange_end(exch);
681
682 if (rc == EOVERFLOW) {
683 /*
684 * Number of namespaces has changed since
685 * the last call of LOC_GET_NAMESPACE_COUNT
686 */
687 free(devs);
688 continue;
689 }
690
691 if (rc != EOK) {
692 async_forget(req);
693 free(devs);
694 return 0;
695 }
696
697 errno_t retval;
698 async_wait_for(req, &retval);
699
700 if (retval != EOK)
701 return 0;
702
703 *data = devs;
704 return count;
705 }
706}
707
708size_t loc_get_services(service_id_t ns_handle, loc_sdesc_t **data)
709{
710 /* Loop until read is succesful */
711 while (true) {
712 async_exch_t *exch = loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
713 size_t count = loc_count_services_internal(exch, ns_handle);
714 loc_exchange_end(exch);
715
716 if (count == 0)
717 return 0;
718
719 loc_sdesc_t *devs = (loc_sdesc_t *) calloc(count, sizeof(loc_sdesc_t));
720 if (devs == NULL)
721 return 0;
722
723 exch = loc_exchange_begin(INTERFACE_LOC_CONSUMER);
724
725 ipc_call_t answer;
726 aid_t req = async_send_1(exch, LOC_GET_SERVICES, ns_handle, &answer);
727 errno_t rc = async_data_read_start(exch, devs, count * sizeof(loc_sdesc_t));
728
729 loc_exchange_end(exch);
730
731 if (rc == EOVERFLOW) {
732 /*
733 * Number of services has changed since
734 * the last call of LOC_GET_SERVICE_COUNT
735 */
736 free(devs);
737 continue;
738 }
739
740 if (rc != EOK) {
741 async_forget(req);
742 free(devs);
743 return 0;
744 }
745
746 errno_t retval;
747 async_wait_for(req, &retval);
748
749 if (retval != EOK)
750 return 0;
751
752 *data = devs;
753 return count;
754 }
755}
756
757static errno_t loc_category_get_ids_once(sysarg_t method, sysarg_t arg1,
758 sysarg_t *id_buf, size_t buf_size, size_t *act_size)
759{
760 async_exch_t *exch = loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
761
762 ipc_call_t answer;
763 aid_t req = async_send_1(exch, method, arg1, &answer);
764 errno_t rc = async_data_read_start(exch, id_buf, buf_size);
765
766 loc_exchange_end(exch);
767
768 if (rc != EOK) {
769 async_forget(req);
770 return rc;
771 }
772
773 errno_t retval;
774 async_wait_for(req, &retval);
775
776 if (retval != EOK) {
777 return retval;
778 }
779
780 *act_size = ipc_get_arg1(&answer);
781 return EOK;
782}
783
784/** Get list of IDs.
785 *
786 * Returns an allocated array of service IDs.
787 *
788 * @param method IPC method
789 * @param arg1 IPC argument 1
790 * @param data Place to store pointer to array of IDs
791 * @param count Place to store number of IDs
792 * @return EOK on success or an error code
793 */
794static errno_t loc_get_ids_internal(sysarg_t method, sysarg_t arg1,
795 sysarg_t **data, size_t *count)
796{
797 *data = NULL;
798 *count = 0;
799
800 size_t act_size = 0;
801 errno_t rc = loc_category_get_ids_once(method, arg1, NULL, 0,
802 &act_size);
803 if (rc != EOK)
804 return rc;
805
806 size_t alloc_size = act_size;
807 service_id_t *ids = malloc(alloc_size);
808 if (ids == NULL)
809 return ENOMEM;
810
811 while (true) {
812 rc = loc_category_get_ids_once(method, arg1, ids, alloc_size,
813 &act_size);
814 if (rc != EOK)
815 return rc;
816
817 if (act_size <= alloc_size)
818 break;
819
820 alloc_size = act_size;
821 ids = realloc(ids, alloc_size);
822 if (ids == NULL)
823 return ENOMEM;
824 }
825
826 *count = act_size / sizeof(category_id_t);
827 *data = ids;
828 return EOK;
829}
830
831/** Get list of services in category.
832 *
833 * Returns an allocated array of service IDs.
834 *
835 * @param cat_id Category ID
836 * @param data Place to store pointer to array of IDs
837 * @param count Place to store number of IDs
838 * @return EOK on success or an error code
839 */
840errno_t loc_category_get_svcs(category_id_t cat_id, service_id_t **data,
841 size_t *count)
842{
843 return loc_get_ids_internal(LOC_CATEGORY_GET_SVCS, cat_id,
844 data, count);
845}
846
847/** Get list of categories.
848 *
849 * Returns an allocated array of category IDs.
850 *
851 * @param data Place to store pointer to array of IDs
852 * @param count Place to store number of IDs
853 * @return EOK on success or an error code
854 */
855errno_t loc_get_categories(category_id_t **data, size_t *count)
856{
857 return loc_get_ids_internal(LOC_GET_CATEGORIES, 0,
858 data, count);
859}
860
861errno_t loc_register_cat_change_cb(loc_cat_change_cb_t cb_fun, void *cb_arg)
862{
863 fibril_mutex_lock(&loc_callback_mutex);
864 if (cat_change_cb != NULL) {
865 fibril_mutex_unlock(&loc_callback_mutex);
866 return EEXIST;
867 }
868
869 if (loc_callback_create() != EOK) {
870 fibril_mutex_unlock(&loc_callback_mutex);
871 return EIO;
872 }
873
874 cat_change_cb = cb_fun;
875 cat_change_arg = cb_arg;
876 fibril_mutex_unlock(&loc_callback_mutex);
877
878 return EOK;
879}
Note: See TracBrowser for help on using the repository browser.