source: mainline/uspace/lib/c/generic/loc.c@ 25a179e

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 25a179e was 25a179e, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 8 years ago

IPC return values are always errno constants. Adjust types to reflect that.

In principle, IPC server is not allowed to return non-errno values via
the "main" return value, because kernel interprets it (e.g. EHANGUP).
It's still possible to return arbitrary additional return values alongside EOK,
which are not interpreted in normal communication.

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