Skip to content

Commit

Permalink
WIP adding stack support for timer
Browse files Browse the repository at this point in the history
  • Loading branch information
sigilante committed Oct 1, 2024
1 parent 500815b commit 047105a
Show file tree
Hide file tree
Showing 5 changed files with 190 additions and 17 deletions.
166 changes: 162 additions & 4 deletions pkg/noun/manage.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@
//
#undef NO_OVERFLOW

/** Global variables.
**/
static timer_stack *stk_u;

/* (u3_noun)setjmp(u3R->esc.buf): setjmp within road.
*/
#if 0
Expand Down Expand Up @@ -376,14 +380,51 @@ _cm_signal_deep(c3_w mil_w)
u3t_boot();
}

/* u3m_timer_set
// Function to add an `itimerval` to a `timeval`
struct timeval __add_itimer(struct timeval base_time, struct itimerval timer) {
struct timeval result;

// Add seconds
result.tv_sec = base_time.tv_sec + timer.it_value.tv_sec;

// Add microseconds
result.tv_usec = base_time.tv_usec + timer.it_value.tv_usec;

// Handle microsecond overflow
if (result.tv_usec >= 1000000) {
result.tv_sec += 1;
result.tv_usec -= 1000000;
}

return result;
}

// Function to calculate the interval between two `timeval` structs
struct itimerval __get_interval(struct timeval start, struct timeval end) {
struct itimerval interval;

// Calculate the difference in seconds and microseconds
interval.it_value.tv_sec = end.tv_sec - start.tv_sec;
interval.it_value.tv_usec = end.tv_usec - start.tv_usec;

// Handle underflow of microseconds (i.e., if end's microseconds < start's microseconds)
if (interval.it_value.tv_usec < 0) {
interval.it_value.tv_sec -= 1;
interval.it_value.tv_usec += 1000000;
}

timerclear(&interval.it_interval);

return interval;
}

/* u3m_timer_set: set interval timer for mil_w milliseconds
*/
void
u3m_timer_set(c3_w mil_w)
{
if ( mil_w ) {
struct itimerval itm_u;

timerclear(&itm_u.it_interval);
itm_u.it_value.tv_sec = (mil_w / 1000);
itm_u.it_value.tv_usec = 1000 * (mil_w % 1000);
Expand All @@ -402,11 +443,122 @@ u3m_timer_set(c3_w mil_w)
void
u3m_timer_clear()
{
struct itimerval itm_u;
rsignal_deinstall_handler(SIGVTALRM);
}

/* u3m_timer_push: set interval timer against walltime
*/
void
u3m_timer_push(c3_w mil_w)
{
fprintf(stderr, "pushing timer %d\n", mil_w);
// get the request timer interval
struct itimerval itm_u;
timerclear(&itm_u.it_interval);
itm_u.it_value.tv_sec = (mil_w / 1000);
itm_u.it_value.tv_usec = 1000 * (mil_w % 1000);
fprintf(stderr, "interval: %d s %d us\n", itm_u.it_value.tv_sec, itm_u.it_value.tv_usec);

// does the stack have anything on it? if it's clean, this is easy:
fprintf(stderr, "checking stack\n");
fprintf(stderr, "checking stack %x\n", stk_u->top);
if (stk_u->top == NULL) {
fprintf(stderr, "no timer on stack\n");
// if not, set the timer and return
if ( rsignal_setitimer(ITIMER_VIRTUAL, &itm_u, 0) ) {
u3l_log("loom: push timer failed %s", strerror(errno));
}
else {
// keep the expiry walltime in the stack
struct timeval tim_u;
gettimeofday(&tim_u, 0);

rsignal_deinstall_handler(SIGVTALRM);
// debugging, TODO remove
c3_d tim_d = 1000000ULL * tim_u.tv_sec + tim_u.tv_usec;
fprintf(stderr, "expiry: %lx us\n", tim_d);

struct timer* new_u = (timer*)u3a_malloc(sizeof(timer));
new_u->wal_u = tim_u;
new_u->nex_u = stk_u->top;
stk_u->top = new_u;

rsignal_install_handler(SIGVTALRM, _cm_signal_handle_alrm);
}
return;
}

// check that it is less than the current remaining interval
struct itimerval cur_u;

rsignal_getitimer(ITIMER_VIRTUAL, &cur_u);
// zero if no timer is set
fprintf(stderr, "current interval: %d s %d us\n", cur_u.it_value.tv_sec, cur_u.it_value.tv_usec);

if (timercmp(&cur_u.it_value, &itm_u.it_value, <)) {
u3l_log("loom: nest timer failed, too large for remaining time %s",
strerror(errno));
}

// otherwise set the timer
struct itimerval rem_u;

timersub(&cur_u.it_value, &itm_u.it_value, &rem_u.it_value);

if ( rsignal_setitimer(ITIMER_VIRTUAL, &itm_u, 0) ) {
u3l_log("loom: nest timer failed %s", strerror(errno));
}
else {
// keep the expiry walltime in the stack
struct timeval tim_u;
gettimeofday(&tim_u, 0);

// debugging, TODO remove
c3_d tim_d = 1000000ULL * tim_u.tv_sec + tim_u.tv_usec;
fprintf(stderr, "expiry: %lx us\n", tim_d);
c3_d cur_d = cur_u.it_value.tv_sec * 1000 + cur_u.it_value.tv_usec / 1000;
fprintf(stderr, "remaining: %lx ms\n", cur_d);

struct timer* new_u = (timer*)u3a_malloc(sizeof(timer));
new_u->wal_u = __add_itimer(tim_u, cur_u);
new_u->nex_u = stk_u->top;
stk_u->top = new_u;

rsignal_install_handler(SIGVTALRM, _cm_signal_handle_alrm);
}
}

/* u3m_timer_pop
*/
void
u3m_timer_pop()
{
if (stk_u->top == NULL) {
u3l_log("loom: no \%jinx timer to pop");
}
else {
timer *old_u = stk_u->top;
stk_u->top = stk_u->top->nex_u;

if (stk_u->top == NULL) {
u3m_timer_clear();
return;
}

struct timeval nex_u = stk_u->top->wal_u;
struct timeval tim_u;
gettimeofday(&tim_u, 0);
struct itimerval itm_u;
itm_u = __get_interval(tim_u, nex_u);

if ( rsignal_setitimer(ITIMER_VIRTUAL, &itm_u, 0) ) {
u3l_log("loom: pop timer failed %s", strerror(errno));
}
else {
rsignal_install_handler(SIGVTALRM, _cm_signal_handle_alrm);
}

free(old_u);
}
}

/* _cm_signal_done():
Expand Down Expand Up @@ -2101,6 +2253,11 @@ u3m_init(size_t len_i)
u3C.wor_i = len_i >> 2;
u3l_log("loom: mapped %zuMB", len_i >> 20);
}

// start %jinx timer stack
//
fprintf(stderr, "jinx: start\r\n");
// stk_u->top = (timer*)NULL;
}

extern void u3je_secp_stop(void);
Expand Down Expand Up @@ -2207,6 +2364,7 @@ u3m_boot(c3_c* dir_c, size_t len_i)
memset(u3A, 0, sizeof(*u3A));
return 0;
}

}

/* u3m_boot_lite(): start without checkpointing.
Expand Down
19 changes: 19 additions & 0 deletions pkg/noun/manage.h
Original file line number Diff line number Diff line change
Expand Up @@ -208,4 +208,23 @@
void
u3m_timer_clear(void);

/* u3m_timer_push: push a timer on the stack.
*/
void
u3m_timer_push(c3_w mil_w);

/* u3m_timer_pop: pop a timer from the stack.
*/
void
u3m_timer_pop(void);

typedef struct timer {
struct timeval wal_u;
struct timer* nex_u;
} timer;

typedef struct timer_stack {
timer* top;
} timer_stack;

#endif /* ifndef U3_MANAGE_H */
20 changes: 7 additions & 13 deletions pkg/noun/nock.c
Original file line number Diff line number Diff line change
Expand Up @@ -1930,18 +1930,12 @@ _n_hint_fore(u3_cell hin, u3_noun bus, u3_noun* clu)
case c3__jinx: {
if (c3y == u3a_is_atom(*clu)) {
// clu is in Urbit time, but we need Unix time
mpz_t clu_mp;
u3r_mp(clu_mp, *clu);
mpz_t urs_mp, tim_mp;
mpz_init(urs_mp);
mpz_init(tim_mp);
mpz_tdiv_q_2exp(tim_mp, clu_mp, 48);
mpz_mul_ui(tim_mp, tim_mp, 1000);
mpz_tdiv_q_2exp(urs_mp, tim_mp, 16);
c3_w mil_w = u3i_mp(urs_mp);
u3m_timer_set(mil_w); // set ITIMER (mil_w is in microseconds)
mpz_clear(clu_mp);
mpz_clear(tim_mp);
c3_d tim_d;
if ( c3y == u3r_safe_chub(*clu, &tim_d) ) {
c3_w mil_w = u3_time_msc_out(tim_d);
fprintf(stderr, "u3t_jinx_time 2: %lld -> %u\n", tim_d, mil_w);
// u3m_timer_push(mil_w);
}
}
u3z(*clu);
*clu = c3__jinx;
Expand Down Expand Up @@ -2009,7 +2003,7 @@ _n_hint_hind(u3_noun tok, u3_noun pro)
{
u3_noun p_tok, q_tok, r_tok;
if (c3__jinx == tok) {
u3m_timer_clear();
u3m_timer_pop();
}
else if ( (c3y == u3r_trel(tok, &p_tok, &q_tok, &r_tok)) && (c3__bout == p_tok) ) {
// get the microseconds elapsed
Expand Down
1 change: 1 addition & 0 deletions pkg/noun/platform/darwin/rsignal.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@
#define rsignal_install_handler signal
#define rsignal_deinstall_handler(sig) signal((sig), SIG_IGN)
#define rsignal_setitimer setitimer
#define rsignal_getitimer getitimer

#endif /* ifndef NOUN_PLATFORM_DARWIN_RSIGNAL_H */
1 change: 1 addition & 0 deletions pkg/noun/platform/linux/rsignal.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@
#define rsignal_install_handler signal
#define rsignal_deinstall_handler(sig) signal((sig), SIG_IGN)
#define rsignal_setitimer setitimer
#define rsignal_getitimer getitimer

#endif /* ifndef NOUN_PLATFORM_LINUX_RSIGNAL_H */

0 comments on commit 047105a

Please sign in to comment.