Main Page | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

fdset.c File Reference

#include "gw-config.h"
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include "gwlib/gwlib.h"

Include dependency graph for fdset.c:

Include dependency graph

Go to the source code of this file.

Data Structures

struct  FDSet
struct  action

Functions

actionaction_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)
FDSetfdset_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)


Function Documentation

struct action* action_create int  type  )  [static]
 

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 }

void action_destroy struct action action  )  [static]
 

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:

void action_destroy_item void *  action  )  [static]
 

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:

FDSet* fdset_create_real long  timeout  ) 
 

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:

void fdset_destroy FDSet set  ) 
 

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:

void fdset_listen FDSet set,
int  fd,
int  mask,
int  events
 

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:

void fdset_register FDSet set,
int  fd,
int  events,
fdset_callback_t  callback,
void *  data
 

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:

void fdset_set_timeout FDSet set,
long  timeout
 

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:

void fdset_unregister FDSet set,
int  fd
 

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:

int find_entry FDSet set,
int  fd
[static]
 

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:

int handle_action FDSet set,
struct action action
[static]
 

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:

void poller void *  arg  )  [static]
 

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:

void remove_deleted_entries FDSet set  )  [static]
 

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:

void remove_entry FDSet set,
int  entry
[static]
 

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 }

void submit_action FDSet set,
struct action action
[static]
 

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:

void submit_action_nosync FDSet set,
struct action action
[static]
 

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:

See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.