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

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

unify interface API

  • introduce new interfaces
  • unify location service clients to always expect service ID as the second argument
  • remove obsolete methods that take explicit exchange management arguments (first phase)
  • use interfaces in device drivers, devman, location service, logger, inet
  • Property mode set to 100644
File size: 19.5 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>
[3e6a98c5]39#include <stdbool.h>
[15f3c3f]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;
[a6240a31]49static loc_cat_change_cb_t cat_change_cb = NULL;
[12f9f0d0]50
[15f3c3f]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
[12f9f0d0]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);
[a6240a31]71 loc_cat_change_cb_t cb_fun = cat_change_cb;
[12f9f0d0]72 fibril_mutex_unlock(&loc_callback_mutex);
[a6240a31]73
74 async_answer_0(callid, EOK);
75
76 if (cb_fun != NULL)
77 (*cb_fun)();
78
[12f9f0d0]79 break;
80 default:
[a6240a31]81 async_answer_0(callid, ENOTSUP);
[12f9f0d0]82 }
83 }
84}
85
86
[15f3c3f]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
[a6240a31]98/** Create callback
99 *
100 * Must be called with loc_callback_mutex locked.
101 *
102 * @return EOK on success.
103 *
104 */
[12f9f0d0]105static int loc_callback_create(void)
106{
107 if (!loc_callback_created) {
[a6240a31]108 async_exch_t *exch =
[f9b2cb4c]109 loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
[12f9f0d0]110
111 ipc_call_t answer;
112 aid_t req = async_send_0(exch, LOC_CALLBACK_CREATE, &answer);
[f9b2cb4c]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
[12f9f0d0]118 loc_exchange_end(exch);
119
120 if (rc != EOK)
[a6240a31]121 return rc;
[12f9f0d0]122
[cd66f3c]123 sysarg_t retval;
124 async_wait_for(req, &retval);
125 if (retval != EOK)
126 return retval;
[12f9f0d0]127
128 loc_callback_created = true;
129 }
130
[a6240a31]131 return EOK;
[12f9f0d0]132}
133
[15f3c3f]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 */
[f9b2cb4c]141async_exch_t *loc_exchange_begin_blocking(iface_t iface)
[15f3c3f]142{
143 switch (iface) {
[f9b2cb4c]144 case INTERFACE_LOC_SUPPLIER:
[15f3c3f]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 =
[f9b2cb4c]153 service_connect_blocking(SERVICE_LOC,
154 INTERFACE_LOC_SUPPLIER, 0);
[15f3c3f]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);
[f9b2cb4c]163 case INTERFACE_LOC_CONSUMER:
[15f3c3f]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 =
[f9b2cb4c]172 service_connect_blocking(SERVICE_LOC,
173 INTERFACE_LOC_CONSUMER, 0);
[15f3c3f]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 */
[f9b2cb4c]194async_exch_t *loc_exchange_begin(iface_t iface)
[15f3c3f]195{
196 switch (iface) {
[f9b2cb4c]197 case INTERFACE_LOC_SUPPLIER:
[15f3c3f]198 fibril_mutex_lock(&loc_supplier_mutex);
199
200 if (loc_supplier_sess == NULL)
201 loc_supplier_sess =
[f9b2cb4c]202 service_connect(SERVICE_LOC,
203 INTERFACE_LOC_SUPPLIER, 0);
[15f3c3f]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);
[f9b2cb4c]211 case INTERFACE_LOC_CONSUMER:
[15f3c3f]212 fibril_mutex_lock(&loc_consumer_mutex);
213
214 if (loc_consumer_sess == NULL)
215 loc_consumer_sess =
[f9b2cb4c]216 service_connect(SERVICE_LOC,
217 INTERFACE_LOC_CONSUMER, 0);
[15f3c3f]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. */
[f302586]241int loc_server_register(const char *name)
[15f3c3f]242{
[f9b2cb4c]243 async_exch_t *exch = loc_exchange_begin_blocking(INTERFACE_LOC_SUPPLIER);
[15f3c3f]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 loc_exchange_end(exch);
250
251 if (retval != EOK) {
[50b581d]252 async_forget(req);
[15f3c3f]253 return retval;
254 }
255
[f9b2cb4c]256 exch = loc_exchange_begin(INTERFACE_LOC_SUPPLIER);
257 async_connect_to_me(exch, 0, 0, 0);
[15f3c3f]258 loc_exchange_end(exch);
259
260 async_wait_for(req, &retval);
261 return retval;
262}
263
[d0dd7b5]264/** Register new service.
[15f3c3f]265 *
[f9b2cb4c]266 * @param fqsn Fully qualified service name
267 * @param[out] sid Service ID of new service
[15f3c3f]268 *
269 */
[f9b2cb4c]270int loc_service_register(const char *fqsn, service_id_t *sid)
[15f3c3f]271{
[f9b2cb4c]272 async_exch_t *exch = loc_exchange_begin_blocking(INTERFACE_LOC_SUPPLIER);
[15f3c3f]273
274 ipc_call_t answer;
[f9b2cb4c]275 aid_t req = async_send_0(exch, LOC_SERVICE_REGISTER, &answer);
[d0dd7b5]276 sysarg_t retval = async_data_write_start(exch, fqsn, str_size(fqsn));
[15f3c3f]277
278 loc_exchange_end(exch);
279
280 if (retval != EOK) {
[50b581d]281 async_forget(req);
[15f3c3f]282 return retval;
283 }
284
285 async_wait_for(req, &retval);
286
287 if (retval != EOK) {
[d0dd7b5]288 if (sid != NULL)
289 *sid = -1;
[15f3c3f]290
291 return retval;
292 }
293
[d0dd7b5]294 if (sid != NULL)
295 *sid = (service_id_t) IPC_GET_ARG1(answer);
[15f3c3f]296
297 return retval;
298}
299
[d0dd7b5]300/** Unregister service.
301 *
302 * @param sid Service ID
303 */
304int loc_service_unregister(service_id_t sid)
305{
306 async_exch_t *exch;
307 sysarg_t retval;
308
[f9b2cb4c]309 exch = loc_exchange_begin_blocking(INTERFACE_LOC_SUPPLIER);
[d0dd7b5]310 retval = async_req_1_0(exch, LOC_SERVICE_UNREGISTER, sid);
311 loc_exchange_end(exch);
312
313 return (int)retval;
[15f3c3f]314}
315
316int loc_service_get_id(const char *fqdn, service_id_t *handle,
317 unsigned int flags)
318{
319 async_exch_t *exch;
320
321 if (flags & IPC_FLAG_BLOCKING)
[f9b2cb4c]322 exch = loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
[15f3c3f]323 else {
[f9b2cb4c]324 exch = loc_exchange_begin(INTERFACE_LOC_CONSUMER);
[15f3c3f]325 if (exch == NULL)
326 return errno;
327 }
328
329 ipc_call_t answer;
330 aid_t req = async_send_2(exch, LOC_SERVICE_GET_ID, flags, 0,
331 &answer);
332 sysarg_t retval = async_data_write_start(exch, fqdn, str_size(fqdn));
333
334 loc_exchange_end(exch);
335
336 if (retval != EOK) {
[50b581d]337 async_forget(req);
[15f3c3f]338 return retval;
339 }
340
341 async_wait_for(req, &retval);
342
343 if (retval != EOK) {
344 if (handle != NULL)
345 *handle = (service_id_t) -1;
346
347 return retval;
348 }
349
350 if (handle != NULL)
351 *handle = (service_id_t) IPC_GET_ARG1(answer);
352
353 return retval;
354}
355
[763e0cd]356/** Get object name.
[cce8a83]357 *
[763e0cd]358 * Provided ID of an object, return its name.
[cce8a83]359 *
[763e0cd]360 * @param method IPC method
361 * @param id Object ID
[cce8a83]362 * @param name Place to store pointer to new string. Caller should
363 * free it using free().
364 * @return EOK on success or negative error code
365 */
[763e0cd]366static int loc_get_name_internal(sysarg_t method, sysarg_t id, char **name)
[cce8a83]367{
368 async_exch_t *exch;
369 char name_buf[LOC_NAME_MAXLEN + 1];
[45058baa]370 ipc_call_t dreply;
371 size_t act_size;
372 sysarg_t dretval;
[cce8a83]373
374 *name = NULL;
[f9b2cb4c]375 exch = loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
[cce8a83]376
377 ipc_call_t answer;
[763e0cd]378 aid_t req = async_send_1(exch, method, id, &answer);
[45058baa]379 aid_t dreq = async_data_read(exch, name_buf, LOC_NAME_MAXLEN,
380 &dreply);
381 async_wait_for(dreq, &dretval);
[cce8a83]382
383 loc_exchange_end(exch);
384
[45058baa]385 if (dretval != EOK) {
[50b581d]386 async_forget(req);
[45058baa]387 return dretval;
[cce8a83]388 }
389
390 sysarg_t retval;
391 async_wait_for(req, &retval);
392
393 if (retval != EOK)
394 return retval;
395
[45058baa]396 act_size = IPC_GET_ARG2(dreply);
397 assert(act_size <= LOC_NAME_MAXLEN);
398 name_buf[act_size] = '\0';
399
[cce8a83]400 *name = str_dup(name_buf);
401 if (*name == NULL)
402 return ENOMEM;
403
404 return EOK;
405}
406
[763e0cd]407/** Get category name.
408 *
409 * Provided ID of a service, return its name.
410 *
411 * @param cat_id Category ID
412 * @param name Place to store pointer to new string. Caller should
413 * free it using free().
414 * @return EOK on success or negative error code
415 */
416int loc_category_get_name(category_id_t cat_id, char **name)
417{
418 return loc_get_name_internal(LOC_CATEGORY_GET_NAME, cat_id, name);
419}
420
421/** Get service name.
422 *
423 * Provided ID of a service, return its name.
424 *
425 * @param svc_id Service ID
426 * @param name Place to store pointer to new string. Caller should
427 * free it using free().
428 * @return EOK on success or negative error code
429 */
430int loc_service_get_name(service_id_t svc_id, char **name)
431{
432 return loc_get_name_internal(LOC_SERVICE_GET_NAME, svc_id, name);
433}
[cce8a83]434
[a3fcfba]435/** Get service server name.
436 *
437 * Provided ID of a service, return the name of its server.
438 *
439 * @param svc_id Service ID
440 * @param name Place to store pointer to new string. Caller should
441 * free it using free().
442 * @return EOK on success or negative error code
443 */
444int loc_service_get_server_name(service_id_t svc_id, char **name)
445{
446 return loc_get_name_internal(LOC_SERVICE_GET_SERVER_NAME, svc_id, name);
447}
448
[15f3c3f]449int loc_namespace_get_id(const char *name, service_id_t *handle,
450 unsigned int flags)
451{
452 async_exch_t *exch;
453
454 if (flags & IPC_FLAG_BLOCKING)
[f9b2cb4c]455 exch = loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
[15f3c3f]456 else {
[f9b2cb4c]457 exch = loc_exchange_begin(INTERFACE_LOC_CONSUMER);
[15f3c3f]458 if (exch == NULL)
459 return errno;
460 }
461
462 ipc_call_t answer;
463 aid_t req = async_send_2(exch, LOC_NAMESPACE_GET_ID, flags, 0,
464 &answer);
465 sysarg_t retval = async_data_write_start(exch, name, str_size(name));
466
467 loc_exchange_end(exch);
468
469 if (retval != EOK) {
[50b581d]470 async_forget(req);
[15f3c3f]471 return retval;
472 }
473
474 async_wait_for(req, &retval);
475
476 if (retval != EOK) {
477 if (handle != NULL)
478 *handle = (service_id_t) -1;
479
480 return retval;
481 }
482
483 if (handle != NULL)
484 *handle = (service_id_t) IPC_GET_ARG1(answer);
485
486 return retval;
487}
488
[cc574511]489/** Get category ID.
490 *
491 * Provided name of a category, return its ID.
492 *
493 * @param name Category name
494 * @param cat_id Place to store ID
495 * @param flags IPC_FLAG_BLOCKING to wait for location service to start
496 * @return EOK on success or negative error code
497 */
498int loc_category_get_id(const char *name, category_id_t *cat_id,
499 unsigned int flags)
500{
501 async_exch_t *exch;
502
503 if (flags & IPC_FLAG_BLOCKING)
[f9b2cb4c]504 exch = loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
[cc574511]505 else {
[f9b2cb4c]506 exch = loc_exchange_begin(INTERFACE_LOC_CONSUMER);
[cc574511]507 if (exch == NULL)
508 return errno;
509 }
510
511 ipc_call_t answer;
512 aid_t req = async_send_0(exch, LOC_CATEGORY_GET_ID,
513 &answer);
514 sysarg_t retval = async_data_write_start(exch, name, str_size(name));
515
516 loc_exchange_end(exch);
517
518 if (retval != EOK) {
[50b581d]519 async_forget(req);
[cc574511]520 return retval;
521 }
522
523 async_wait_for(req, &retval);
524
525 if (retval != EOK) {
526 if (cat_id != NULL)
527 *cat_id = (category_id_t) -1;
528
529 return retval;
530 }
531
532 if (cat_id != NULL)
533 *cat_id = (category_id_t) IPC_GET_ARG1(answer);
534
535 return retval;
536}
537
538
[15f3c3f]539loc_object_type_t loc_id_probe(service_id_t handle)
540{
[f9b2cb4c]541 async_exch_t *exch = loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
[15f3c3f]542
543 sysarg_t type;
544 int retval = async_req_1_1(exch, LOC_ID_PROBE, handle, &type);
545
546 loc_exchange_end(exch);
547
548 if (retval != EOK)
549 return LOC_OBJECT_NONE;
550
551 return (loc_object_type_t) type;
552}
553
[f9b2cb4c]554async_sess_t *loc_service_connect(service_id_t handle, iface_t iface,
[15f3c3f]555 unsigned int flags)
556{
557 async_sess_t *sess;
558
559 if (flags & IPC_FLAG_BLOCKING)
[f9b2cb4c]560 sess = service_connect_blocking(SERVICE_LOC, iface, handle);
[15f3c3f]561 else
[f9b2cb4c]562 sess = service_connect(SERVICE_LOC, iface, handle);
[15f3c3f]563
564 return sess;
565}
566
567int loc_null_create(void)
568{
[f9b2cb4c]569 async_exch_t *exch = loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
[15f3c3f]570
571 sysarg_t null_id;
572 int retval = async_req_0_1(exch, LOC_NULL_CREATE, &null_id);
573
574 loc_exchange_end(exch);
575
576 if (retval != EOK)
577 return -1;
578
579 return (int) null_id;
580}
581
582void loc_null_destroy(int null_id)
583{
[f9b2cb4c]584 async_exch_t *exch = loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
[15f3c3f]585 async_req_1_0(exch, LOC_NULL_DESTROY, (sysarg_t) null_id);
586 loc_exchange_end(exch);
587}
588
589static size_t loc_count_namespaces_internal(async_exch_t *exch)
590{
591 sysarg_t count;
592 int retval = async_req_0_1(exch, LOC_GET_NAMESPACE_COUNT, &count);
593 if (retval != EOK)
594 return 0;
595
596 return count;
597}
598
[cc574511]599/** Add service to category.
600 *
601 * @param svc_id Service ID
602 * @param cat_id Category ID
603 * @return EOK on success or negative error code
604 */
605int loc_service_add_to_cat(service_id_t svc_id, service_id_t cat_id)
606{
607 async_exch_t *exch;
608 sysarg_t retval;
609
[f9b2cb4c]610 exch = loc_exchange_begin_blocking(INTERFACE_LOC_SUPPLIER);
[cc574511]611 retval = async_req_2_0(exch, LOC_SERVICE_ADD_TO_CAT, svc_id, cat_id);
612 loc_exchange_end(exch);
613
614 return retval;
615}
616
[15f3c3f]617static size_t loc_count_services_internal(async_exch_t *exch,
618 service_id_t ns_handle)
619{
620 sysarg_t count;
621 int retval = async_req_1_1(exch, LOC_GET_SERVICE_COUNT, ns_handle,
622 &count);
623 if (retval != EOK)
624 return 0;
625
626 return count;
627}
628
629size_t loc_count_namespaces(void)
630{
[f9b2cb4c]631 async_exch_t *exch = loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
[15f3c3f]632 size_t size = loc_count_namespaces_internal(exch);
633 loc_exchange_end(exch);
634
635 return size;
636}
637
638size_t loc_count_services(service_id_t ns_handle)
639{
[f9b2cb4c]640 async_exch_t *exch = loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
[15f3c3f]641 size_t size = loc_count_services_internal(exch, ns_handle);
642 loc_exchange_end(exch);
643
644 return size;
645}
646
647size_t loc_get_namespaces(loc_sdesc_t **data)
648{
[cc574511]649 /* Loop until read is succesful */
[15f3c3f]650 while (true) {
[f9b2cb4c]651 async_exch_t *exch = loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
[15f3c3f]652 size_t count = loc_count_namespaces_internal(exch);
653 loc_exchange_end(exch);
654
655 if (count == 0)
656 return 0;
657
658 loc_sdesc_t *devs = (loc_sdesc_t *) calloc(count, sizeof(loc_sdesc_t));
659 if (devs == NULL)
660 return 0;
661
[f9b2cb4c]662 exch = loc_exchange_begin(INTERFACE_LOC_CONSUMER);
[15f3c3f]663
664 ipc_call_t answer;
665 aid_t req = async_send_0(exch, LOC_GET_NAMESPACES, &answer);
666 int rc = async_data_read_start(exch, devs, count * sizeof(loc_sdesc_t));
667
668 loc_exchange_end(exch);
669
670 if (rc == EOVERFLOW) {
671 /*
672 * Number of namespaces has changed since
673 * the last call of LOC_GET_NAMESPACE_COUNT
674 */
675 free(devs);
676 continue;
677 }
678
679 if (rc != EOK) {
[50b581d]680 async_forget(req);
[15f3c3f]681 free(devs);
682 return 0;
683 }
684
685 sysarg_t retval;
686 async_wait_for(req, &retval);
687
688 if (retval != EOK)
689 return 0;
690
691 *data = devs;
692 return count;
693 }
694}
695
696size_t loc_get_services(service_id_t ns_handle, loc_sdesc_t **data)
697{
[cc574511]698 /* Loop until read is succesful */
[15f3c3f]699 while (true) {
[f9b2cb4c]700 async_exch_t *exch = loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
[15f3c3f]701 size_t count = loc_count_services_internal(exch, ns_handle);
702 loc_exchange_end(exch);
703
704 if (count == 0)
705 return 0;
706
707 loc_sdesc_t *devs = (loc_sdesc_t *) calloc(count, sizeof(loc_sdesc_t));
708 if (devs == NULL)
709 return 0;
710
[f9b2cb4c]711 exch = loc_exchange_begin(INTERFACE_LOC_CONSUMER);
[15f3c3f]712
713 ipc_call_t answer;
714 aid_t req = async_send_1(exch, LOC_GET_SERVICES, ns_handle, &answer);
715 int rc = async_data_read_start(exch, devs, count * sizeof(loc_sdesc_t));
716
717 loc_exchange_end(exch);
718
719 if (rc == EOVERFLOW) {
720 /*
721 * Number of services has changed since
722 * the last call of LOC_GET_SERVICE_COUNT
723 */
724 free(devs);
725 continue;
726 }
727
728 if (rc != EOK) {
[50b581d]729 async_forget(req);
[15f3c3f]730 free(devs);
731 return 0;
732 }
733
734 sysarg_t retval;
735 async_wait_for(req, &retval);
736
737 if (retval != EOK)
738 return 0;
739
740 *data = devs;
741 return count;
742 }
743}
[cc574511]744
[278ac72]745static int loc_category_get_ids_once(sysarg_t method, sysarg_t arg1,
746 sysarg_t *id_buf, size_t buf_size, size_t *act_size)
[cc574511]747{
[f9b2cb4c]748 async_exch_t *exch = loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
[cc574511]749
750 ipc_call_t answer;
[278ac72]751 aid_t req = async_send_1(exch, method, arg1, &answer);
[cc574511]752 int rc = async_data_read_start(exch, id_buf, buf_size);
753
754 loc_exchange_end(exch);
755
756 if (rc != EOK) {
[50b581d]757 async_forget(req);
[cc574511]758 return rc;
759 }
760
761 sysarg_t retval;
762 async_wait_for(req, &retval);
763
764 if (retval != EOK) {
765 return retval;
766 }
767
768 *act_size = IPC_GET_ARG1(answer);
769 return EOK;
770}
771
[278ac72]772/** Get list of IDs.
[cc574511]773 *
774 * Returns an allocated array of service IDs.
775 *
[278ac72]776 * @param method IPC method
777 * @param arg1 IPC argument 1
[cc574511]778 * @param data Place to store pointer to array of IDs
779 * @param count Place to store number of IDs
780 * @return EOK on success or negative error code
781 */
[278ac72]782static int loc_get_ids_internal(sysarg_t method, sysarg_t arg1,
783 sysarg_t **data, size_t *count)
[cc574511]784{
785 *data = NULL;
[88057e3]786 *count = 0;
787
788 size_t act_size = 0;
789 int rc = loc_category_get_ids_once(method, arg1, NULL, 0,
[278ac72]790 &act_size);
[cc574511]791 if (rc != EOK)
792 return rc;
[88057e3]793
794 size_t alloc_size = act_size;
795 service_id_t *ids = malloc(alloc_size);
[cc574511]796 if (ids == NULL)
797 return ENOMEM;
[88057e3]798
[cc574511]799 while (true) {
[278ac72]800 rc = loc_category_get_ids_once(method, arg1, ids, alloc_size,
[cc574511]801 &act_size);
802 if (rc != EOK)
803 return rc;
[88057e3]804
[c1f27f1d]805 if (act_size <= alloc_size)
[cc574511]806 break;
[88057e3]807
808 alloc_size = act_size;
809 ids = realloc(ids, alloc_size);
[cc574511]810 if (ids == NULL)
811 return ENOMEM;
812 }
[88057e3]813
[cc574511]814 *count = act_size / sizeof(category_id_t);
815 *data = ids;
816 return EOK;
817}
[278ac72]818
819/** Get list of services in category.
820 *
821 * Returns an allocated array of service IDs.
822 *
823 * @param cat_id Category ID
824 * @param data Place to store pointer to array of IDs
825 * @param count Place to store number of IDs
826 * @return EOK on success or negative error code
827 */
828int loc_category_get_svcs(category_id_t cat_id, service_id_t **data,
829 size_t *count)
830{
831 return loc_get_ids_internal(LOC_CATEGORY_GET_SVCS, cat_id,
832 data, count);
833}
834
835/** Get list of categories.
836 *
837 * Returns an allocated array of category IDs.
838 *
839 * @param data Place to store pointer to array of IDs
840 * @param count Place to store number of IDs
841 * @return EOK on success or negative error code
842 */
843int loc_get_categories(category_id_t **data, size_t *count)
844{
845 return loc_get_ids_internal(LOC_GET_CATEGORIES, 0,
846 data, count);
847}
[12f9f0d0]848
849int loc_register_cat_change_cb(loc_cat_change_cb_t cb_fun)
850{
[a6240a31]851 fibril_mutex_lock(&loc_callback_mutex);
852 if (loc_callback_create() != EOK) {
853 fibril_mutex_unlock(&loc_callback_mutex);
[12f9f0d0]854 return EIO;
[a6240a31]855 }
856
[12f9f0d0]857 cat_change_cb = cb_fun;
[a6240a31]858 fibril_mutex_unlock(&loc_callback_mutex);
859
[12f9f0d0]860 return EOK;
861}
Note: See TracBrowser for help on using the repository browser.