Merge pull request #1671 from urbit/term-spin-on-loop

rewrites the terminal spinner on the main loop
This commit is contained in:
Jared Tobin 2019-08-29 04:14:40 -02:30 committed by GitHub
commit f39952d75f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 151 additions and 232 deletions

View File

@ -384,14 +384,12 @@
} fut;
struct {
uv_thread_t* sit_u; // spinner thread
c3_o diz_o; // spinner activated
c3_d eve_d; // spinner start tick (unix μs)
c3_d end_d; // spinner end tick (unix μs)
c3_c* why_c; // spinner event wire (root only)
} sun;
uv_mutex_t mex_u; // mutex for non-daemon term state
uv_timer_t tim_u; // spinner timeout
c3_o diz_o; // spinner activated
c3_d eve_d; // spin count
c3_d end_d; // spinner end tick (ms)
c3_c* why_c; // spinner label
} sun_u;
} u3_utat;
struct _u3_umon;
@ -871,7 +869,7 @@
/* u3_term_start_spinner(): prepare spinner state. RETAIN.
*/
void
u3_term_start_spinner(u3_noun ovo);
u3_term_start_spinner(c3_c* why_c, c3_o now_o);
/* u3_term_stop_spinner(): reset spinner state and restore input line.
*/

View File

@ -658,6 +658,54 @@ _pier_work_release(u3_writ* wit_u)
}
}
/* _pier_work_spin_start(): activate spinner.
*/
static void
_pier_work_spin_start(u3_writ* wit_u)
{
u3_pier* pir_u = wit_u->pir_u;
c3_o now_o = c3n;
c3_c* why_c = 0;
if ( wit_u->evt_d <= pir_u->lif_d ) {
why_c = strdup("nock");
}
else {
u3_noun why;
// second item of the event wire
//
// i.t.p.q:*(pair @da ovum)
//
if ( u3_none != (why = u3r_at(26, wit_u->job)) ) {
u3_noun cad, tag, lag;
if ( c3__term != why ) {
why_c = u3r_string(why);
}
else if ( ( u3_none != (cad = u3r_at(7, wit_u->job)) ) &&
( u3_none != (tag = u3r_at(2, cad)) ) &&
( u3_none != (lag = u3r_at(6, cad)) ) &&
( c3__belt == tag ) &&
( c3__ret == lag ) )
{
now_o = c3y;
}
}
}
u3_term_start_spinner(why_c, now_o);
}
/* _pier_work_spin_stop(): deactivate spinner.
*/
static void
_pier_work_spin_stop(u3_writ* wit_u)
{
u3_term_stop_spinner();
}
/* _pier_work_complete(): worker reported completion.
*/
static void
@ -680,9 +728,7 @@ _pier_work_complete(u3_writ* wit_u,
c3_assert(wit_u->act == 0);
wit_u->act = act;
if ( wit_u->evt_d > pir_u->lif_d ) {
u3_term_stop_spinner();
}
_pier_work_spin_stop(wit_u);
}
/* _pier_work_replace(): worker reported replacement.
@ -720,9 +766,7 @@ _pier_work_replace(u3_writ* wit_u,
god_u->sen_d -= 1ULL;
}
if ( wit_u->evt_d > pir_u->lif_d ) {
u3_term_stop_spinner();
}
_pier_work_spin_stop(wit_u);
}
/* _pier_work_compute(): dispatch for processing.
@ -746,9 +790,7 @@ _pier_work_compute(u3_writ* wit_u)
god_u->sen_d += 1;
if ( wit_u->evt_d > pir_u->lif_d ) {
u3_term_start_spinner(wit_u->job);
}
_pier_work_spin_start(wit_u);
}
/* _pier_work_play(): with active worker, create or load log.

View File

@ -15,28 +15,23 @@
#include "all.h"
#include "vere/vere.h"
static void _term_spinner_cb(void*);
static void _term_read_cb(uv_stream_t* tcp_u,
ssize_t siz_i,
const uv_buf_t * buf_u);
static inline void _term_suck(u3_utty*, const c3_y*, ssize_t);
static u3_utty* _term_main();
static c3_i _term_tcsetattr(int, int, const struct termios *);
static void _term_read_cb(uv_stream_t* tcp_u,
ssize_t siz_i,
const uv_buf_t* buf_u);
static c3_i _term_tcsetattr(int, int, const struct termios *);
#define _SPIN_COOL_US 500000 // spinner activation delay when cool
#define _SPIN_WARM_US 50000 // spinner activation delay when warm
#define _SPIN_RATE_US 250000 // spinner rate (microseconds/frame)
#define _SPIN_IDLE_US 500000 // spinner cools down if stopped this long
static void _write(int fd, const void *buf, size_t count)
/* _write(): wraps write(), asserting length
*/
static void
_write(c3_i fid_i, const void* buf_v, size_t len)
{
if (count != write(fd, buf, count)){
if ( len != write(fid_i, buf_v, len) ){
u3l_log("write failed\r\n");
c3_assert(0);
}
}
/* _term_msc_out_host(): unix microseconds from current host time.
*/
static c3_d
@ -254,25 +249,11 @@ u3_term_io_init()
}
}
// Start spinner thread.
// initialize spinner timeout (if not in daemon-mode)
//
{
uty_u->tat_u.sun.sit_u = (uv_thread_t*)malloc(sizeof(uv_thread_t));
if ( uty_u->tat_u.sun.sit_u ) {
uv_mutex_init(&uty_u->tat_u.mex_u);
uv_mutex_lock(&uty_u->tat_u.mex_u);
c3_w ret_w = uv_thread_create(uty_u->tat_u.sun.sit_u,
_term_spinner_cb,
uty_u);
if ( 0 != ret_w ) {
u3l_log("term: spinner start: %s\n", uv_strerror(ret_w));
free(uty_u->tat_u.sun.sit_u);
uty_u->tat_u.sun.sit_u = NULL;
uv_mutex_unlock(&uty_u->tat_u.mex_u);
uv_mutex_destroy(&uty_u->tat_u.mex_u);
}
}
if ( c3n == u3_Host.ops_u.dem ) {
uv_timer_init(u3L, &uty_u->tat_u.sun_u.tim_u);
uty_u->tat_u.sun_u.tim_u.data = uty_u;
}
}
}
@ -288,7 +269,7 @@ void
u3_term_io_exit(void)
{
if ( c3y == u3_Host.ops_u.dem ) {
uv_close((uv_handle_t*)&u3_Host.uty_u->pop_u, NULL);
uv_close((uv_handle_t*)&u3_Host.uty_u->pop_u, 0);
}
else {
u3_utty* uty_u;
@ -303,25 +284,7 @@ u3_term_io_exit(void)
}
_write(uty_u->fid_i, "\r\n", 2);
#if 0
if ( uty_u->tat_u.sun.sit_u ) {
uv_thread_t* sit_u = uty_u->tat_u.sun.sit_u;
uty_u->tat_u.sun.sit_u = NULL;
uv_mutex_unlock(&uty_u->tat_u.mex_u);
// XX can block exit waiting for wakeup (max _SPIN_COOL_US)
c3_w ret_w;
if ( 0 != (ret_w = uv_thread_join(sit_u)) ) {
u3l_log("term: spinner exit: %s\n", uv_strerror(ret_w));
}
else {
uv_mutex_destroy(&uty_u->tat_u.mex_u);
}
free(sit_u);
}
#endif
uv_close((uv_handle_t*)&uty_u->tat_u.sun_u.tim_u, 0);
}
}
}
@ -353,25 +316,17 @@ _term_it_buf(c3_w len_w, const c3_y* hun_y)
return buf_u;
}
/* An unusual lameness in libuv.
*/
typedef struct {
uv_write_t wri_u;
c3_y* buf_y;
} _u3_write_t;
/* _term_write_cb(): general write callback.
*/
static void
_term_write_cb(uv_write_t* wri_u, c3_i sas_i)
{
_u3_write_t* ruq_u = (void *)wri_u;
if ( 0 != sas_i ) {
// u3l_log("term: write: ERROR\n");
u3l_log("term: write: %s\n", uv_strerror(sas_i));
}
free(ruq_u->buf_y);
free(ruq_u);
free(wri_u->data);
free(wri_u);
}
/* _term_it_write_buf(): write buffer uv style.
@ -379,17 +334,16 @@ _term_write_cb(uv_write_t* wri_u, c3_i sas_i)
static void
_term_it_write_buf(u3_utty* uty_u, uv_buf_t buf_u)
{
_u3_write_t* ruq_u = (_u3_write_t*) c3_malloc(sizeof(_u3_write_t));
ruq_u->buf_y = (c3_y*)buf_u.base;
uv_write_t* wri_u = c3_malloc(sizeof(uv_write_t));
wri_u->data = buf_u.base;
c3_w ret_w;
if ( 0 != (ret_w = uv_write(&ruq_u->wri_u,
if ( 0 != (ret_w = uv_write(wri_u,
(uv_stream_t*)&(uty_u->pop_u),
&buf_u, 1,
_term_write_cb)) )
_term_write_cb)) )
{
u3l_log("terminal: %s\n", uv_strerror(ret_w));
u3l_log("term: write: %s\n", uv_strerror(ret_w));
}
}
@ -780,11 +734,11 @@ _term_read_cb(uv_stream_t* tcp_u,
free(buf_u->base);
}
/* _term_try_write_str(): write null-terminated string (off-thread, retain).
/* _term_spin_write_str(): write null-terminated string
*/
static void
_term_try_write_str(u3_utty* uty_u,
const c3_c* str_c)
_term_spin_write_str(u3_utty* uty_u,
const c3_c* str_c)
{
// c3_i fid_i = uv_fileno(&uty_u->pop_u);
c3_i fid_i = uty_u->pop_u.io_watcher.fd; // XX old libuv
@ -795,30 +749,31 @@ _term_try_write_str(u3_utty* uty_u,
}
}
/* _term_try_move_left(): move the cursor left (off-thread).
/* _term_spin_move_left(): move the cursor left
*/
static void
_term_try_move_left(u3_utty* uty_u)
_term_spin_move_left(u3_utty* uty_u)
{
_term_try_write_str(uty_u, (const c3_c*)uty_u->ufo_u.out.cub1_y);
_term_spin_write_str(uty_u, (const c3_c*)uty_u->ufo_u.out.cub1_y);
}
/* _term_show_spinner(): render spinner (off-thread).
/* _term_spin_timer_cb(): render spinner
*/
static void
_term_show_spinner(u3_utty* uty_u, c3_d lag_d)
_term_spin_timer_cb(uv_timer_t* tim_u)
{
if ( 0 == uty_u->tat_u.sun.eve_d ) {
u3_utty* uty_u = tim_u->data;
u3_utat* tat_u = &uty_u->tat_u;
c3_w cus_w = tat_u->mir.cus_w;
c3_l col_l = tat_u->siz.col_l;
if ( cus_w >= col_l ) { // shenanigans!
return;
}
c3_w cus_w = uty_u->tat_u.mir.cus_w;
if ( cus_w >= uty_u->tat_u.siz.col_l ) { // shenanigans!
return;
}
c3_w bac_w = uty_u->tat_u.siz.col_l - 1 - cus_w; // backoff from end of line
c3_w bac_w = col_l - 1 - cus_w; // backoff from end of line
c3_d lag_d = tat_u->sun_u.eve_d++;
const c3_c daz_c[] = "|/-\\";
const c3_c dal_c[] = "\xc2\xab";
@ -829,109 +784,75 @@ _term_show_spinner(u3_utty* uty_u, c3_d lag_d)
c3_c* cur_c = buf_c;
*cur_c++ = daz_c[(lag_d / _SPIN_RATE_US) % strlen(daz_c)];
*cur_c++ = daz_c[lag_d % strlen(daz_c)];
c3_w sol_w = 1; // spinner length (utf-32)
c3_c* why_c = uty_u->tat_u.sun.why_c;
if ( why_c && strlen(why_c) <= 4 ) {
strcpy(cur_c, dal_c);
cur_c += strlen(dal_c);
if ( tat_u->sun_u.why_c ) {
strncpy(cur_c, dal_c, 2);
cur_c += 2;
sol_w += 1; // length of dal_c (utf-32)
c3_w wel_w = strlen(why_c);
strcpy(cur_c, why_c);
cur_c += wel_w;
sol_w += wel_w;
// c3_w wel_w = strlen(tat_u.sun_u->why_c);
strncpy(cur_c, tat_u->sun_u.why_c, 4);
cur_c += 4;
sol_w += 4; // XX assumed utf-8
strcpy(cur_c, dar_c);
cur_c += strlen(dar_c);
strncpy(cur_c, dar_c, 2);
cur_c += 2;
sol_w += 1; // length of dar_c (utf-32)
}
*cur_c = '\0';
// One-time cursor backoff.
if ( c3n == uty_u->tat_u.sun.diz_o ) {
// One-time cursor backoff.
if ( c3n == tat_u->sun_u.diz_o ) {
c3_w i_w;
for ( i_w = bac_w; i_w < sol_w; i_w++ ) {
_term_try_move_left(uty_u);
_term_spin_move_left(uty_u);
}
}
_term_try_write_str(uty_u, buf_c);
uty_u->tat_u.sun.diz_o = c3y;
_term_spin_write_str(uty_u, buf_c);
tat_u->sun_u.diz_o = c3y;
// Cursor stays on spinner.
while ( sol_w-- ) {
_term_try_move_left(uty_u);
_term_spin_move_left(uty_u);
}
}
/* _term_start_spinner(): prepare spinner state. RETAIN.
*/
static void
_term_start_spinner(u3_utty* uty_u, u3_noun ovo)
{
uty_u->tat_u.sun.diz_o = c3n;
#define _SPIN_COOL_US 500UL // spinner activation delay when cool
#define _SPIN_WARM_US 50UL // spinner activation delay when warm
#define _SPIN_RATE_US 250UL // spinner rate (ms/frame)
#define _SPIN_IDLE_US 500UL // spinner cools down if stopped this long
c3_d now_d = _term_msc_out_host();
// If we receive an event shortly after a previous spin, use a shorter delay
// to avoid giving the impression of a half-idle system.
//
c3_d lag_d;
if ( now_d - uty_u->tat_u.sun.end_d < _SPIN_IDLE_US ) {
lag_d = _SPIN_WARM_US;
}
else {
lag_d = _SPIN_COOL_US;
}
// second item of the event wire
//
u3_noun why = u3h(u3t(u3h(u3t(ovo))));
if ( c3__term == why ) {
u3_noun eve = u3t(u3t(ovo));
if ( c3__belt == u3h(eve) && c3__ret == u3h(u3t(eve)) ) {
lag_d = 0; // No delay for %ret.
}
}
else {
uty_u->tat_u.sun.why_c = (c3_c*)u3r_string(why);
}
uty_u->tat_u.sun.eve_d = now_d + lag_d;
uv_mutex_unlock(&uty_u->tat_u.mex_u);
}
/* u3_term_stop_spinner(): reset spinner state and restore input line.
*/
static void
_term_stop_spinner(u3_utty* uty_u)
{
uv_mutex_lock(&uty_u->tat_u.mex_u);
if ( c3y == uty_u->tat_u.sun.diz_o ) {
_term_it_refresh_line(uty_u);
uty_u->tat_u.sun.end_d = _term_msc_out_host();
}
else {
uty_u->tat_u.sun.end_d = 0;
}
uty_u->tat_u.sun.diz_o = c3n;
uty_u->tat_u.sun.eve_d = 0;
free(uty_u->tat_u.sun.why_c);
uty_u->tat_u.sun.why_c = NULL;
}
/* u3_term_start_spinner(): prepare spinner state. RETAIN.
/* u3_term_start_spinner(): prepare spinner state
*/
void
u3_term_start_spinner(u3_noun ovo)
u3_term_start_spinner(c3_c* why_c, c3_o now_o)
{
if ( c3n == u3_Host.ops_u.dem ) {
_term_start_spinner(_term_main(), ovo);
u3_utty* uty_u = _term_main();
u3_utat* tat_u = &uty_u->tat_u;
free(tat_u-> sun_u.why_c);
tat_u->sun_u.why_c = why_c;
tat_u->sun_u.eve_d = 0;
// XX must be c3n for cursor backoff from EOL?
tat_u->sun_u.diz_o = c3n;
{
c3_d now_d = _term_msc_out_host();
c3_d end_d = tat_u->sun_u.end_d;
c3_d wen_d = (c3y == now_o) ? 0UL :
(now_d - end_d < _SPIN_IDLE_US) ?
_SPIN_WARM_US : _SPIN_COOL_US;
uv_timer_start(&tat_u->sun_u.tim_u,
_term_spin_timer_cb,
wen_d, _SPIN_RATE_US);
}
}
}
@ -941,52 +862,20 @@ void
u3_term_stop_spinner(void)
{
if ( c3n == u3_Host.ops_u.dem ) {
_term_stop_spinner(_term_main());
}
}
u3_utty* uty_u = _term_main();
u3_utat* tat_u = &uty_u->tat_u;
/* _term_spinner_cb(): manage spinner (off-thread).
*/
static void
_term_spinner_cb(void* ptr_v)
{
// This thread shouldn't receive signals.
//
{
sigset_t set;
sigfillset(&set);
pthread_sigmask(SIG_BLOCK, &set, NULL);
}
uv_timer_stop(&tat_u->sun_u.tim_u);
u3_utty* uty_u = (u3_utty*)ptr_v;
for ( uv_mutex_lock(&uty_u->tat_u.mex_u);
uty_u->tat_u.sun.sit_u;
uv_mutex_lock(&uty_u->tat_u.mex_u) )
{
c3_d eve_d = uty_u->tat_u.sun.eve_d;
if ( 0 == eve_d ) {
c3_o diz_o = uty_u->tat_u.sun.diz_o;
uv_mutex_unlock(&uty_u->tat_u.mex_u);
usleep(c3y == diz_o ? _SPIN_WARM_US : _SPIN_COOL_US);
if ( c3y == tat_u->sun_u.diz_o ) {
_term_it_refresh_line(uty_u);
tat_u->sun_u.end_d = _term_msc_out_host();
tat_u->sun_u.diz_o = c3n;
}
else {
c3_d now_d = _term_msc_out_host();
if (now_d < eve_d) {
uv_mutex_unlock(&uty_u->tat_u.mex_u);
usleep(eve_d - now_d);
}
else {
_term_show_spinner(uty_u, now_d - eve_d);
uv_mutex_unlock(&uty_u->tat_u.mex_u);
usleep(_SPIN_RATE_US);
}
tat_u->sun_u.end_d = 0;
}
}
uv_mutex_unlock(&uty_u->tat_u.mex_u);
}
/* _term_main(): return main or console terminal.
@ -1100,16 +989,6 @@ _term_ef_blit(u3_utty* uty_u,
{
switch ( u3h(blt) ) {
default: break;
case c3__bee: {
if ( c3n == u3_Host.ops_u.dem ) {
if ( u3_nul == u3t(blt) ) {
_term_stop_spinner(uty_u);
}
else {
_term_start_spinner(uty_u, u3t(blt));
}
}
} break;
case c3__bel: {
if ( c3n == u3_Host.ops_u.dem ) {