source: mainline/uspace/lib/c/generic/loc.c@ 6aae539d

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 6aae539d was 50b581d, checked in by Jakub Jermar <jakub@…>, 13 years ago

Replace the async_wait_for(msg, NULL) pattern in the error paths with
async_forget(msg).

  • Property mode set to 100644
File size: 19.6 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;
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(EXCHANGE_SERIALIZE,
150 SERVICE_LOC, LOC_PORT_SUPPLIER, 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(EXCHANGE_SERIALIZE,
169 SERVICE_LOC, LOC_PORT_CONSUMER, 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(EXCHANGE_SERIALIZE, SERVICE_LOC,
199 LOC_PORT_SUPPLIER, 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(EXCHANGE_SERIALIZE, SERVICE_LOC,
213 LOC_PORT_CONSUMER, 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
452int loc_namespace_get_id(const char *name, service_id_t *handle,
453 unsigned int flags)
454{
455 async_exch_t *exch;
456
457 if (flags & IPC_FLAG_BLOCKING)
458 exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
459 else {
460 exch = loc_exchange_begin(LOC_PORT_CONSUMER);
461 if (exch == NULL)
462 return errno;
463 }
464
465 ipc_call_t answer;
466 aid_t req = async_send_2(exch, LOC_NAMESPACE_GET_ID, flags, 0,
467 &answer);
468 sysarg_t retval = async_data_write_start(exch, name, str_size(name));
469
470 loc_exchange_end(exch);
471
472 if (retval != EOK) {
473 async_forget(req);
474 return retval;
475 }
476
477 async_wait_for(req, &retval);
478
479 if (retval != EOK) {
480 if (handle != NULL)
481 *handle = (service_id_t) -1;
482
483 return retval;
484 }
485
486 if (handle != NULL)
487 *handle = (service_id_t) IPC_GET_ARG1(answer);
488
489 return retval;
490}
491
492/** Get category ID.
493 *
494 * Provided name of a category, return its ID.
495 *
496 * @param name Category name
497 * @param cat_id Place to store ID
498 * @param flags IPC_FLAG_BLOCKING to wait for location service to start
499 * @return EOK on success or negative error code
500 */
501int loc_category_get_id(const char *name, category_id_t *cat_id,
502 unsigned int flags)
503{
504 async_exch_t *exch;
505
506 if (flags & IPC_FLAG_BLOCKING)
507 exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
508 else {
509 exch = loc_exchange_begin(LOC_PORT_CONSUMER);
510 if (exch == NULL)
511 return errno;
512 }
513
514 ipc_call_t answer;
515 aid_t req = async_send_0(exch, LOC_CATEGORY_GET_ID,
516 &answer);
517 sysarg_t retval = async_data_write_start(exch, name, str_size(name));
518
519 loc_exchange_end(exch);
520
521 if (retval != EOK) {
522 async_forget(req);
523 return retval;
524 }
525
526 async_wait_for(req, &retval);
527
528 if (retval != EOK) {
529 if (cat_id != NULL)
530 *cat_id = (category_id_t) -1;
531
532 return retval;
533 }
534
535 if (cat_id != NULL)
536 *cat_id = (category_id_t) IPC_GET_ARG1(answer);
537
538 return retval;
539}
540
541
542loc_object_type_t loc_id_probe(service_id_t handle)
543{
544 async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
545
546 sysarg_t type;
547 int retval = async_req_1_1(exch, LOC_ID_PROBE, handle, &type);
548
549 loc_exchange_end(exch);
550
551 if (retval != EOK)
552 return LOC_OBJECT_NONE;
553
554 return (loc_object_type_t) type;
555}
556
557async_sess_t *loc_service_connect(exch_mgmt_t mgmt, service_id_t handle,
558 unsigned int flags)
559{
560 async_sess_t *sess;
561
562 if (flags & IPC_FLAG_BLOCKING)
563 sess = service_connect_blocking(mgmt, SERVICE_LOC,
564 LOC_CONNECT_TO_SERVICE, handle);
565 else
566 sess = service_connect(mgmt, SERVICE_LOC,
567 LOC_CONNECT_TO_SERVICE, handle);
568
569 return sess;
570}
571
572int loc_null_create(void)
573{
574 async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
575
576 sysarg_t null_id;
577 int retval = async_req_0_1(exch, LOC_NULL_CREATE, &null_id);
578
579 loc_exchange_end(exch);
580
581 if (retval != EOK)
582 return -1;
583
584 return (int) null_id;
585}
586
587void loc_null_destroy(int null_id)
588{
589 async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
590 async_req_1_0(exch, LOC_NULL_DESTROY, (sysarg_t) null_id);
591 loc_exchange_end(exch);
592}
593
594static size_t loc_count_namespaces_internal(async_exch_t *exch)
595{
596 sysarg_t count;
597 int retval = async_req_0_1(exch, LOC_GET_NAMESPACE_COUNT, &count);
598 if (retval != EOK)
599 return 0;
600
601 return count;
602}
603
604/** Add service to category.
605 *
606 * @param svc_id Service ID
607 * @param cat_id Category ID
608 * @return EOK on success or negative error code
609 */
610int loc_service_add_to_cat(service_id_t svc_id, service_id_t cat_id)
611{
612 async_exch_t *exch;
613 sysarg_t retval;
614
615 exch = loc_exchange_begin_blocking(LOC_PORT_SUPPLIER);
616 retval = async_req_2_0(exch, LOC_SERVICE_ADD_TO_CAT, svc_id, cat_id);
617 loc_exchange_end(exch);
618
619 return retval;
620}
621
622static size_t loc_count_services_internal(async_exch_t *exch,
623 service_id_t ns_handle)
624{
625 sysarg_t count;
626 int retval = async_req_1_1(exch, LOC_GET_SERVICE_COUNT, ns_handle,
627 &count);
628 if (retval != EOK)
629 return 0;
630
631 return count;
632}
633
634size_t loc_count_namespaces(void)
635{
636 async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
637 size_t size = loc_count_namespaces_internal(exch);
638 loc_exchange_end(exch);
639
640 return size;
641}
642
643size_t loc_count_services(service_id_t ns_handle)
644{
645 async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
646 size_t size = loc_count_services_internal(exch, ns_handle);
647 loc_exchange_end(exch);
648
649 return size;
650}
651
652size_t loc_get_namespaces(loc_sdesc_t **data)
653{
654 /* Loop until read is succesful */
655 while (true) {
656 async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
657 size_t count = loc_count_namespaces_internal(exch);
658 loc_exchange_end(exch);
659
660 if (count == 0)
661 return 0;
662
663 loc_sdesc_t *devs = (loc_sdesc_t *) calloc(count, sizeof(loc_sdesc_t));
664 if (devs == NULL)
665 return 0;
666
667 exch = loc_exchange_begin(LOC_PORT_CONSUMER);
668
669 ipc_call_t answer;
670 aid_t req = async_send_0(exch, LOC_GET_NAMESPACES, &answer);
671 int rc = async_data_read_start(exch, devs, count * sizeof(loc_sdesc_t));
672
673 loc_exchange_end(exch);
674
675 if (rc == EOVERFLOW) {
676 /*
677 * Number of namespaces has changed since
678 * the last call of LOC_GET_NAMESPACE_COUNT
679 */
680 free(devs);
681 continue;
682 }
683
684 if (rc != EOK) {
685 async_forget(req);
686 free(devs);
687 return 0;
688 }
689
690 sysarg_t retval;
691 async_wait_for(req, &retval);
692
693 if (retval != EOK)
694 return 0;
695
696 *data = devs;
697 return count;
698 }
699}
700
701size_t loc_get_services(service_id_t ns_handle, loc_sdesc_t **data)
702{
703 /* Loop until read is succesful */
704 while (true) {
705 async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
706 size_t count = loc_count_services_internal(exch, ns_handle);
707 loc_exchange_end(exch);
708
709 if (count == 0)
710 return 0;
711
712 loc_sdesc_t *devs = (loc_sdesc_t *) calloc(count, sizeof(loc_sdesc_t));
713 if (devs == NULL)
714 return 0;
715
716 exch = loc_exchange_begin(LOC_PORT_CONSUMER);
717
718 ipc_call_t answer;
719 aid_t req = async_send_1(exch, LOC_GET_SERVICES, ns_handle, &answer);
720 int rc = async_data_read_start(exch, devs, count * sizeof(loc_sdesc_t));
721
722 loc_exchange_end(exch);
723
724 if (rc == EOVERFLOW) {
725 /*
726 * Number of services has changed since
727 * the last call of LOC_GET_SERVICE_COUNT
728 */
729 free(devs);
730 continue;
731 }
732
733 if (rc != EOK) {
734 async_forget(req);
735 free(devs);
736 return 0;
737 }
738
739 sysarg_t retval;
740 async_wait_for(req, &retval);
741
742 if (retval != EOK)
743 return 0;
744
745 *data = devs;
746 return count;
747 }
748}
749
750static int loc_category_get_ids_once(sysarg_t method, sysarg_t arg1,
751 sysarg_t *id_buf, size_t buf_size, size_t *act_size)
752{
753 async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
754
755 ipc_call_t answer;
756 aid_t req = async_send_1(exch, method, arg1, &answer);
757 int rc = async_data_read_start(exch, id_buf, buf_size);
758
759 loc_exchange_end(exch);
760
761 if (rc != EOK) {
762 async_forget(req);
763 return rc;
764 }
765
766 sysarg_t retval;
767 async_wait_for(req, &retval);
768
769 if (retval != EOK) {
770 return retval;
771 }
772
773 *act_size = IPC_GET_ARG1(answer);
774 return EOK;
775}
776
777/** Get list of IDs.
778 *
779 * Returns an allocated array of service IDs.
780 *
781 * @param method IPC method
782 * @param arg1 IPC argument 1
783 * @param data Place to store pointer to array of IDs
784 * @param count Place to store number of IDs
785 * @return EOK on success or negative error code
786 */
787static int loc_get_ids_internal(sysarg_t method, sysarg_t arg1,
788 sysarg_t **data, size_t *count)
789{
790 *data = NULL;
791 *count = 0;
792
793 size_t act_size = 0;
794 int rc = loc_category_get_ids_once(method, arg1, NULL, 0,
795 &act_size);
796 if (rc != EOK)
797 return rc;
798
799 size_t alloc_size = act_size;
800 service_id_t *ids = malloc(alloc_size);
801 if (ids == NULL)
802 return ENOMEM;
803
804 while (true) {
805 rc = loc_category_get_ids_once(method, arg1, ids, alloc_size,
806 &act_size);
807 if (rc != EOK)
808 return rc;
809
810 if (act_size <= alloc_size)
811 break;
812
813 alloc_size = act_size;
814 ids = realloc(ids, alloc_size);
815 if (ids == NULL)
816 return ENOMEM;
817 }
818
819 *count = act_size / sizeof(category_id_t);
820 *data = ids;
821 return EOK;
822}
823
824/** Get list of services in category.
825 *
826 * Returns an allocated array of service IDs.
827 *
828 * @param cat_id Category ID
829 * @param data Place to store pointer to array of IDs
830 * @param count Place to store number of IDs
831 * @return EOK on success or negative error code
832 */
833int loc_category_get_svcs(category_id_t cat_id, service_id_t **data,
834 size_t *count)
835{
836 return loc_get_ids_internal(LOC_CATEGORY_GET_SVCS, cat_id,
837 data, count);
838}
839
840/** Get list of categories.
841 *
842 * Returns an allocated array of category IDs.
843 *
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_get_categories(category_id_t **data, size_t *count)
849{
850 return loc_get_ids_internal(LOC_GET_CATEGORIES, 0,
851 data, count);
852}
853
854int loc_register_cat_change_cb(loc_cat_change_cb_t cb_fun)
855{
856 fibril_mutex_lock(&loc_callback_mutex);
857 if (loc_callback_create() != EOK) {
858 fibril_mutex_unlock(&loc_callback_mutex);
859 return EIO;
860 }
861
862 cat_change_cb = cb_fun;
863 fibril_mutex_unlock(&loc_callback_mutex);
864
865 return EOK;
866}
Note: See TracBrowser for help on using the repository browser.