source: mainline/uspace/lib/c/generic/loc.c@ 0dd16778

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

start migrating devman to interfaces

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