source: mainline/uspace/lib/c/generic/loc.c@ 153dd3b

ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 153dd3b was 7d7f5e3, checked in by Jiri Svoboda <jiri@…>, 22 months ago

loc_server_register() should be callable more than once (implementation)

We create a new session for each loc_server_register() / loc_srv_t
object. Alternatively we could multiplex all to a single connection
and then demultiplex them in the server, but this seemed simpler
at the moment.

We add a test case to libc test suite.

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