Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add %jinx hint to Vere. #648

Open
wants to merge 7 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pkg/c3/motes.h
Original file line number Diff line number Diff line change
Expand Up @@ -618,6 +618,7 @@
# define c3__jato c3_s4('j','a','t','o')
# define c3__jet c3_s3('j','e','t')
# define c3__jetd c3_s4('j','e','t','d')
# define c3__jinx c3_s4('j','i','n','x')
# define c3__just c3_s4('j','u','s','t')
# define c3__k c3_s1('k')
# define c3__khan c3_s4('k','h','a','n')
Expand Down
187 changes: 185 additions & 2 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 @@ -197,6 +201,8 @@ _cm_signal_handle_intr(int x)
static void
_cm_signal_handle_alrm(int x)
{
stk_u->top = (timer*)NULL; // clear the timer stack
u3l_log("\%jinx timer expired\r\n");
_cm_signal_handle(c3__alrm);
}

Expand Down Expand Up @@ -367,9 +373,60 @@ _cm_signal_deep(c3_w mil_w)
);
}

u3m_timer_set(mil_w);

// factor into own function, call here and in _n_hint_fore() TODO
// _n_hint_hind() will look like this w/ deinstall handler instead
// return void b/c just clearing timer, no args

u3t_boot();
}

// 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 @@ -381,8 +438,128 @@ _cm_signal_deep(c3_w mil_w)
rsignal_install_handler(SIGVTALRM, _cm_signal_handle_alrm);
}
}
}

u3t_boot();
/* u3m_timer_clear
*/
void
u3m_timer_clear()
{
rsignal_deinstall_handler(SIGVTALRM);
}

/* u3m_timer_push: set interval timer against walltime
*/
void
u3m_timer_push(c3_w 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, "\r\npushing timer for %lu ms at 0x%lx\r\n", mil_w, (c3_d)stk_u->top);

// does the stack have anything on it? if it's clean, this is easy:
if (stk_u->top == NULL) {
// 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);

struct timer* new_u = (timer*)c3_malloc(sizeof(timer));
new_u->wal_u = tim_u;
new_u->nex_u = stk_u->top;
stk_u->top = new_u;
fprintf(stderr, "\r\npushed timer for %lu ms at 0x%lx\r\n", tim_u.tv_sec*1000+tim_u.tv_usec, (c3_d)stk_u->top);

rsignal_install_handler(SIGVTALRM, _cm_signal_handle_alrm);
}
return;
}

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

// if no timer is set this is zero but we shouldn't be here if that's the case
rsignal_getitimer(ITIMER_VIRTUAL, &cur_u);
fprintf(stderr, "current interval: %d s %d us\r\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));
return;
}

// 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: %lu us\r\n", tim_d);
c3_d cur_d = cur_u.it_value.tv_sec * 1000 + cur_u.it_value.tv_usec / 1000;
fprintf(stderr, "remaining: %lu ms\r\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()
{
fprintf(stderr, "popping timer at 0x%lx\r\n", (c3_d)stk_u->top);
if (stk_u->top == NULL) {
u3m_timer_clear();
return;
}
else {
timer *old_u = stk_u->top;
stk_u->top = old_u->nex_u;

if (stk_u->top == NULL) {
// if the stack is empty, simply clear the timer
fprintf(stderr, "no more timers to pop\r\n");
u3m_timer_clear();
c3_free(old_u);
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(nex_u, tim_u);
fprintf(stderr, "remaining interval: %d s %d us\r\n", itm_u.it_value.tv_sec, itm_u.it_value.tv_usec);

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);
}

c3_free(old_u);
}
}

/* _cm_signal_done():
Expand Down Expand Up @@ -2077,6 +2254,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
//
stk_u = (struct timer_stack*)c3_malloc(sizeof(struct timer_stack));
stk_u->top = (timer*)NULL;
}

extern void u3je_secp_stop(void);
Expand Down Expand Up @@ -2183,6 +2365,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
29 changes: 29 additions & 0 deletions pkg/noun/manage.h
Original file line number Diff line number Diff line change
Expand Up @@ -198,4 +198,33 @@
c3_w
u3m_pack(void);

/* u3m_timer_set: set the timer.
*/
void
u3m_timer_set(c3_w mil_w);

/* u3m_timer_clear: clear the timer.
*/
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 */
21 changes: 20 additions & 1 deletion pkg/noun/nock.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
#include "xtract.h"
#include "zave.h"

#include <stdio.h>

// define to have each opcode printed as it executes,
// along with some other debugging info
# undef VERBOSE_BYTECODE
Expand Down Expand Up @@ -1060,6 +1062,7 @@ _n_bint(u3_noun* ops, u3_noun hif, u3_noun nef, c3_o los_o, c3_o tel_o)
case c3__meme:
case c3__nara:
case c3__hela:
case c3__jinx:
case c3__bout: {
u3_noun fen = u3_nul;
c3_w nef_w = _n_comp(&fen, nef, los_o, c3n);
Expand Down Expand Up @@ -1924,6 +1927,19 @@ _n_hint_fore(u3_cell hin, u3_noun bus, u3_noun* clu)
*clu = u3nt(u3k(tag), *clu, now);
} break;

case c3__jinx: {
if (c3y == u3a_is_atom(*clu)) {
// clu is in Urbit time, but we need Unix time
c3_d tim_d[2];
u3r_chubs(0, 2, &tim_d, *clu);
c3_w sec_w = tim_d[1];
c3_w mil_w = u3_time_msc_out(tim_d[0]);
u3m_timer_push(sec_w * 1000 + mil_w);
}
u3z(*clu);
*clu = c3__jinx;
} break;

case c3__nara: {
u3_noun pri, tan;
if ( c3y == u3r_cell(*clu, &pri, &tan) ) {
Expand Down Expand Up @@ -1985,7 +2001,10 @@ static void
_n_hint_hind(u3_noun tok, u3_noun pro)
{
u3_noun p_tok, q_tok, r_tok;
if ( (c3y == u3r_trel(tok, &p_tok, &q_tok, &r_tok)) && (c3__bout == p_tok) ) {
if (c3__jinx == tok) {
u3m_timer_pop();
}
else if ( (c3y == u3r_trel(tok, &p_tok, &q_tok, &r_tok)) && (c3__bout == p_tok) ) {
// get the microseconds elapsed
u3_atom delta = u3ka_sub(u3i_chub(u3t_trace_time()), u3k(r_tok));

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 */
Loading