source: mainline/uspace/lib/c/generic/loc.c@ 514d561

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

ns: register service interfaces individually

Each service interface is now registered individually with the naming
service. This adds a degree of type safety, potentially allows the
individual interfaces to be implemented by independent tasks and moves
the code slightly closer to the full-fledged ports design.

Broker services (e.g. the location service) can still register a
fallback port for receiving connections to all interface types
explicitly using service_register_broker().

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