1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
|
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "elasticarray.h"
#include "events.h"
#include "warnp.h"
#include "tsnetwork.h"
#include "tsnetwork_internal.h"
/* Sleepers. */
struct sleeper {
network_callback * callback;
void * cookie;
void * event_cookie;
};
ELASTICARRAY_DECL(SLEEPERS, sleepers, struct sleeper *);
static SLEEPERS sleepers = NULL;
/* Callback from network_sleep when timer expires. */
static int
callback_timer(void * cookie)
{
struct sleeper * sp = cookie;
/* This callback is no longer pending. */
sp->event_cookie = NULL;
/* Do callback. */
return ((sp->callback)(sp->cookie, NETWORK_STATUS_TIMEOUT));
}
/**
* network_sleep(timeo, callback, cookie):
* Register a callback to be performed by network_select once the specified
* timeout has expired. Return a handle which can be passed to
* network_desleep().
*/
int
network_sleep(struct timeval * timeo,
network_callback * callback, void * cookie)
{
struct sleeper s;
struct sleeper * sp = NULL; /* Silence bogus compiler warnings. */
size_t h;
/* Initialize array if required. */
if (sleepers == NULL) {
if ((sleepers = sleepers_init(0)) == NULL)
goto err0;
}
/* Construct sleeper record. */
s.callback = callback;
s.cookie = cookie;
s.event_cookie = NULL;
/* Search for empty space. */
for (h = 0; h < sleepers_getsize(sleepers); h++) {
sp = *sleepers_get(sleepers, h);
if (sp->event_cookie == NULL) {
/* Use this one. */
memcpy(sp, &s, sizeof(struct sleeper));
break;
}
}
/* If we didn't find an empty space, add a new sleeper. */
if (h == sleepers_getsize(sleepers)) {
/* Don't have too many sleepers... */
if (h == 1024) {
warn0("Too many sleepers");
goto err0;
}
/* Allocate a record. */
if ((sp = malloc(sizeof(struct sleeper))) == NULL)
goto err0;
/* Copy data in. */
memcpy(sp, &s, sizeof(struct sleeper));
/* Append the record. */
if (sleepers_append(sleepers, &sp, 1))
goto err1;
} else {
/*-
* If (h != sleepers_getsize()), then sp was set in the
* earlier 'for' loop, but compilers don't realize it.
*/
assert(sp != NULL);
}
/* Register the timer event. */
if ((sp->event_cookie =
events_timer_register(callback_timer, sp, timeo)) == NULL)
goto err0;
/* Success! */
return ((int)h);
err1:
free(sp);
err0:
/* Failure! */
return (-1);
}
/**
* network_desleep(handle):
* Deregister the callback associated with the provided handle. The
* callback will be called with a status of NETWORK_STATUS_CANCEL.
*/
int
network_desleep(int handle)
{
struct sleeper * sp;
/* Sanity-check the handle. */
if ((handle >= (int)sleepers_getsize(sleepers)) || (handle < 0)) {
warn0("Invalid sleeper handle: %d", handle);
goto err0;
}
/* Grab the relevant sleeper record. */
sp = *sleepers_get(sleepers, (size_t)handle);
/* If there is no timer, return silently. */
if (sp->event_cookie == NULL)
return (0);
/* Cancel the timer. */
events_timer_cancel(sp->event_cookie);
sp->event_cookie = NULL;
/* Invoke the callback. */
return ((sp->callback)(sp->cookie, NETWORK_STATUS_CANCEL));
err0:
/* Failure! */
return (-1);
}
/**
* network_sleep_fini(void):
* Free resources allocated.
*/
void
network_sleep_fini(void)
{
struct sleeper * sp;
size_t i;
/* Nothing to do if we're uninitialized. */
if (sleepers == NULL)
return;
/* Free records. */
for (i = 0; i < sleepers_getsize(sleepers); i++) {
sp = *sleepers_get(sleepers, i);
/* If this sleep is no longer in progress, free the record. */
if (sp->event_cookie == NULL)
free(sp);
}
/* Free the sleepers array. */
sleepers_free(sleepers);
}
|