source: mainline/uspace/lib/c/generic/loc.c@ 99ac5cf

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

Notifications on changes in loc categories. Limitations:

  • cannot specify single category to watch
  • max one task can register notifications with loc service
  • max one user callback function can be registered with C library

Remove devman tests as they are not applicable anymore.

  • Property mode set to 100644
File size: 18.7 KB
RevLine 
[15f3c3f]1/*
2 * Copyright (c) 2007 Josef Cejka
[cc574511]3 * Copyright (c) 2011 Jiri Svoboda
[15f3c3f]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
[12f9f0d0]47static FIBRIL_MUTEX_INITIALIZE(loc_callback_mutex);
48static bool loc_callback_created = false;
49
[15f3c3f]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
[12f9f0d0]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
[15f3c3f]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
[12f9f0d0]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
[15f3c3f]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 device.
270 *
271 * The @p interface is used when forwarding connection to the driver.
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 fqdn Fully qualified device name.
279 * @param[out] handle Handle to the created instance of device.
280 * @param interface Interface when forwarding.
281 *
282 */
283int loc_service_register_with_iface(const char *fqdn,
284 service_id_t *handle, 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, fqdn, str_size(fqdn));
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 (handle != NULL)
304 *handle = -1;
305
306 return retval;
307 }
308
309 if (handle != NULL)
310 *handle = (service_id_t) IPC_GET_ARG1(answer);
311
312 return retval;
313}
314
315/** Register new device.
316 *
317 * @param fqdn Fully qualified device name.
318 * @param handle Output: Handle to the created instance of device.
319 *
320 */
321int loc_service_register(const char *fqdn, service_id_t *handle)
322{
323 return loc_service_register_with_iface(fqdn, handle, 0);
324}
325
326int loc_service_get_id(const char *fqdn, service_id_t *handle,
327 unsigned int flags)
328{
329 async_exch_t *exch;
330
331 if (flags & IPC_FLAG_BLOCKING)
332 exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
333 else {
334 exch = loc_exchange_begin(LOC_PORT_CONSUMER);
335 if (exch == NULL)
336 return errno;
337 }
338
339 ipc_call_t answer;
340 aid_t req = async_send_2(exch, LOC_SERVICE_GET_ID, flags, 0,
341 &answer);
342 sysarg_t retval = async_data_write_start(exch, fqdn, str_size(fqdn));
343
344 loc_exchange_end(exch);
345
346 if (retval != EOK) {
347 async_wait_for(req, NULL);
348 return retval;
349 }
350
351 async_wait_for(req, &retval);
352
353 if (retval != EOK) {
354 if (handle != NULL)
355 *handle = (service_id_t) -1;
356
357 return retval;
358 }
359
360 if (handle != NULL)
361 *handle = (service_id_t) IPC_GET_ARG1(answer);
362
363 return retval;
364}
365
[cce8a83]366/** Get service name.
367 *
368 * Provided ID of a service, return its name.
369 *
370 * @param svc_id Service 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 */
375int loc_service_get_name(service_id_t svc_id, char **name)
376{
377 async_exch_t *exch;
378 char name_buf[LOC_NAME_MAXLEN + 1];
[45058baa]379 ipc_call_t dreply;
380 size_t act_size;
381 sysarg_t dretval;
[cce8a83]382
383 *name = NULL;
384 exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
385
386 ipc_call_t answer;
387 aid_t req = async_send_1(exch, LOC_SERVICE_GET_NAME, svc_id, &answer);
[45058baa]388 aid_t dreq = async_data_read(exch, name_buf, LOC_NAME_MAXLEN,
389 &dreply);
390 async_wait_for(dreq, &dretval);
[cce8a83]391
392 loc_exchange_end(exch);
393
[45058baa]394 if (dretval != EOK) {
[cce8a83]395 async_wait_for(req, NULL);
[45058baa]396 return dretval;
[cce8a83]397 }
398
399 sysarg_t retval;
400 async_wait_for(req, &retval);
401
402 if (retval != EOK)
403 return retval;
404
[45058baa]405 act_size = IPC_GET_ARG2(dreply);
406 assert(act_size <= LOC_NAME_MAXLEN);
407 name_buf[act_size] = '\0';
408
[cce8a83]409 *name = str_dup(name_buf);
410 if (*name == NULL)
411 return ENOMEM;
412
413 return EOK;
414}
415
416
[15f3c3f]417int loc_namespace_get_id(const char *name, service_id_t *handle,
418 unsigned int flags)
419{
420 async_exch_t *exch;
421
422 if (flags & IPC_FLAG_BLOCKING)
423 exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
424 else {
425 exch = loc_exchange_begin(LOC_PORT_CONSUMER);
426 if (exch == NULL)
427 return errno;
428 }
429
430 ipc_call_t answer;
431 aid_t req = async_send_2(exch, LOC_NAMESPACE_GET_ID, flags, 0,
432 &answer);
433 sysarg_t retval = async_data_write_start(exch, name, str_size(name));
434
435 loc_exchange_end(exch);
436
437 if (retval != EOK) {
438 async_wait_for(req, NULL);
439 return retval;
440 }
441
442 async_wait_for(req, &retval);
443
444 if (retval != EOK) {
445 if (handle != NULL)
446 *handle = (service_id_t) -1;
447
448 return retval;
449 }
450
451 if (handle != NULL)
452 *handle = (service_id_t) IPC_GET_ARG1(answer);
453
454 return retval;
455}
456
[cc574511]457/** Get category ID.
458 *
459 * Provided name of a category, return its ID.
460 *
461 * @param name Category name
462 * @param cat_id Place to store ID
463 * @param flags IPC_FLAG_BLOCKING to wait for location service to start
464 * @return EOK on success or negative error code
465 */
466int loc_category_get_id(const char *name, category_id_t *cat_id,
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_0(exch, LOC_CATEGORY_GET_ID,
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_wait_for(req, NULL);
488 return retval;
489 }
490
491 async_wait_for(req, &retval);
492
493 if (retval != EOK) {
494 if (cat_id != NULL)
495 *cat_id = (category_id_t) -1;
496
497 return retval;
498 }
499
500 if (cat_id != NULL)
501 *cat_id = (category_id_t) IPC_GET_ARG1(answer);
502
503 return retval;
504}
505
506
[15f3c3f]507loc_object_type_t loc_id_probe(service_id_t handle)
508{
509 async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
510
511 sysarg_t type;
512 int retval = async_req_1_1(exch, LOC_ID_PROBE, handle, &type);
513
514 loc_exchange_end(exch);
515
516 if (retval != EOK)
517 return LOC_OBJECT_NONE;
518
519 return (loc_object_type_t) type;
520}
521
522async_sess_t *loc_service_connect(exch_mgmt_t mgmt, service_id_t handle,
523 unsigned int flags)
524{
525 async_sess_t *sess;
526
527 if (flags & IPC_FLAG_BLOCKING)
528 sess = service_connect_blocking(mgmt, SERVICE_LOC,
529 LOC_CONNECT_TO_SERVICE, handle);
530 else
531 sess = service_connect(mgmt, SERVICE_LOC,
532 LOC_CONNECT_TO_SERVICE, handle);
533
534 return sess;
535}
536
537int loc_null_create(void)
538{
539 async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
540
541 sysarg_t null_id;
542 int retval = async_req_0_1(exch, LOC_NULL_CREATE, &null_id);
543
544 loc_exchange_end(exch);
545
546 if (retval != EOK)
547 return -1;
548
549 return (int) null_id;
550}
551
552void loc_null_destroy(int null_id)
553{
554 async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
555 async_req_1_0(exch, LOC_NULL_DESTROY, (sysarg_t) null_id);
556 loc_exchange_end(exch);
557}
558
559static size_t loc_count_namespaces_internal(async_exch_t *exch)
560{
561 sysarg_t count;
562 int retval = async_req_0_1(exch, LOC_GET_NAMESPACE_COUNT, &count);
563 if (retval != EOK)
564 return 0;
565
566 return count;
567}
568
[cc574511]569/** Add service to category.
570 *
571 * @param svc_id Service ID
572 * @param cat_id Category ID
573 * @return EOK on success or negative error code
574 */
575int loc_service_add_to_cat(service_id_t svc_id, service_id_t cat_id)
576{
577 async_exch_t *exch;
578 sysarg_t retval;
579
580 exch = loc_exchange_begin_blocking(LOC_PORT_SUPPLIER);
581 retval = async_req_2_0(exch, LOC_SERVICE_ADD_TO_CAT, svc_id, cat_id);
582 loc_exchange_end(exch);
583
584 return retval;
585}
586
[15f3c3f]587static size_t loc_count_services_internal(async_exch_t *exch,
588 service_id_t ns_handle)
589{
590 sysarg_t count;
591 int retval = async_req_1_1(exch, LOC_GET_SERVICE_COUNT, ns_handle,
592 &count);
593 if (retval != EOK)
594 return 0;
595
596 return count;
597}
598
599size_t loc_count_namespaces(void)
600{
601 async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
602 size_t size = loc_count_namespaces_internal(exch);
603 loc_exchange_end(exch);
604
605 return size;
606}
607
608size_t loc_count_services(service_id_t ns_handle)
609{
610 async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
611 size_t size = loc_count_services_internal(exch, ns_handle);
612 loc_exchange_end(exch);
613
614 return size;
615}
616
617size_t loc_get_namespaces(loc_sdesc_t **data)
618{
[cc574511]619 /* Loop until read is succesful */
[15f3c3f]620 while (true) {
621 async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
622 size_t count = loc_count_namespaces_internal(exch);
623 loc_exchange_end(exch);
624
625 if (count == 0)
626 return 0;
627
628 loc_sdesc_t *devs = (loc_sdesc_t *) calloc(count, sizeof(loc_sdesc_t));
629 if (devs == NULL)
630 return 0;
631
632 exch = loc_exchange_begin(LOC_PORT_CONSUMER);
633
634 ipc_call_t answer;
635 aid_t req = async_send_0(exch, LOC_GET_NAMESPACES, &answer);
636 int rc = async_data_read_start(exch, devs, count * sizeof(loc_sdesc_t));
637
638 loc_exchange_end(exch);
639
640 if (rc == EOVERFLOW) {
641 /*
642 * Number of namespaces has changed since
643 * the last call of LOC_GET_NAMESPACE_COUNT
644 */
645 free(devs);
646 continue;
647 }
648
649 if (rc != EOK) {
650 async_wait_for(req, NULL);
651 free(devs);
652 return 0;
653 }
654
655 sysarg_t retval;
656 async_wait_for(req, &retval);
657
658 if (retval != EOK)
659 return 0;
660
661 *data = devs;
662 return count;
663 }
664}
665
666size_t loc_get_services(service_id_t ns_handle, loc_sdesc_t **data)
667{
[cc574511]668 /* Loop until read is succesful */
[15f3c3f]669 while (true) {
670 async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
671 size_t count = loc_count_services_internal(exch, ns_handle);
672 loc_exchange_end(exch);
673
674 if (count == 0)
675 return 0;
676
677 loc_sdesc_t *devs = (loc_sdesc_t *) calloc(count, sizeof(loc_sdesc_t));
678 if (devs == NULL)
679 return 0;
680
681 exch = loc_exchange_begin(LOC_PORT_CONSUMER);
682
683 ipc_call_t answer;
684 aid_t req = async_send_1(exch, LOC_GET_SERVICES, ns_handle, &answer);
685 int rc = async_data_read_start(exch, devs, count * sizeof(loc_sdesc_t));
686
687 loc_exchange_end(exch);
688
689 if (rc == EOVERFLOW) {
690 /*
691 * Number of services has changed since
692 * the last call of LOC_GET_SERVICE_COUNT
693 */
694 free(devs);
695 continue;
696 }
697
698 if (rc != EOK) {
699 async_wait_for(req, NULL);
700 free(devs);
701 return 0;
702 }
703
704 sysarg_t retval;
705 async_wait_for(req, &retval);
706
707 if (retval != EOK)
708 return 0;
709
710 *data = devs;
711 return count;
712 }
713}
[cc574511]714
[278ac72]715static int loc_category_get_ids_once(sysarg_t method, sysarg_t arg1,
716 sysarg_t *id_buf, size_t buf_size, size_t *act_size)
[cc574511]717{
718 async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
719
720 ipc_call_t answer;
[278ac72]721 aid_t req = async_send_1(exch, method, arg1, &answer);
[cc574511]722 int rc = async_data_read_start(exch, id_buf, buf_size);
723
724 loc_exchange_end(exch);
725
726 if (rc != EOK) {
727 async_wait_for(req, NULL);
728 return rc;
729 }
730
731 sysarg_t retval;
732 async_wait_for(req, &retval);
733
734 if (retval != EOK) {
735 return retval;
736 }
737
738 *act_size = IPC_GET_ARG1(answer);
739 return EOK;
740}
741
[278ac72]742/** Get list of IDs.
[cc574511]743 *
744 * Returns an allocated array of service IDs.
745 *
[278ac72]746 * @param method IPC method
747 * @param arg1 IPC argument 1
[cc574511]748 * @param data Place to store pointer to array of IDs
749 * @param count Place to store number of IDs
750 * @return EOK on success or negative error code
751 */
[278ac72]752static int loc_get_ids_internal(sysarg_t method, sysarg_t arg1,
753 sysarg_t **data, size_t *count)
[cc574511]754{
755 service_id_t *ids;
756 size_t act_size;
757 size_t alloc_size;
758 int rc;
759
760 *data = NULL;
761 act_size = 0; /* silence warning */
762
[278ac72]763 rc = loc_category_get_ids_once(method, arg1, NULL, 0,
764 &act_size);
[cc574511]765 if (rc != EOK)
766 return rc;
767
768 alloc_size = act_size;
769 ids = malloc(alloc_size);
770 if (ids == NULL)
771 return ENOMEM;
772
773 while (true) {
[278ac72]774 rc = loc_category_get_ids_once(method, arg1, ids, alloc_size,
[cc574511]775 &act_size);
776 if (rc != EOK)
777 return rc;
778
779 if (act_size <= alloc_size)
780 break;
781
782 alloc_size *= 2;
783 free(ids);
784
785 ids = malloc(alloc_size);
786 if (ids == NULL)
787 return ENOMEM;
788 }
789
790 *count = act_size / sizeof(category_id_t);
791 *data = ids;
792 return EOK;
793}
[278ac72]794
795/** Get list of services in category.
796 *
797 * Returns an allocated array of service IDs.
798 *
799 * @param cat_id Category ID
800 * @param data Place to store pointer to array of IDs
801 * @param count Place to store number of IDs
802 * @return EOK on success or negative error code
803 */
804int loc_category_get_svcs(category_id_t cat_id, service_id_t **data,
805 size_t *count)
806{
807 return loc_get_ids_internal(LOC_CATEGORY_GET_SVCS, cat_id,
808 data, count);
809}
810
811/** Get list of categories.
812 *
813 * Returns an allocated array of category IDs.
814 *
815 * @param data Place to store pointer to array of IDs
816 * @param count Place to store number of IDs
817 * @return EOK on success or negative error code
818 */
819int loc_get_categories(category_id_t **data, size_t *count)
820{
821 return loc_get_ids_internal(LOC_GET_CATEGORIES, 0,
822 data, count);
823}
[12f9f0d0]824
825int loc_register_cat_change_cb(loc_cat_change_cb_t cb_fun)
826{
827 if (loc_callback_create() != EOK)
828 return EIO;
829
830 cat_change_cb = cb_fun;
831 return EOK;
832}
Note: See TracBrowser for help on using the repository browser.