source: mainline/uspace/lib/c/generic/loc.c@ 514d561

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

ns: register service interfaces individually

Each service interface is now registered individually with the naming
service. This adds a degree of type safety, potentially allows the
individual interfaces to be implemented by independent tasks and moves
the code slightly closer to the full-fledged ports design.

Broker services (e.g. the location service) can still register a
fallback port for receiving connections to all interface types
explicitly using service_register_broker().

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