source: mainline/uspace/lib/c/generic/loc.c@ 14b5c30f

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

Use an optional output argument instead of errno to propagate the error

The use of errno is troublesome in all other than top-level library
functions since the value in errno might get overwritten by subsequent
inner calls on the error path (e.g. cleanup, deallocation, etc.). The
optional output argument makes it possible to explicitly ignore the
error code if it is not needed, but still to pass it reliably back to
the original caller.

This change affecs async_connect_me_to(),
async_connect_me_to_blocking(), async_connect_kbox(), service_connect(),
service_connect_blocking() and loader_connect().

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