![]() |
libsigrok
0.3.0
sigrok hardware access and backend library
|
00001 /* 00002 * This file is part of the libsigrok project. 00003 * 00004 * Copyright (C) 2010-2012 Bert Vermeulen <bert@biot.com> 00005 * 00006 * This program is free software: you can redistribute it and/or modify 00007 * it under the terms of the GNU General Public License as published by 00008 * the Free Software Foundation, either version 3 of the License, or 00009 * (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program. If not, see <http://www.gnu.org/licenses/>. 00018 */ 00019 00020 #include <stdio.h> 00021 #include <stdlib.h> 00022 #include <unistd.h> 00023 #include <string.h> 00024 #include <glib.h> 00025 #include "libsigrok.h" 00026 #include "libsigrok-internal.h" 00027 00028 /** @cond PRIVATE */ 00029 #define LOG_PREFIX "session" 00030 /** @endcond */ 00031 00032 /** 00033 * @file 00034 * 00035 * Creating, using, or destroying libsigrok sessions. 00036 */ 00037 00038 /** 00039 * @defgroup grp_session Session handling 00040 * 00041 * Creating, using, or destroying libsigrok sessions. 00042 * 00043 * @{ 00044 */ 00045 00046 struct source { 00047 int timeout; 00048 sr_receive_data_callback cb; 00049 void *cb_data; 00050 00051 /* This is used to keep track of the object (fd, pollfd or channel) which is 00052 * being polled and will be used to match the source when removing it again. 00053 */ 00054 gintptr poll_object; 00055 }; 00056 00057 struct datafeed_callback { 00058 sr_datafeed_callback cb; 00059 void *cb_data; 00060 }; 00061 00062 /* There can only be one session at a time. */ 00063 /* 'session' is not static, it's used elsewhere (via 'extern'). */ 00064 struct sr_session *session; 00065 00066 /** 00067 * Create a new session. 00068 * 00069 * @todo Should it use the file-global "session" variable or take an argument? 00070 * The same question applies to all the other session functions. 00071 * 00072 * @retval NULL Error. 00073 * @retval other A pointer to the newly allocated session. 00074 * 00075 * @since 0.1.0 00076 */ 00077 SR_API struct sr_session *sr_session_new(void) 00078 { 00079 if (!(session = g_try_malloc0(sizeof(struct sr_session)))) { 00080 sr_err("Session malloc failed."); 00081 return NULL; 00082 } 00083 00084 session->source_timeout = -1; 00085 session->running = FALSE; 00086 session->abort_session = FALSE; 00087 g_mutex_init(&session->stop_mutex); 00088 00089 return session; 00090 } 00091 00092 /** 00093 * Destroy the current session. 00094 * This frees up all memory used by the session. 00095 * 00096 * @retval SR_OK Success. 00097 * @retval SR_ERR_BUG No session exists. 00098 * 00099 * @since 0.1.0 00100 */ 00101 SR_API int sr_session_destroy(void) 00102 { 00103 if (!session) { 00104 sr_err("%s: session was NULL", __func__); 00105 return SR_ERR_BUG; 00106 } 00107 00108 sr_session_dev_remove_all(); 00109 00110 /* TODO: Error checks needed? */ 00111 00112 g_mutex_clear(&session->stop_mutex); 00113 00114 g_free(session); 00115 session = NULL; 00116 00117 return SR_OK; 00118 } 00119 00120 /** 00121 * Remove all the devices from the current session. 00122 * 00123 * The session itself (i.e., the struct sr_session) is not free'd and still 00124 * exists after this function returns. 00125 * 00126 * @retval SR_OK Success. 00127 * @retval SR_ERR_BUG No session exists. 00128 * 00129 * @since 0.1.0 00130 */ 00131 SR_API int sr_session_dev_remove_all(void) 00132 { 00133 if (!session) { 00134 sr_err("%s: session was NULL", __func__); 00135 return SR_ERR_BUG; 00136 } 00137 00138 g_slist_free(session->devs); 00139 session->devs = NULL; 00140 00141 return SR_OK; 00142 } 00143 00144 /** 00145 * Add a device instance to the current session. 00146 * 00147 * @param sdi The device instance to add to the current session. Must not 00148 * be NULL. Also, sdi->driver and sdi->driver->dev_open must 00149 * not be NULL. 00150 * 00151 * @retval SR_OK Success. 00152 * @retval SR_ERR_ARG Invalid argument. 00153 * @retval SR_ERR_BUG No session exists. 00154 * 00155 * @since 0.2.0 00156 */ 00157 SR_API int sr_session_dev_add(const struct sr_dev_inst *sdi) 00158 { 00159 int ret; 00160 00161 if (!sdi) { 00162 sr_err("%s: sdi was NULL", __func__); 00163 return SR_ERR_ARG; 00164 } 00165 00166 if (!session) { 00167 sr_err("%s: session was NULL", __func__); 00168 return SR_ERR_BUG; 00169 } 00170 00171 /* If sdi->driver is NULL, this is a virtual device. */ 00172 if (!sdi->driver) { 00173 sr_dbg("%s: sdi->driver was NULL, this seems to be " 00174 "a virtual device; continuing", __func__); 00175 /* Just add the device, don't run dev_open(). */ 00176 session->devs = g_slist_append(session->devs, (gpointer)sdi); 00177 return SR_OK; 00178 } 00179 00180 /* sdi->driver is non-NULL (i.e. we have a real device). */ 00181 if (!sdi->driver->dev_open) { 00182 sr_err("%s: sdi->driver->dev_open was NULL", __func__); 00183 return SR_ERR_BUG; 00184 } 00185 00186 session->devs = g_slist_append(session->devs, (gpointer)sdi); 00187 00188 if (session->running) { 00189 /* Adding a device to a running session. Commit settings 00190 * and start acquisition on that device now. */ 00191 if ((ret = sr_config_commit(sdi)) != SR_OK) { 00192 sr_err("Failed to commit device settings before " 00193 "starting acquisition in running session (%s)", 00194 sr_strerror(ret)); 00195 return ret; 00196 } 00197 if ((ret = sdi->driver->dev_acquisition_start(sdi, 00198 (void *)sdi)) != SR_OK) { 00199 sr_err("Failed to start acquisition of device in " 00200 "running session (%s)", sr_strerror(ret)); 00201 return ret; 00202 } 00203 } 00204 00205 return SR_OK; 00206 } 00207 00208 /** 00209 * List all device instances attached to the current session. 00210 * 00211 * @param devlist A pointer where the device instance list will be 00212 * stored on return. If no devices are in the session, 00213 * this will be NULL. Each element in the list points 00214 * to a struct sr_dev_inst *. 00215 * The list must be freed by the caller, but not the 00216 * elements pointed to. 00217 * 00218 * @retval SR_OK Success. 00219 * @retval SR_ERR Invalid argument. 00220 * 00221 * @since 0.3.0 00222 */ 00223 SR_API int sr_session_dev_list(GSList **devlist) 00224 { 00225 00226 *devlist = NULL; 00227 00228 if (!session) 00229 return SR_ERR; 00230 00231 *devlist = g_slist_copy(session->devs); 00232 00233 return SR_OK; 00234 } 00235 00236 /** 00237 * Remove all datafeed callbacks in the current session. 00238 * 00239 * @retval SR_OK Success. 00240 * @retval SR_ERR_BUG No session exists. 00241 * 00242 * @since 0.1.0 00243 */ 00244 SR_API int sr_session_datafeed_callback_remove_all(void) 00245 { 00246 if (!session) { 00247 sr_err("%s: session was NULL", __func__); 00248 return SR_ERR_BUG; 00249 } 00250 00251 g_slist_free_full(session->datafeed_callbacks, g_free); 00252 session->datafeed_callbacks = NULL; 00253 00254 return SR_OK; 00255 } 00256 00257 /** 00258 * Add a datafeed callback to the current session. 00259 * 00260 * @param cb Function to call when a chunk of data is received. 00261 * Must not be NULL. 00262 * @param cb_data Opaque pointer passed in by the caller. 00263 * 00264 * @retval SR_OK Success. 00265 * @retval SR_ERR_BUG No session exists. 00266 * 00267 * @since 0.3.0 00268 */ 00269 SR_API int sr_session_datafeed_callback_add(sr_datafeed_callback cb, void *cb_data) 00270 { 00271 struct datafeed_callback *cb_struct; 00272 00273 if (!session) { 00274 sr_err("%s: session was NULL", __func__); 00275 return SR_ERR_BUG; 00276 } 00277 00278 if (!cb) { 00279 sr_err("%s: cb was NULL", __func__); 00280 return SR_ERR_ARG; 00281 } 00282 00283 if (!(cb_struct = g_try_malloc0(sizeof(struct datafeed_callback)))) 00284 return SR_ERR_MALLOC; 00285 00286 cb_struct->cb = cb; 00287 cb_struct->cb_data = cb_data; 00288 00289 session->datafeed_callbacks = 00290 g_slist_append(session->datafeed_callbacks, cb_struct); 00291 00292 return SR_OK; 00293 } 00294 00295 /** 00296 * Call every device in the session's callback. 00297 * 00298 * For sessions not driven by select loops such as sr_session_run(), 00299 * but driven by another scheduler, this can be used to poll the devices 00300 * from within that scheduler. 00301 * 00302 * @param block If TRUE, this call will wait for any of the session's 00303 * sources to fire an event on the file descriptors, or 00304 * any of their timeouts to activate. In other words, this 00305 * can be used as a select loop. 00306 * If FALSE, all sources have their callback run, regardless 00307 * of file descriptor or timeout status. 00308 * 00309 * @retval SR_OK Success. 00310 * @retval SR_ERR Error occured. 00311 */ 00312 static int sr_session_iteration(gboolean block) 00313 { 00314 unsigned int i; 00315 int ret; 00316 00317 ret = g_poll(session->pollfds, session->num_sources, 00318 block ? session->source_timeout : 0); 00319 for (i = 0; i < session->num_sources; i++) { 00320 if (session->pollfds[i].revents > 0 || (ret == 0 00321 && session->source_timeout == session->sources[i].timeout)) { 00322 /* 00323 * Invoke the source's callback on an event, 00324 * or if the poll timed out and this source 00325 * asked for that timeout. 00326 */ 00327 if (!session->sources[i].cb(session->pollfds[i].fd, 00328 session->pollfds[i].revents, 00329 session->sources[i].cb_data)) 00330 sr_session_source_remove(session->sources[i].poll_object); 00331 } 00332 /* 00333 * We want to take as little time as possible to stop 00334 * the session if we have been told to do so. Therefore, 00335 * we check the flag after processing every source, not 00336 * just once per main event loop. 00337 */ 00338 g_mutex_lock(&session->stop_mutex); 00339 if (session->abort_session) { 00340 sr_session_stop_sync(); 00341 /* But once is enough. */ 00342 session->abort_session = FALSE; 00343 } 00344 g_mutex_unlock(&session->stop_mutex); 00345 } 00346 00347 return SR_OK; 00348 } 00349 00350 /** 00351 * Start a session. 00352 * 00353 * There can only be one session at a time. 00354 * 00355 * @retval SR_OK Success. 00356 * @retval SR_ERR Error occured. 00357 * 00358 * @since 0.1.0 00359 */ 00360 SR_API int sr_session_start(void) 00361 { 00362 struct sr_dev_inst *sdi; 00363 GSList *l; 00364 int ret; 00365 00366 if (!session) { 00367 sr_err("%s: session was NULL; a session must be " 00368 "created before starting it.", __func__); 00369 return SR_ERR_BUG; 00370 } 00371 00372 if (!session->devs) { 00373 sr_err("%s: session->devs was NULL; a session " 00374 "cannot be started without devices.", __func__); 00375 return SR_ERR_BUG; 00376 } 00377 00378 sr_info("Starting."); 00379 00380 ret = SR_OK; 00381 for (l = session->devs; l; l = l->next) { 00382 sdi = l->data; 00383 if ((ret = sr_config_commit(sdi)) != SR_OK) { 00384 sr_err("Failed to commit device settings before " 00385 "starting acquisition (%s)", sr_strerror(ret)); 00386 break; 00387 } 00388 if ((ret = sdi->driver->dev_acquisition_start(sdi, sdi)) != SR_OK) { 00389 sr_err("%s: could not start an acquisition " 00390 "(%s)", __func__, sr_strerror(ret)); 00391 break; 00392 } 00393 } 00394 00395 /* TODO: What if there are multiple devices? Which return code? */ 00396 00397 return ret; 00398 } 00399 00400 /** 00401 * Run the session. 00402 * 00403 * @retval SR_OK Success. 00404 * @retval SR_ERR_BUG Error occured. 00405 * 00406 * @since 0.1.0 00407 */ 00408 SR_API int sr_session_run(void) 00409 { 00410 if (!session) { 00411 sr_err("%s: session was NULL; a session must be " 00412 "created first, before running it.", __func__); 00413 return SR_ERR_BUG; 00414 } 00415 00416 if (!session->devs) { 00417 /* TODO: Actually the case? */ 00418 sr_err("%s: session->devs was NULL; a session " 00419 "cannot be run without devices.", __func__); 00420 return SR_ERR_BUG; 00421 } 00422 session->running = TRUE; 00423 00424 sr_info("Running."); 00425 00426 /* Do we have real sources? */ 00427 if (session->num_sources == 1 && session->pollfds[0].fd == -1) { 00428 /* Dummy source, freewheel over it. */ 00429 while (session->num_sources) 00430 session->sources[0].cb(-1, 0, session->sources[0].cb_data); 00431 } else { 00432 /* Real sources, use g_poll() main loop. */ 00433 while (session->num_sources) 00434 sr_session_iteration(TRUE); 00435 } 00436 00437 return SR_OK; 00438 } 00439 00440 /** 00441 * Stop the current session. 00442 * 00443 * The current session is stopped immediately, with all acquisition sessions 00444 * being stopped and hardware drivers cleaned up. 00445 * 00446 * This must be called from within the session thread, to prevent freeing 00447 * resources that the session thread will try to use. 00448 * 00449 * @retval SR_OK Success. 00450 * @retval SR_ERR_BUG No session exists. 00451 * 00452 * @private 00453 */ 00454 SR_PRIV int sr_session_stop_sync(void) 00455 { 00456 struct sr_dev_inst *sdi; 00457 GSList *l; 00458 00459 if (!session) { 00460 sr_err("%s: session was NULL", __func__); 00461 return SR_ERR_BUG; 00462 } 00463 00464 sr_info("Stopping."); 00465 00466 for (l = session->devs; l; l = l->next) { 00467 sdi = l->data; 00468 if (sdi->driver) { 00469 if (sdi->driver->dev_acquisition_stop) 00470 sdi->driver->dev_acquisition_stop(sdi, sdi); 00471 } 00472 } 00473 session->running = FALSE; 00474 00475 return SR_OK; 00476 } 00477 00478 /** 00479 * Stop the current session. 00480 * 00481 * The current session is stopped immediately, with all acquisition sessions 00482 * being stopped and hardware drivers cleaned up. 00483 * 00484 * If the session is run in a separate thread, this function will not block 00485 * until the session is finished executing. It is the caller's responsibility 00486 * to wait for the session thread to return before assuming that the session is 00487 * completely decommissioned. 00488 * 00489 * @retval SR_OK Success. 00490 * @retval SR_ERR_BUG No session exists. 00491 * 00492 * @since 0.1.0 00493 */ 00494 SR_API int sr_session_stop(void) 00495 { 00496 if (!session) { 00497 sr_err("%s: session was NULL", __func__); 00498 return SR_ERR_BUG; 00499 } 00500 00501 g_mutex_lock(&session->stop_mutex); 00502 session->abort_session = TRUE; 00503 g_mutex_unlock(&session->stop_mutex); 00504 00505 return SR_OK; 00506 } 00507 00508 /** 00509 * Debug helper. 00510 * 00511 * @param packet The packet to show debugging information for. 00512 */ 00513 static void datafeed_dump(const struct sr_datafeed_packet *packet) 00514 { 00515 const struct sr_datafeed_logic *logic; 00516 const struct sr_datafeed_analog *analog; 00517 00518 switch (packet->type) { 00519 case SR_DF_HEADER: 00520 sr_dbg("bus: Received SR_DF_HEADER packet."); 00521 break; 00522 case SR_DF_TRIGGER: 00523 sr_dbg("bus: Received SR_DF_TRIGGER packet."); 00524 break; 00525 case SR_DF_META: 00526 sr_dbg("bus: Received SR_DF_META packet."); 00527 break; 00528 case SR_DF_LOGIC: 00529 logic = packet->payload; 00530 sr_dbg("bus: Received SR_DF_LOGIC packet (%" PRIu64 " bytes, " 00531 "unitsize = %d).", logic->length, logic->unitsize); 00532 break; 00533 case SR_DF_ANALOG: 00534 analog = packet->payload; 00535 sr_dbg("bus: Received SR_DF_ANALOG packet (%d samples).", 00536 analog->num_samples); 00537 break; 00538 case SR_DF_END: 00539 sr_dbg("bus: Received SR_DF_END packet."); 00540 break; 00541 case SR_DF_FRAME_BEGIN: 00542 sr_dbg("bus: Received SR_DF_FRAME_BEGIN packet."); 00543 break; 00544 case SR_DF_FRAME_END: 00545 sr_dbg("bus: Received SR_DF_FRAME_END packet."); 00546 break; 00547 default: 00548 sr_dbg("bus: Received unknown packet type: %d.", packet->type); 00549 break; 00550 } 00551 } 00552 00553 /** 00554 * Send a packet to whatever is listening on the datafeed bus. 00555 * 00556 * Hardware drivers use this to send a data packet to the frontend. 00557 * 00558 * @param sdi TODO. 00559 * @param packet The datafeed packet to send to the session bus. 00560 * 00561 * @retval SR_OK Success. 00562 * @retval SR_ERR_ARG Invalid argument. 00563 * 00564 * @private 00565 */ 00566 SR_PRIV int sr_session_send(const struct sr_dev_inst *sdi, 00567 const struct sr_datafeed_packet *packet) 00568 { 00569 GSList *l; 00570 struct datafeed_callback *cb_struct; 00571 00572 if (!sdi) { 00573 sr_err("%s: sdi was NULL", __func__); 00574 return SR_ERR_ARG; 00575 } 00576 00577 if (!packet) { 00578 sr_err("%s: packet was NULL", __func__); 00579 return SR_ERR_ARG; 00580 } 00581 00582 for (l = session->datafeed_callbacks; l; l = l->next) { 00583 if (sr_log_loglevel_get() >= SR_LOG_DBG) 00584 datafeed_dump(packet); 00585 cb_struct = l->data; 00586 cb_struct->cb(sdi, packet, cb_struct->cb_data); 00587 } 00588 00589 return SR_OK; 00590 } 00591 00592 /** 00593 * Add an event source for a file descriptor. 00594 * 00595 * @param pollfd The GPollFD. 00596 * @param[in] timeout Max time to wait before the callback is called, 00597 * ignored if 0. 00598 * @param cb Callback function to add. Must not be NULL. 00599 * @param cb_data Data for the callback function. Can be NULL. 00600 * @param poll_object TODO. 00601 * 00602 * @retval SR_OK Success. 00603 * @retval SR_ERR_ARG Invalid argument. 00604 * @retval SR_ERR_MALLOC Memory allocation error. 00605 */ 00606 static int _sr_session_source_add(GPollFD *pollfd, int timeout, 00607 sr_receive_data_callback cb, void *cb_data, gintptr poll_object) 00608 { 00609 struct source *new_sources, *s; 00610 GPollFD *new_pollfds; 00611 00612 if (!cb) { 00613 sr_err("%s: cb was NULL", __func__); 00614 return SR_ERR_ARG; 00615 } 00616 00617 /* Note: cb_data can be NULL, that's not a bug. */ 00618 00619 new_pollfds = g_try_realloc(session->pollfds, 00620 sizeof(GPollFD) * (session->num_sources + 1)); 00621 if (!new_pollfds) { 00622 sr_err("%s: new_pollfds malloc failed", __func__); 00623 return SR_ERR_MALLOC; 00624 } 00625 00626 new_sources = g_try_realloc(session->sources, sizeof(struct source) * 00627 (session->num_sources + 1)); 00628 if (!new_sources) { 00629 sr_err("%s: new_sources malloc failed", __func__); 00630 return SR_ERR_MALLOC; 00631 } 00632 00633 new_pollfds[session->num_sources] = *pollfd; 00634 s = &new_sources[session->num_sources++]; 00635 s->timeout = timeout; 00636 s->cb = cb; 00637 s->cb_data = cb_data; 00638 s->poll_object = poll_object; 00639 session->pollfds = new_pollfds; 00640 session->sources = new_sources; 00641 00642 if (timeout != session->source_timeout && timeout > 0 00643 && (session->source_timeout == -1 || timeout < session->source_timeout)) 00644 session->source_timeout = timeout; 00645 00646 return SR_OK; 00647 } 00648 00649 /** 00650 * Add an event source for a file descriptor. 00651 * 00652 * @param fd The file descriptor. 00653 * @param events Events to check for. 00654 * @param timeout Max time to wait before the callback is called, ignored if 0. 00655 * @param cb Callback function to add. Must not be NULL. 00656 * @param cb_data Data for the callback function. Can be NULL. 00657 * 00658 * @retval SR_OK Success. 00659 * @retval SR_ERR_ARG Invalid argument. 00660 * @retval SR_ERR_MALLOC Memory allocation error. 00661 * 00662 * @since 0.3.0 00663 */ 00664 SR_API int sr_session_source_add(int fd, int events, int timeout, 00665 sr_receive_data_callback cb, void *cb_data) 00666 { 00667 GPollFD p; 00668 00669 p.fd = fd; 00670 p.events = events; 00671 00672 return _sr_session_source_add(&p, timeout, cb, cb_data, (gintptr)fd); 00673 } 00674 00675 /** 00676 * Add an event source for a GPollFD. 00677 * 00678 * @param pollfd The GPollFD. 00679 * @param timeout Max time to wait before the callback is called, ignored if 0. 00680 * @param cb Callback function to add. Must not be NULL. 00681 * @param cb_data Data for the callback function. Can be NULL. 00682 * 00683 * @retval SR_OK Success. 00684 * @retval SR_ERR_ARG Invalid argument. 00685 * @retval SR_ERR_MALLOC Memory allocation error. 00686 * 00687 * @since 0.3.0 00688 */ 00689 SR_API int sr_session_source_add_pollfd(GPollFD *pollfd, int timeout, 00690 sr_receive_data_callback cb, void *cb_data) 00691 { 00692 return _sr_session_source_add(pollfd, timeout, cb, 00693 cb_data, (gintptr)pollfd); 00694 } 00695 00696 /** 00697 * Add an event source for a GIOChannel. 00698 * 00699 * @param channel The GIOChannel. 00700 * @param events Events to poll on. 00701 * @param timeout Max time to wait before the callback is called, ignored if 0. 00702 * @param cb Callback function to add. Must not be NULL. 00703 * @param cb_data Data for the callback function. Can be NULL. 00704 * 00705 * @retval SR_OK Success. 00706 * @retval SR_ERR_ARG Invalid argument. 00707 * @retval SR_ERR_MALLOC Memory allocation error. 00708 * 00709 * @since 0.3.0 00710 */ 00711 SR_API int sr_session_source_add_channel(GIOChannel *channel, int events, 00712 int timeout, sr_receive_data_callback cb, void *cb_data) 00713 { 00714 GPollFD p; 00715 00716 #ifdef _WIN32 00717 g_io_channel_win32_make_pollfd(channel, events, &p); 00718 #else 00719 p.fd = g_io_channel_unix_get_fd(channel); 00720 p.events = events; 00721 #endif 00722 00723 return _sr_session_source_add(&p, timeout, cb, cb_data, (gintptr)channel); 00724 } 00725 00726 /** 00727 * Remove the source belonging to the specified channel. 00728 * 00729 * @todo Add more error checks and logging. 00730 * 00731 * @param poll_object The channel for which the source should be removed. 00732 * 00733 * @retval SR_OK Success 00734 * @retval SR_ERR_ARG Invalid arguments 00735 * @retval SR_ERR_MALLOC Memory allocation error 00736 * @retval SR_ERR_BUG Internal error 00737 */ 00738 static int _sr_session_source_remove(gintptr poll_object) 00739 { 00740 struct source *new_sources; 00741 GPollFD *new_pollfds; 00742 unsigned int old; 00743 00744 if (!session->sources || !session->num_sources) { 00745 sr_err("%s: sources was NULL", __func__); 00746 return SR_ERR_BUG; 00747 } 00748 00749 for (old = 0; old < session->num_sources; old++) { 00750 if (session->sources[old].poll_object == poll_object) 00751 break; 00752 } 00753 00754 /* fd not found, nothing to do */ 00755 if (old == session->num_sources) 00756 return SR_OK; 00757 00758 session->num_sources -= 1; 00759 00760 if (old != session->num_sources) { 00761 memmove(&session->pollfds[old], &session->pollfds[old+1], 00762 (session->num_sources - old) * sizeof(GPollFD)); 00763 memmove(&session->sources[old], &session->sources[old+1], 00764 (session->num_sources - old) * sizeof(struct source)); 00765 } 00766 00767 new_pollfds = g_try_realloc(session->pollfds, sizeof(GPollFD) * session->num_sources); 00768 if (!new_pollfds && session->num_sources > 0) { 00769 sr_err("%s: new_pollfds malloc failed", __func__); 00770 return SR_ERR_MALLOC; 00771 } 00772 00773 new_sources = g_try_realloc(session->sources, sizeof(struct source) * session->num_sources); 00774 if (!new_sources && session->num_sources > 0) { 00775 sr_err("%s: new_sources malloc failed", __func__); 00776 return SR_ERR_MALLOC; 00777 } 00778 00779 session->pollfds = new_pollfds; 00780 session->sources = new_sources; 00781 00782 return SR_OK; 00783 } 00784 00785 /** 00786 * Remove the source belonging to the specified file descriptor. 00787 * 00788 * @param fd The file descriptor for which the source should be removed. 00789 * 00790 * @retval SR_OK Success 00791 * @retval SR_ERR_ARG Invalid argument 00792 * @retval SR_ERR_MALLOC Memory allocation error. 00793 * @retval SR_ERR_BUG Internal error. 00794 * 00795 * @since 0.3.0 00796 */ 00797 SR_API int sr_session_source_remove(int fd) 00798 { 00799 return _sr_session_source_remove((gintptr)fd); 00800 } 00801 00802 /** 00803 * Remove the source belonging to the specified poll descriptor. 00804 * 00805 * @param pollfd The poll descriptor for which the source should be removed. 00806 * 00807 * @return SR_OK upon success, SR_ERR_ARG upon invalid arguments, or 00808 * SR_ERR_MALLOC upon memory allocation errors, SR_ERR_BUG upon 00809 * internal errors. 00810 * 00811 * @since 0.2.0 00812 */ 00813 SR_API int sr_session_source_remove_pollfd(GPollFD *pollfd) 00814 { 00815 return _sr_session_source_remove((gintptr)pollfd); 00816 } 00817 00818 /** 00819 * Remove the source belonging to the specified channel. 00820 * 00821 * @param channel The channel for which the source should be removed. 00822 * 00823 * @retval SR_OK Success. 00824 * @retval SR_ERR_ARG Invalid argument. 00825 * @retval SR_ERR_MALLOC Memory allocation error. 00826 * @return SR_ERR_BUG Internal error. 00827 * 00828 * @since 0.2.0 00829 */ 00830 SR_API int sr_session_source_remove_channel(GIOChannel *channel) 00831 { 00832 return _sr_session_source_remove((gintptr)channel); 00833 } 00834 00835 /** @} */
1.7.6.1