#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include "isns_server.h"
#include "isns_protocol.h"
#include "isns_log.h"
#include "isns_sched.h"
#include "isns_scn.h"
#include "isns_esi.h"
pthread_mutex_t el_mtx = PTHREAD_MUTEX_INITIALIZER;
static el_key_t **il;
static int icurr = 0;
static el_notice_t *curr = NULL;
static uint32_t DU;
static uint32_t DT;
static uint32_t LB;
static uint32_t NLIM;
static void
il_shift(
uint32_t t
)
{
el_notice_t *fn, *n;
el_key_t *fk, *k;
uint32_t nt;
int c;
k = il[icurr];
while (k->time < t) {
fk = k;
fn = k->notice;
fk->left->right = fk->right;
fk->right->left = fk->left;
fn->pred->sucd = fn->sucd;
fn->sucd->pred = fn->pred;
k = il[(icurr + DU - 1) % DU];
if (k->time < INFINITY - DT) {
nt = k->time + DT;
} else {
nt = INFINITY - 1;
}
while (k->time < nt) {
k = k->right;
}
n = k->notice->pred;
c = 1;
while (n->time >= nt) {
c ++;
n = n->pred;
}
n = n->sucd;
LB = fk->time;
fk->time = nt;
fk->count = k->count - c + 1;
fk->left = k->left;
fk->right = k;
k->left->right = fk;
k->left = fk;
k->count = c;
fn->time = nt;
fn->pred = n->pred;
fn->sucd = n;
n->pred->sucd = fn;
n->pred = fn;
icurr = (icurr + 1) % DU;
k = il[icurr];
}
}
int
el_init(
uint32_t du,
uint32_t dt,
uint32_t nlim
)
{
el_key_t *k, *kleft;
el_notice_t *n, *npred;
uint32_t t = 0;
int i;
if (du < 1 || dt < 1 || nlim < 1) {
return (1);
}
DU = du;
DT = dt;
LB = 0;
NLIM = nlim;
n = (el_notice_t *)malloc(sizeof (el_notice_t));
if (n == NULL) {
return (1);
}
n->time = LB;
n->event = NULL;
n->isdummy = 1;
n->pred = NULL;
npred = n;
k = (el_key_t *)malloc(sizeof (el_key_t));
if (k == NULL) {
return (1);
}
k->time = LB;
k->count = 1;
k->notice = n;
k->left = NULL;
kleft = k;
n->key = k;
il = (el_key_t **)malloc((DU + 1) * sizeof (el_key_t *));
if (il == NULL) {
return (1);
}
for (i = 0; i < DU; i++) {
t += DT;
n = (el_notice_t *)malloc(sizeof (el_notice_t));
if (n == NULL) {
return (1);
}
n->time = t;
n->event = NULL;
n->isdummy = 1;
n->pred = npred;
npred->sucd = n;
npred = n;
k = (el_key_t *)malloc(sizeof (el_key_t));
if (k == NULL) {
return (1);
}
k->time = t;
k->count = 1;
k->notice = n;
k->left = kleft;
kleft->right = k;
kleft = k;
n->key = k;
il[i] = k;
}
n = (el_notice_t *)malloc(sizeof (el_notice_t));
if (n == NULL) {
return (1);
}
n->time = INFINITY;
n->event = NULL;
n->isdummy = 1;
n->pred = npred;
n->sucd = NULL;
npred->sucd = n;
k = (el_key_t *)malloc(sizeof (el_key_t));
if (k == NULL) {
return (1);
}
k->time = INFINITY;
k->count = 1;
k->notice = n;
k->left = kleft;
k->right = NULL;
kleft->right = k;
n->key = k;
il[DU] = k;
return (0);
}
int
el_add(
void *ev,
uint32_t t,
void **evp
)
{
int ec = 0;
uint32_t t1 = 0;
int i, j;
el_key_t *k;
el_notice_t *n;
el_key_t *y;
el_notice_t *x;
(void) pthread_mutex_lock(&el_mtx);
if (evf_again(ev) != 0) {
if (evf_rem(ev) == 0 &&
evp != NULL &&
(curr == NULL || t <= curr->time)) {
*evp = ev;
goto add_done;
}
evl_strip(ev);
if (evf_rem(ev) != 0) {
ev_free(ev);
goto add_done;
}
}
if (t == 0) {
t = ev_intval(ev);
if (evf_init(ev) || evf_again(ev)) {
t1 = get_stopwatch(evf_wakeup(ev));
il_shift(t1);
if (t1 >= INFINITY - t) {
t1 = INFINITY - t1 - 1;
}
}
t += t1;
}
i = (t - LB) / DT;
if (i >= DU) {
i = DU;
} else {
i = (i + icurr) % DU;
}
k = (il[i])->left;
while (k->time > t) {
k = k->left;
}
k = k->right;
if (k->count == NLIM) {
y = (el_key_t *)malloc(sizeof (el_key_t));
if (y == NULL) {
ec = ISNS_RSP_INTERNAL_ERROR;
goto add_done;
}
k->count = NLIM / 2;
x = k->notice;
for (j = 1; j <= NLIM / 2; j++) {
x = x->pred;
}
y->time = x->time;
y->count = NLIM - NLIM / 2;
y->notice = x;
y->right = k;
y->left = k->left;
k->left->right = y;
k->left = y;
x->key = y;
if (y->time > t) {
k = y;
}
}
x = (el_notice_t *)malloc(sizeof (el_notice_t));
if (x == NULL) {
ec = ISNS_RSP_INTERNAL_ERROR;
goto add_done;
}
x->time = t;
x->event = ev;
x->isdummy = 0;
x->key = NULL;
n = k->notice;
while (n->time > t) {
n = n->pred;
}
x->pred = n;
x->sucd = n->sucd;
n->sucd->pred = x;
n->sucd = x;
k->count ++;
if (curr == NULL || curr->time > t) {
curr = x;
}
evf_zero(ev);
isnslog(LOG_DEBUG, "el_add", "%s [%d] is scheduled at %d.",
((ev_t *)ev)->type == EV_ESI ? "ESI" : "REG_EXP",
((ev_t *)ev)->uid,
t);
add_done:
(void) pthread_mutex_unlock(&el_mtx);
if (ec != 0) {
ev_free(ev);
isnslog(LOG_DEBUG, "el_add", "failed, no memory.");
}
return (ec);
}
int
el_remove(
uint32_t id1,
uint32_t id2,
int pending
)
{
el_key_t *k, *kl, *kr;
el_notice_t *n, *n2;
(void) pthread_mutex_lock(&el_mtx);
if (evl_remove(id1, id2, pending) != 0) {
(void) pthread_mutex_unlock(&el_mtx);
return (0);
}
n = curr;
while (n != NULL) {
if (!n->isdummy && ev_match(n->event, id1) != 0) {
if (ev_remove(n->event, id2, 1, pending) == 0) {
k = n->key;
if (k != NULL && k->count == 1) {
k->left->right = k->right;
k->right->left = k->left;
free(k);
} else {
if (k != NULL) {
k->notice = n->pred;
k->notice->key = k;
k->time = k->notice->time;
}
n2 = n;
k = n2->key;
while (k == NULL) {
n2 = n2->sucd;
k = n2->key;
}
k->count --;
kl = k->left;
kr = k->right;
if (!kl->notice->isdummy &&
(kl->count + k->count) <= NLIM) {
k->count += kl->count;
k->left = kl->left;
k->left->right = k;
kl->notice->key = NULL;
free(kl);
} else if (!k->notice->isdummy &&
(kr->count + k->count) <= NLIM) {
kr->count += k->count;
kr->left = k->left;
kr->left->right = kr;
k->notice->key = NULL;
free(k);
}
}
n->pred->sucd = n->sucd;
n->sucd->pred = n->pred;
if (n == curr) {
n2 = n->sucd;
while (n2 != NULL && n2->isdummy) {
n2 = n2->sucd;
}
curr = n2;
}
free(n);
}
break;
}
n = n->sucd;
}
(void) pthread_mutex_unlock(&el_mtx);
return (0);
}
void *
el_first(
uint32_t *t
)
{
void *p = NULL;
el_notice_t *n;
el_key_t *k;
(void) pthread_mutex_lock(&el_mtx);
if (curr != NULL) {
curr->pred->sucd = curr->sucd;
curr->sucd->pred = curr->pred;
n = curr;
while (n->key == NULL) {
n = n->sucd;
}
k = n->key;
k->count --;
if (k->count == 0) {
k->left->right = k->right;
k->right->left = k->left;
free(k);
}
n = curr->sucd;
while (n != NULL && n->isdummy) {
n = n->sucd;
}
*t = curr->time;
p = curr->event;
free(curr);
curr = n;
}
if (p) {
evl_append(p);
}
(void) pthread_mutex_unlock(&el_mtx);
if (p) {
isnslog(LOG_DEBUG, "el_first", "%s [%d] is fetched.",
((ev_t *)p)->type == EV_ESI ? "ESI" : "REG_EXP",
((ev_t *)p)->uid);
}
return (p);
}