#include "gw-config.h"#include <stdlib.h>#include <unistd.h>#include <errno.h>#include "gwlib/gwlib.h"Include dependency graph for fdset.c:

Go to the source code of this file.
Data Structures | |
| struct | FDSet |
| struct | action |
Functions | |
| action * | action_create (int type) |
| void | action_destroy (struct action *action) |
| void | action_destroy_item (void *action) |
| void | submit_action (FDSet *set, struct action *action) |
| void | submit_action_nosync (FDSet *set, struct action *action) |
| int | handle_action (FDSet *set, struct action *action) |
| int | find_entry (FDSet *set, int fd) |
| void | remove_entry (FDSet *set, int entry) |
| void | remove_deleted_entries (FDSet *set) |
| void | poller (void *arg) |
| FDSet * | fdset_create_real (long timeout) |
| void | fdset_destroy (FDSet *set) |
| void | fdset_register (FDSet *set, int fd, int events, fdset_callback_t callback, void *data) |
| void | fdset_listen (FDSet *set, int fd, int mask, int events) |
| void | fdset_unregister (FDSet *set, int fd) |
| void | fdset_set_timeout (FDSet *set, long timeout) |
|
|
Definition at line 155 of file fdset.c. References action::callback, action::data, action::done, action::events, action::fd, action::mask, and action::type. Referenced by fdset_destroy(), fdset_listen(), fdset_register(), fdset_set_timeout(), and fdset_unregister(). 00156 {
00157 struct action *new;
00158
00159 new = gw_malloc(sizeof(*new));
00160 new->type = type;
00161 new->fd = -1;
00162 new->mask = 0;
00163 new->events = 0;
00164 new->callback = NULL;
00165 new->data = NULL;
00166 new->done = NULL;
00167
00168 return new;
00169 }
|
|
|
Definition at line 171 of file fdset.c. References action, action::done, and gwlist_destroy(). Referenced by action_destroy_item(), handle_action(), and submit_action(). 00172 {
00173 if (action == NULL)
00174 return;
00175
00176 gwlist_destroy(action->done, NULL);
00177 gw_free(action);
00178 }
|
Here is the call graph for this function:

|
|
Definition at line 181 of file fdset.c. References action, and action_destroy(). Referenced by fdset_destroy(). 00182 {
00183 action_destroy(action);
00184 }
|
Here is the call graph for this function:

|
|
Definition at line 368 of file fdset.c. References FDSet::entries, error(), fdset_destroy(), gwlist_create, gwthread_create, poller(), FDSet::pollinfo, and FDSet::size. Referenced by start_client_threads(), and start_server_thread(). 00369 {
00370 FDSet *new;
00371
00372 new = gw_malloc(sizeof(*new));
00373
00374 /* Start off with space for one element because we can't malloc 0 bytes
00375 * and we don't want to worry about these pointers being NULL. */
00376 new->size = 1;
00377 new->entries = 0;
00378 new->pollinfo = gw_malloc(sizeof(new->pollinfo[0]) * new->size);
00379 new->callbacks = gw_malloc(sizeof(new->callbacks[0]) * new->size);
00380 new->datafields = gw_malloc(sizeof(new->datafields[0]) * new->size);
00381 new->times = gw_malloc(sizeof(new->times[0]) * new->size);
00382 new->timeout = timeout > 0 ? timeout : -1;
00383 new->scanning = 0;
00384 new->deleted_entries = 0;
00385
00386 new->actions = gwlist_create();
00387
00388 new->poll_thread = gwthread_create(poller, new);
00389 if (new->poll_thread < 0) {
00390 error(0, "Could not start internal thread for fdset.");
00391 fdset_destroy(new);
00392 return NULL;
00393 }
00394
00395 return new;
00396 }
|
Here is the call graph for this function:

|
|
Definition at line 398 of file fdset.c. References action_create(), action_destroy_item(), FDSet::actions, FDSet::callbacks, FDSet::datafields, FDSet::entries, error(), gwlist_destroy(), gwlist_len(), gwthread_join(), gwthread_self(), FDSet::poll_thread, FDSet::pollinfo, submit_action(), FDSet::times, and warning(). Referenced by client_shutdown(), fdset_create_real(), handle_action(), http_close_all_ports(), server_shutdown(), and start_client_threads(). 00399 {
00400 if (set == NULL)
00401 return;
00402
00403 if (set->poll_thread < 0 || gwthread_self() == set->poll_thread) {
00404 if (set->entries > 0) {
00405 warning(0, "Destroying fdset with %d active entries.",
00406 set->entries);
00407 }
00408 gw_free(set->pollinfo);
00409 gw_free(set->callbacks);
00410 gw_free(set->datafields);
00411 gw_free(set->times);
00412 if (gwlist_len(set->actions) > 0) {
00413 error(0, "Destroying fdset with %ld pending actions.",
00414 gwlist_len(set->actions));
00415 }
00416 gwlist_destroy(set->actions, action_destroy_item);
00417 gw_free(set);
00418 } else {
00419 long thread = set->poll_thread;
00420 submit_action(set, action_create(DESTROY));
00421 gwthread_join(thread);
00422 }
00423 }
|
Here is the call graph for this function:

|
||||||||||||||||||||
|
Definition at line 470 of file fdset.c. References action, action_create(), action::events, pollfd::events, action::fd, find_entry(), gw_assert, gwthread_self(), LISTEN, action::mask, FDSet::poll_thread, FDSet::pollinfo, pollfd::revents, FDSet::scanning, submit_action(), FDSet::times, and warning(). Referenced by handle_action(), unlocked_register_pollin(), and unlocked_register_pollout(). 00471 {
00472 int entry;
00473
00474 gw_assert(set != NULL);
00475
00476 if (gwthread_self() != set->poll_thread) {
00477 struct action *action;
00478
00479 action = action_create(LISTEN);
00480 action->fd = fd;
00481 action->mask = mask;
00482 action->events = events;
00483 submit_action(set, action);
00484 return;
00485 }
00486
00487 entry = find_entry(set, fd);
00488 if (entry < 0) {
00489 warning(0, "fdset_listen called on unregistered fd %d.", fd);
00490 return;
00491 }
00492
00493 /* Copy the bits from events specified by the mask, and preserve the
00494 * bits not specified by the mask. */
00495 set->pollinfo[entry].events =
00496 (set->pollinfo[entry].events & ~mask) | (events & mask);
00497
00498 /* If poller is currently scanning the array, then change the
00499 * revents field so that the callback function will not be called
00500 * for events we should no longer listen for. The idea is the
00501 * same as for the events field, except that we only turn bits off. */
00502 if (set->scanning) {
00503 set->pollinfo[entry].revents =
00504 set->pollinfo[entry].revents & (events | ~mask);
00505 }
00506
00507 time(&set->times[entry]);
00508 }
|
Here is the call graph for this function:

|
||||||||||||||||||||||||
|
Definition at line 425 of file fdset.c. References action, action_create(), action::callback, FDSet::callbacks, action::data, FDSet::datafields, FDSet::entries, action::events, pollfd::events, action::fd, pollfd::fd, gw_assert, gwthread_self(), FDSet::poll_thread, FDSet::pollinfo, pollfd::revents, FDSet::size, submit_action_nosync(), and FDSet::times. Referenced by conn_register_real(), and handle_action(). 00427 {
00428 int new;
00429
00430 gw_assert(set != NULL);
00431
00432 if (gwthread_self() != set->poll_thread) {
00433 struct action *action;
00434
00435 action = action_create(REGISTER);
00436 action->fd = fd;
00437 action->events = events;
00438 action->callback = callback;
00439 action->data = data;
00440 submit_action_nosync(set, action);
00441 return;
00442 }
00443
00444 gw_assert(set->entries <= set->size);
00445
00446 if (set->entries >= set->size) {
00447 int newsize = set->entries + 1;
00448 set->pollinfo = gw_realloc(set->pollinfo,
00449 sizeof(set->pollinfo[0]) * newsize);
00450 set->callbacks = gw_realloc(set->callbacks,
00451 sizeof(set->callbacks[0]) * newsize);
00452 set->datafields = gw_realloc(set->datafields,
00453 sizeof(set->datafields[0]) * newsize);
00454 set->times = gw_realloc(set->times, sizeof(set->times[0]) * newsize);
00455 set->size = newsize;
00456 }
00457
00458 /* We don't check set->scanning. Adding new entries is not harmful
00459 * because their revents fields are 0. */
00460
00461 new = set->entries++;
00462 set->pollinfo[new].fd = fd;
00463 set->pollinfo[new].events = events;
00464 set->pollinfo[new].revents = 0;
00465 set->callbacks[new] = callback;
00466 set->datafields[new] = data;
00467 time(&set->times[new]);
00468 }
|
Here is the call graph for this function:

|
||||||||||||
|
Set timeout in seconds for this FDSet. Definition at line 547 of file fdset.c. References action, action_create(), gw_assert, gwthread_self(), FDSet::poll_thread, submit_action(), action::timeout, and FDSet::timeout. Referenced by http_set_client_timeout(). 00548 {
00549 gw_assert(set != NULL);
00550
00551 if (gwthread_self() != set->poll_thread) {
00552 struct action *action;
00553
00554 action = action_create(SET_TIMEOUT);
00555 action->timeout = timeout;
00556 submit_action(set, action);
00557 return;
00558 }
00559 set->timeout = timeout;
00560 }
|
Here is the call graph for this function:

|
||||||||||||
|
Definition at line 510 of file fdset.c. References action, action_create(), FDSet::deleted_entries, FDSet::entries, action::fd, pollfd::fd, find_entry(), gw_assert, gwthread_self(), FDSet::poll_thread, FDSet::pollinfo, remove_entry(), FDSet::scanning, submit_action(), and warning(). Referenced by conn_destroy(), conn_unregister(), and handle_action(). 00511 {
00512 int entry;
00513
00514 gw_assert(set != NULL);
00515
00516 if (gwthread_self() != set->poll_thread) {
00517 struct action *action;
00518
00519 action = action_create(UNREGISTER);
00520 action->fd = fd;
00521 submit_action(set, action);
00522 return;
00523 }
00524
00525 /* Remove the entry from the pollinfo array */
00526
00527 entry = find_entry(set, fd);
00528 if (entry < 0) {
00529 warning(0, "fdset_listen called on unregistered fd %d.", fd);
00530 return;
00531 }
00532
00533 if (entry == set->entries - 1) {
00534 /* It's the last entry. We can safely remove it even while
00535 * the array is being scanned, because the scan checks set->entries. */
00536 set->entries--;
00537 } else if (set->scanning) {
00538 /* We can't remove entries because the array is being
00539 * scanned. Mark it as deleted. */
00540 set->pollinfo[entry].fd = -1;
00541 set->deleted_entries++;
00542 } else {
00543 remove_entry(set, entry);
00544 }
00545 }
|
Here is the call graph for this function:

|
||||||||||||
|
Definition at line 269 of file fdset.c. References FDSet::entries, pollfd::fd, gw_assert, gwthread_self(), FDSet::poll_thread, and FDSet::pollinfo. Referenced by fdset_listen(), and fdset_unregister(). 00270 {
00271 int i;
00272
00273 gw_assert(set != NULL);
00274 gw_assert(gwthread_self() == set->poll_thread);
00275
00276 for (i = 0; i < set->entries; i++) {
00277 if (set->pollinfo[i].fd == fd)
00278 return i;
00279 }
00280
00281 return -1;
00282 }
|
Here is the call graph for this function:

|
||||||||||||
|
Definition at line 226 of file fdset.c. References action, action_destroy(), action::callback, action::data, action::done, action::events, action::fd, fdset_destroy(), fdset_listen(), fdset_register(), fdset_unregister(), gw_assert, gwlist_produce(), gwthread_self(), LISTEN, action::mask, panic, FDSet::poll_thread, result, action::timeout, FDSet::timeout, and action::type. Referenced by poller(). 00227 {
00228 int result;
00229
00230 gw_assert(set != NULL);
00231 gw_assert(set->poll_thread == gwthread_self());
00232 gw_assert(action != NULL);
00233
00234 result = 0;
00235
00236 switch (action->type) {
00237 case REGISTER:
00238 fdset_register(set, action->fd, action->events,
00239 action->callback, action->data);
00240 break;
00241 case LISTEN:
00242 fdset_listen(set, action->fd, action->mask, action->events);
00243 break;
00244 case UNREGISTER:
00245 fdset_unregister(set, action->fd);
00246 break;
00247 case DESTROY:
00248 fdset_destroy(set);
00249 result = -1;
00250 break;
00251 case SET_TIMEOUT:
00252 set->timeout = action->timeout;
00253 break;
00254 default:
00255 panic(0, "fdset: handle_action got unknown action type %d.",
00256 action->type);
00257 }
00258
00259 if (action->done == NULL)
00260 action_destroy(action);
00261 else
00262 gwlist_produce(action->done, action);
00263
00264 return result;
00265 }
|
Here is the call graph for this function:

|
|
Definition at line 318 of file fdset.c. References action, FDSet::actions, FDSet::callbacks, FDSet::datafields, debug(), FDSet::deleted_entries, FDSet::entries, error(), pollfd::fd, gw_assert, gwlist_extract_first(), gwthread_poll(), gwthread_sleep(), handle_action(), FDSet::pollinfo, remove_deleted_entries(), pollfd::revents, FDSet::scanning, FDSet::timeout, and FDSet::times. Referenced by fdset_create_real(). 00319 {
00320 FDSet *set = arg;
00321 struct action *action;
00322 int ret;
00323 int i;
00324 time_t now;
00325
00326 gw_assert(set != NULL);
00327
00328 for (;;) {
00329 while ((action = gwlist_extract_first(set->actions)) != NULL) {
00330 /* handle_action returns -1 if the set was destroyed. */
00331 if (handle_action(set, action) < 0)
00332 return;
00333 }
00334
00335 /* Block for defined timeout, waiting for activity */
00336 ret = gwthread_poll(set->pollinfo, set->entries, set->timeout);
00337
00338 if (ret < 0) {
00339 if (errno != EINTR) {
00340 error(errno, "Poller: can't handle error; sleeping 1 second.");
00341 gwthread_sleep(1.0);
00342 }
00343 continue;
00344 }
00345 time(&now);
00346 /* Callbacks may modify the table while we scan it, so be careful. */
00347 set->scanning = 1;
00348 for (i = 0; i < set->entries; i++) {
00349 if (set->pollinfo[i].revents != 0) {
00350 set->callbacks[i](set->pollinfo[i].fd,
00351 set->pollinfo[i].revents,
00352 set->datafields[i]);
00353 /* update event time */
00354 time(&set->times[i]);
00355 } else if (set->timeout > 0 && difftime(set->times[i] + set->timeout, now) <= 0) {
00356 debug("gwlib.fdset", 0, "Timeout for fd:%d appeares.", set->pollinfo[i].fd);
00357 set->callbacks[i](set->pollinfo[i].fd, POLLERR, set->datafields[i]);
00358 }
00359 }
00360 set->scanning = 0;
00361
00362 if (set->deleted_entries > 0)
00363 remove_deleted_entries(set);
00364 }
00365 }
|
Here is the call graph for this function:

|
|
Definition at line 297 of file fdset.c. References FDSet::deleted_entries, FDSet::entries, pollfd::fd, FDSet::pollinfo, and remove_entry(). Referenced by poller(). 00298 {
00299 int i;
00300
00301 i = 0;
00302 while (i < set->entries && set->deleted_entries > 0) {
00303 if (set->pollinfo[i].fd < 0) {
00304 remove_entry(set, i);
00305 set->deleted_entries--;
00306 } else {
00307 i++;
00308 }
00309 }
00310 }
|
Here is the call graph for this function:

|
||||||||||||
|
Definition at line 284 of file fdset.c. References FDSet::callbacks, FDSet::datafields, FDSet::entries, FDSet::pollinfo, and FDSet::times. Referenced by fdset_unregister(), and remove_deleted_entries(). 00285 {
00286 if (entry != set->entries - 1) {
00287 /* We need to keep the array contiguous, so move the last element
00288 * to fill in the hole. */
00289 set->pollinfo[entry] = set->pollinfo[set->entries - 1];
00290 set->callbacks[entry] = set->callbacks[set->entries - 1];
00291 set->datafields[entry] = set->datafields[set->entries - 1];
00292 set->times[entry] = set->times[set->entries - 1];
00293 }
00294 set->entries--;
00295 }
|
|
||||||||||||
|
Definition at line 191 of file fdset.c. References action, action_destroy(), FDSet::actions, action::done, gw_assert, gwlist_add_producer(), gwlist_append(), gwlist_consume(), gwlist_create, gwthread_wakeup(), and FDSet::poll_thread. Referenced by fdset_destroy(), fdset_listen(), fdset_set_timeout(), and fdset_unregister(). 00192 {
00193 List *done;
00194 void *sync;
00195
00196 gw_assert(set != NULL);
00197 gw_assert(action != NULL);
00198
00199 done = gwlist_create();
00200 gwlist_add_producer(done);
00201
00202 action->done = done;
00203
00204 gwlist_append(set->actions, action);
00205 gwthread_wakeup(set->poll_thread);
00206
00207 sync = gwlist_consume(done);
00208 gw_assert(sync == action);
00209
00210 action_destroy(action);
00211 }
|
Here is the call graph for this function:

|
||||||||||||
|
Definition at line 216 of file fdset.c. References action, FDSet::actions, gwlist_append(), gwthread_wakeup(), and FDSet::poll_thread. Referenced by fdset_register(). 00217 {
00218 gwlist_append(set->actions, action);
00219 gwthread_wakeup(set->poll_thread);
00220 }
|
Here is the call graph for this function:
