source: mainline/uspace/lib/c/generic/loc.c@ d4a829e

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since d4a829e was 38d150e, checked in by Jiri Svoboda <jiri@…>, 8 years ago

Prefer to get memory allocation functions through the standard stdlib header.

  • Property mode set to 100644
File size: 19.8 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 sysarg_t 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 sysarg_t 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 sysarg_t 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 sysarg_t 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 sysarg_t 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 sysarg_t 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 sysarg_t 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 sysarg_t 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 sysarg_t 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 sysarg_t 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 sysarg_t 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 sysarg_t 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 sysarg_t 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.