source: mainline/uspace/lib/c/generic/loc.c@ 649f087

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

Work on device removal:

  • properly track service memberships in categories
  • implement loc_service_unregister()
  • ddf_fun_unbind() (limited to exposed functions for now)
  • 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 <malloc.h>
39#include <bool.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;
49
50static async_sess_t *loc_supp_block_sess = NULL;
51static async_sess_t *loc_cons_block_sess = NULL;
52
53static async_sess_t *loc_supplier_sess = NULL;
54static async_sess_t *loc_consumer_sess = NULL;
55
56static loc_cat_change_cb_t cat_change_cb = NULL;
57
58static void loc_cb_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg)
59{
60 loc_cat_change_cb_t cb_fun;
61
62 while (true) {
63 ipc_call_t call;
64 ipc_callid_t callid = async_get_call(&call);
65
66 if (!IPC_GET_IMETHOD(call)) {
67 /* TODO: Handle hangup */
68 return;
69 }
70
71 int retval;
72
73 switch (IPC_GET_IMETHOD(call)) {
74 case LOC_EVENT_CAT_CHANGE:
75 fibril_mutex_lock(&loc_callback_mutex);
76 cb_fun = cat_change_cb;
77 if (cb_fun != NULL) {
78 (*cb_fun)();
79 }
80 fibril_mutex_unlock(&loc_callback_mutex);
81 retval = 0;
82 break;
83 default:
84 retval = ENOTSUP;
85 }
86
87 async_answer_0(callid, retval);
88 }
89}
90
91
92static void clone_session(fibril_mutex_t *mtx, async_sess_t *src,
93 async_sess_t **dst)
94{
95 fibril_mutex_lock(mtx);
96
97 if ((*dst == NULL) && (src != NULL))
98 *dst = src;
99
100 fibril_mutex_unlock(mtx);
101}
102
103static int loc_callback_create(void)
104{
105 async_exch_t *exch;
106 sysarg_t retval;
107 int rc = EOK;
108
109 fibril_mutex_lock(&loc_callback_mutex);
110
111 if (!loc_callback_created) {
112 exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
113
114 ipc_call_t answer;
115 aid_t req = async_send_0(exch, LOC_CALLBACK_CREATE, &answer);
116 async_connect_to_me(exch, 0, 0, 0, loc_cb_conn, NULL);
117 loc_exchange_end(exch);
118
119 async_wait_for(req, &retval);
120 if (rc != EOK)
121 goto done;
122
123 if (retval != EOK) {
124 rc = retval;
125 goto done;
126 }
127
128 loc_callback_created = true;
129 }
130
131 rc = EOK;
132done:
133 fibril_mutex_unlock(&loc_callback_mutex);
134 return rc;
135}
136
137/** Start an async exchange on the loc session (blocking).
138 *
139 * @param iface Location service interface to choose
140 *
141 * @return New exchange.
142 *
143 */
144async_exch_t *loc_exchange_begin_blocking(loc_interface_t iface)
145{
146 switch (iface) {
147 case LOC_PORT_SUPPLIER:
148 fibril_mutex_lock(&loc_supp_block_mutex);
149
150 while (loc_supp_block_sess == NULL) {
151 clone_session(&loc_supplier_mutex, loc_supplier_sess,
152 &loc_supp_block_sess);
153
154 if (loc_supp_block_sess == NULL)
155 loc_supp_block_sess =
156 service_connect_blocking(EXCHANGE_SERIALIZE,
157 SERVICE_LOC, LOC_PORT_SUPPLIER, 0);
158 }
159
160 fibril_mutex_unlock(&loc_supp_block_mutex);
161
162 clone_session(&loc_supplier_mutex, loc_supp_block_sess,
163 &loc_supplier_sess);
164
165 return async_exchange_begin(loc_supp_block_sess);
166 case LOC_PORT_CONSUMER:
167 fibril_mutex_lock(&loc_cons_block_mutex);
168
169 while (loc_cons_block_sess == NULL) {
170 clone_session(&loc_consumer_mutex, loc_consumer_sess,
171 &loc_cons_block_sess);
172
173 if (loc_cons_block_sess == NULL)
174 loc_cons_block_sess =
175 service_connect_blocking(EXCHANGE_SERIALIZE,
176 SERVICE_LOC, LOC_PORT_CONSUMER, 0);
177 }
178
179 fibril_mutex_unlock(&loc_cons_block_mutex);
180
181 clone_session(&loc_consumer_mutex, loc_cons_block_sess,
182 &loc_consumer_sess);
183
184 return async_exchange_begin(loc_cons_block_sess);
185 default:
186 return NULL;
187 }
188}
189
190/** Start an async exchange on the loc session.
191 *
192 * @param iface Location service interface to choose
193 *
194 * @return New exchange.
195 *
196 */
197async_exch_t *loc_exchange_begin(loc_interface_t iface)
198{
199 switch (iface) {
200 case LOC_PORT_SUPPLIER:
201 fibril_mutex_lock(&loc_supplier_mutex);
202
203 if (loc_supplier_sess == NULL)
204 loc_supplier_sess =
205 service_connect(EXCHANGE_SERIALIZE, SERVICE_LOC,
206 LOC_PORT_SUPPLIER, 0);
207
208 fibril_mutex_unlock(&loc_supplier_mutex);
209
210 if (loc_supplier_sess == NULL)
211 return NULL;
212
213 return async_exchange_begin(loc_supplier_sess);
214 case LOC_PORT_CONSUMER:
215 fibril_mutex_lock(&loc_consumer_mutex);
216
217 if (loc_consumer_sess == NULL)
218 loc_consumer_sess =
219 service_connect(EXCHANGE_SERIALIZE, SERVICE_LOC,
220 LOC_PORT_CONSUMER, 0);
221
222 fibril_mutex_unlock(&loc_consumer_mutex);
223
224 if (loc_consumer_sess == NULL)
225 return NULL;
226
227 return async_exchange_begin(loc_consumer_sess);
228 default:
229 return NULL;
230 }
231}
232
233/** Finish an async exchange on the loc session.
234 *
235 * @param exch Exchange to be finished.
236 *
237 */
238void loc_exchange_end(async_exch_t *exch)
239{
240 async_exchange_end(exch);
241}
242
243/** Register new driver with loc. */
244int loc_server_register(const char *name, async_client_conn_t conn)
245{
246 async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_SUPPLIER);
247
248 ipc_call_t answer;
249 aid_t req = async_send_2(exch, LOC_SERVER_REGISTER, 0, 0, &answer);
250 sysarg_t retval = async_data_write_start(exch, name, str_size(name));
251
252 loc_exchange_end(exch);
253
254 if (retval != EOK) {
255 async_wait_for(req, NULL);
256 return retval;
257 }
258
259 async_set_client_connection(conn);
260
261 exch = loc_exchange_begin(LOC_PORT_SUPPLIER);
262 async_connect_to_me(exch, 0, 0, 0, NULL, NULL);
263 loc_exchange_end(exch);
264
265 async_wait_for(req, &retval);
266 return retval;
267}
268
269/** Register new service.
270 *
271 * The @p interface is used when forwarding connection to the server.
272 * If not 0, the first argument is the interface and the second argument
273 * is the service ID.
274 *
275 * When the interface is zero (default), the first argument is directly
276 * the handle (to ensure backward compatibility).
277 *
278 * @param fqsn Fully qualified service name
279 * @param[out] sid Service ID of new service
280 * @param interface Interface when forwarding
281 *
282 */
283int loc_service_register_with_iface(const char *fqsn,
284 service_id_t *sid, sysarg_t interface)
285{
286 async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_SUPPLIER);
287
288 ipc_call_t answer;
289 aid_t req = async_send_2(exch, LOC_SERVICE_REGISTER, interface, 0,
290 &answer);
291 sysarg_t retval = async_data_write_start(exch, fqsn, str_size(fqsn));
292
293 loc_exchange_end(exch);
294
295 if (retval != EOK) {
296 async_wait_for(req, NULL);
297 return retval;
298 }
299
300 async_wait_for(req, &retval);
301
302 if (retval != EOK) {
303 if (sid != NULL)
304 *sid = -1;
305
306 return retval;
307 }
308
309 if (sid != NULL)
310 *sid = (service_id_t) IPC_GET_ARG1(answer);
311
312 return retval;
313}
314
315/** Register new service.
316 *
317 * @param fqsn Fully qualified service name
318 * @param sid Output: ID of new service
319 *
320 */
321int loc_service_register(const char *fqdn, service_id_t *sid)
322{
323 return loc_service_register_with_iface(fqdn, sid, 0);
324}
325
326/** Unregister service.
327 *
328 * @param sid Service ID
329 */
330int loc_service_unregister(service_id_t sid)
331{
332 async_exch_t *exch;
333 sysarg_t retval;
334
335 exch = loc_exchange_begin_blocking(LOC_PORT_SUPPLIER);
336 retval = async_req_1_0(exch, LOC_SERVICE_UNREGISTER, sid);
337 loc_exchange_end(exch);
338
339 return (int)retval;
340}
341
342int loc_service_get_id(const char *fqdn, service_id_t *handle,
343 unsigned int flags)
344{
345 async_exch_t *exch;
346
347 if (flags & IPC_FLAG_BLOCKING)
348 exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
349 else {
350 exch = loc_exchange_begin(LOC_PORT_CONSUMER);
351 if (exch == NULL)
352 return errno;
353 }
354
355 ipc_call_t answer;
356 aid_t req = async_send_2(exch, LOC_SERVICE_GET_ID, flags, 0,
357 &answer);
358 sysarg_t retval = async_data_write_start(exch, fqdn, str_size(fqdn));
359
360 loc_exchange_end(exch);
361
362 if (retval != EOK) {
363 async_wait_for(req, NULL);
364 return retval;
365 }
366
367 async_wait_for(req, &retval);
368
369 if (retval != EOK) {
370 if (handle != NULL)
371 *handle = (service_id_t) -1;
372
373 return retval;
374 }
375
376 if (handle != NULL)
377 *handle = (service_id_t) IPC_GET_ARG1(answer);
378
379 return retval;
380}
381
382/** Get object name.
383 *
384 * Provided ID of an object, return its name.
385 *
386 * @param method IPC method
387 * @param id Object ID
388 * @param name Place to store pointer to new string. Caller should
389 * free it using free().
390 * @return EOK on success or negative error code
391 */
392static int loc_get_name_internal(sysarg_t method, sysarg_t id, char **name)
393{
394 async_exch_t *exch;
395 char name_buf[LOC_NAME_MAXLEN + 1];
396 ipc_call_t dreply;
397 size_t act_size;
398 sysarg_t dretval;
399
400 *name = NULL;
401 exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
402
403 ipc_call_t answer;
404 aid_t req = async_send_1(exch, method, id, &answer);
405 aid_t dreq = async_data_read(exch, name_buf, LOC_NAME_MAXLEN,
406 &dreply);
407 async_wait_for(dreq, &dretval);
408
409 loc_exchange_end(exch);
410
411 if (dretval != EOK) {
412 async_wait_for(req, NULL);
413 return dretval;
414 }
415
416 sysarg_t retval;
417 async_wait_for(req, &retval);
418
419 if (retval != EOK)
420 return retval;
421
422 act_size = IPC_GET_ARG2(dreply);
423 assert(act_size <= LOC_NAME_MAXLEN);
424 name_buf[act_size] = '\0';
425
426 *name = str_dup(name_buf);
427 if (*name == NULL)
428 return ENOMEM;
429
430 return EOK;
431}
432
433/** Get category name.
434 *
435 * Provided ID of a service, return its name.
436 *
437 * @param cat_id Category ID
438 * @param name Place to store pointer to new string. Caller should
439 * free it using free().
440 * @return EOK on success or negative error code
441 */
442int loc_category_get_name(category_id_t cat_id, char **name)
443{
444 return loc_get_name_internal(LOC_CATEGORY_GET_NAME, cat_id, name);
445}
446
447/** Get service name.
448 *
449 * Provided ID of a service, return its name.
450 *
451 * @param svc_id Service ID
452 * @param name Place to store pointer to new string. Caller should
453 * free it using free().
454 * @return EOK on success or negative error code
455 */
456int loc_service_get_name(service_id_t svc_id, char **name)
457{
458 return loc_get_name_internal(LOC_SERVICE_GET_NAME, svc_id, name);
459}
460
461int loc_namespace_get_id(const char *name, service_id_t *handle,
462 unsigned int flags)
463{
464 async_exch_t *exch;
465
466 if (flags & IPC_FLAG_BLOCKING)
467 exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
468 else {
469 exch = loc_exchange_begin(LOC_PORT_CONSUMER);
470 if (exch == NULL)
471 return errno;
472 }
473
474 ipc_call_t answer;
475 aid_t req = async_send_2(exch, LOC_NAMESPACE_GET_ID, flags, 0,
476 &answer);
477 sysarg_t retval = async_data_write_start(exch, name, str_size(name));
478
479 loc_exchange_end(exch);
480
481 if (retval != EOK) {
482 async_wait_for(req, NULL);
483 return retval;
484 }
485
486 async_wait_for(req, &retval);
487
488 if (retval != EOK) {
489 if (handle != NULL)
490 *handle = (service_id_t) -1;
491
492 return retval;
493 }
494
495 if (handle != NULL)
496 *handle = (service_id_t) IPC_GET_ARG1(answer);
497
498 return retval;
499}
500
501/** Get category ID.
502 *
503 * Provided name of a category, return its ID.
504 *
505 * @param name Category name
506 * @param cat_id Place to store ID
507 * @param flags IPC_FLAG_BLOCKING to wait for location service to start
508 * @return EOK on success or negative error code
509 */
510int loc_category_get_id(const char *name, category_id_t *cat_id,
511 unsigned int flags)
512{
513 async_exch_t *exch;
514
515 if (flags & IPC_FLAG_BLOCKING)
516 exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
517 else {
518 exch = loc_exchange_begin(LOC_PORT_CONSUMER);
519 if (exch == NULL)
520 return errno;
521 }
522
523 ipc_call_t answer;
524 aid_t req = async_send_0(exch, LOC_CATEGORY_GET_ID,
525 &answer);
526 sysarg_t retval = async_data_write_start(exch, name, str_size(name));
527
528 loc_exchange_end(exch);
529
530 if (retval != EOK) {
531 async_wait_for(req, NULL);
532 return retval;
533 }
534
535 async_wait_for(req, &retval);
536
537 if (retval != EOK) {
538 if (cat_id != NULL)
539 *cat_id = (category_id_t) -1;
540
541 return retval;
542 }
543
544 if (cat_id != NULL)
545 *cat_id = (category_id_t) IPC_GET_ARG1(answer);
546
547 return retval;
548}
549
550
551loc_object_type_t loc_id_probe(service_id_t handle)
552{
553 async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
554
555 sysarg_t type;
556 int retval = async_req_1_1(exch, LOC_ID_PROBE, handle, &type);
557
558 loc_exchange_end(exch);
559
560 if (retval != EOK)
561 return LOC_OBJECT_NONE;
562
563 return (loc_object_type_t) type;
564}
565
566async_sess_t *loc_service_connect(exch_mgmt_t mgmt, service_id_t handle,
567 unsigned int flags)
568{
569 async_sess_t *sess;
570
571 if (flags & IPC_FLAG_BLOCKING)
572 sess = service_connect_blocking(mgmt, SERVICE_LOC,
573 LOC_CONNECT_TO_SERVICE, handle);
574 else
575 sess = service_connect(mgmt, SERVICE_LOC,
576 LOC_CONNECT_TO_SERVICE, handle);
577
578 return sess;
579}
580
581int loc_null_create(void)
582{
583 async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
584
585 sysarg_t null_id;
586 int 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(LOC_PORT_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 int 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 negative error code
618 */
619int loc_service_add_to_cat(service_id_t svc_id, service_id_t cat_id)
620{
621 async_exch_t *exch;
622 sysarg_t retval;
623
624 exch = loc_exchange_begin_blocking(LOC_PORT_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 int 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(LOC_PORT_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(LOC_PORT_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(LOC_PORT_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(LOC_PORT_CONSUMER);
677
678 ipc_call_t answer;
679 aid_t req = async_send_0(exch, LOC_GET_NAMESPACES, &answer);
680 int 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_wait_for(req, NULL);
695 free(devs);
696 return 0;
697 }
698
699 sysarg_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(LOC_PORT_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(LOC_PORT_CONSUMER);
726
727 ipc_call_t answer;
728 aid_t req = async_send_1(exch, LOC_GET_SERVICES, ns_handle, &answer);
729 int 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_wait_for(req, NULL);
744 free(devs);
745 return 0;
746 }
747
748 sysarg_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 int 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(LOC_PORT_CONSUMER);
763
764 ipc_call_t answer;
765 aid_t req = async_send_1(exch, method, arg1, &answer);
766 int rc = async_data_read_start(exch, id_buf, buf_size);
767
768 loc_exchange_end(exch);
769
770 if (rc != EOK) {
771 async_wait_for(req, NULL);
772 return rc;
773 }
774
775 sysarg_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 negative error code
795 */
796static int loc_get_ids_internal(sysarg_t method, sysarg_t arg1,
797 sysarg_t **data, size_t *count)
798{
799 service_id_t *ids;
800 size_t act_size;
801 size_t alloc_size;
802 int rc;
803
804 *data = NULL;
805 act_size = 0; /* silence warning */
806
807 rc = loc_category_get_ids_once(method, arg1, NULL, 0,
808 &act_size);
809 if (rc != EOK)
810 return rc;
811
812 alloc_size = act_size;
813 ids = malloc(alloc_size);
814 if (ids == NULL)
815 return ENOMEM;
816
817 while (true) {
818 rc = loc_category_get_ids_once(method, arg1, ids, alloc_size,
819 &act_size);
820 if (rc != EOK)
821 return rc;
822
823 if (act_size <= alloc_size)
824 break;
825
826 alloc_size *= 2;
827 free(ids);
828
829 ids = malloc(alloc_size);
830 if (ids == NULL)
831 return ENOMEM;
832 }
833
834 *count = act_size / sizeof(category_id_t);
835 *data = ids;
836 return EOK;
837}
838
839/** Get list of services in category.
840 *
841 * Returns an allocated array of service IDs.
842 *
843 * @param cat_id Category ID
844 * @param data Place to store pointer to array of IDs
845 * @param count Place to store number of IDs
846 * @return EOK on success or negative error code
847 */
848int loc_category_get_svcs(category_id_t cat_id, service_id_t **data,
849 size_t *count)
850{
851 return loc_get_ids_internal(LOC_CATEGORY_GET_SVCS, cat_id,
852 data, count);
853}
854
855/** Get list of categories.
856 *
857 * Returns an allocated array of category IDs.
858 *
859 * @param data Place to store pointer to array of IDs
860 * @param count Place to store number of IDs
861 * @return EOK on success or negative error code
862 */
863int loc_get_categories(category_id_t **data, size_t *count)
864{
865 return loc_get_ids_internal(LOC_GET_CATEGORIES, 0,
866 data, count);
867}
868
869int loc_register_cat_change_cb(loc_cat_change_cb_t cb_fun)
870{
871 if (loc_callback_create() != EOK)
872 return EIO;
873
874 cat_change_cb = cb_fun;
875 return EOK;
876}
Note: See TracBrowser for help on using the repository browser.