diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/args.c | 2 | ||||
-rw-r--r-- | src/bc_lex.c | 2 | ||||
-rw-r--r-- | src/bc_parse.c | 21 | ||||
-rw-r--r-- | src/dc_lex.c | 2 | ||||
-rw-r--r-- | src/dc_parse.c | 5 | ||||
-rw-r--r-- | src/file.c | 37 | ||||
-rw-r--r-- | src/history.c | 95 | ||||
-rw-r--r-- | src/lex.c | 17 | ||||
-rw-r--r-- | src/library.c | 18 | ||||
-rw-r--r-- | src/opt.c | 2 | ||||
-rw-r--r-- | src/parse.c | 14 | ||||
-rw-r--r-- | src/program.c | 53 | ||||
-rw-r--r-- | src/rand.c | 11 | ||||
-rw-r--r-- | src/read.c | 4 | ||||
-rw-r--r-- | src/vm.c | 68 |
15 files changed, 261 insertions, 90 deletions
diff --git a/src/args.c b/src/args.c index 6601cfb2eeb6..5eee96f5b559 100644 --- a/src/args.c +++ b/src/args.c @@ -91,6 +91,8 @@ static void bc_args_redefine(const char *keyword) { size_t i; + BC_SIG_ASSERT_LOCKED; + for (i = 0; i < bc_lex_kws_len; ++i) { const BcLexKeyword *kw = bc_lex_kws + i; diff --git a/src/bc_lex.c b/src/bc_lex.c index cdbdf24b17ac..bd03d169ee06 100644 --- a/src/bc_lex.c +++ b/src/bc_lex.c @@ -158,6 +158,8 @@ void bc_lex_token(BcLex *l) { // character of every identifier would be missing. char c = l->buf[l->i++], c2; + BC_SIG_ASSERT_LOCKED; + // This is the workhorse of the lexer. switch (c) { diff --git a/src/bc_parse.c b/src/bc_parse.c index c2fc2186a065..91de31ad5389 100644 --- a/src/bc_parse.c +++ b/src/bc_parse.c @@ -329,12 +329,8 @@ static void bc_parse_call(BcParse *p, const char *name, uint8_t flags) { // not define it, it's a *runtime* error, not a parse error. if (idx == BC_VEC_INVALID_IDX) { - BC_SIG_LOCK; - idx = bc_program_insertFunc(p->prog, name); - BC_SIG_UNLOCK; - assert(idx != BC_VEC_INVALID_IDX); // Make sure that this pointer was not invalidated. @@ -359,15 +355,13 @@ static void bc_parse_name(BcParse *p, BcInst *type, { char *name; - BC_SIG_LOCK; + BC_SIG_ASSERT_LOCKED; // We want a copy of the name since the lexer might overwrite its copy. name = bc_vm_strdup(p->l.str.v); BC_SETJMP_LOCKED(err); - BC_SIG_UNLOCK; - // We need the next token to see if it's just a variable or something more. bc_lex_next(&p->l); @@ -431,9 +425,9 @@ static void bc_parse_name(BcParse *p, BcInst *type, err: // Need to make sure to unallocate the name. - BC_SIG_MAYLOCK; free(name); BC_LONGJMP_CONT; + BC_SIG_MAYLOCK; } /** @@ -1315,15 +1309,9 @@ static void bc_parse_func(BcParse *p) { // Make sure the functions map and vector are synchronized. assert(p->prog->fns.len == p->prog->fn_map.len); - // Must lock signals because vectors are changed, and the vector functions - // expect signals to be locked. - BC_SIG_LOCK; - // Insert the function by name into the map and vector. idx = bc_program_insertFunc(p->prog, p->l.str.v); - BC_SIG_UNLOCK; - // Make sure the insert worked. assert(idx); @@ -1759,7 +1747,7 @@ void bc_parse_parse(BcParse *p) { assert(p); - BC_SETJMP(exit); + BC_SETJMP_LOCKED(exit); // We should not let an EOF get here unless some partial parse was not // completed, in which case, it's the user's fault. @@ -1780,13 +1768,12 @@ void bc_parse_parse(BcParse *p) { exit: - BC_SIG_MAYLOCK; - // We need to reset on error. if (BC_ERR(((vm.status && vm.status != BC_STATUS_QUIT) || vm.sig))) bc_parse_reset(p); BC_LONGJMP_CONT; + BC_SIG_MAYLOCK; } /** diff --git a/src/dc_lex.c b/src/dc_lex.c index 5c6950ba9698..576d50943f25 100644 --- a/src/dc_lex.c +++ b/src/dc_lex.c @@ -157,6 +157,8 @@ void dc_lex_token(BcLex *l) { char c = l->buf[l->i++], c2; size_t i; + BC_SIG_ASSERT_LOCKED; + // If the last token was a command that needs a register, we need to parse a // register, so do so. for (i = 0; i < dc_lex_regs_len; ++i) { diff --git a/src/dc_parse.c b/src/dc_parse.c index b9b5afb66c44..26aad6796d88 100644 --- a/src/dc_parse.c +++ b/src/dc_parse.c @@ -302,7 +302,7 @@ void dc_parse_parse(BcParse *p) { assert(p != NULL); - BC_SETJMP(exit); + BC_SETJMP_LOCKED(exit); // If we have EOF, someone called this function one too many times. // Otherwise, parse. @@ -311,11 +311,10 @@ void dc_parse_parse(BcParse *p) { exit: - BC_SIG_MAYLOCK; - // Need to reset if there was an error. if (BC_SIG_EXC) bc_parse_reset(p); BC_LONGJMP_CONT; + BC_SIG_MAYLOCK; } #endif // DC_ENABLED diff --git a/src/file.c b/src/file.c index 35a4647dfabf..627664a9c261 100644 --- a/src/file.c +++ b/src/file.c @@ -94,8 +94,12 @@ static BcStatus bc_file_output(int fd, const char *buf, size_t n) { ssize_t written = write(fd, buf + bytes, n - bytes); // Check for error and return, if any. - if (BC_ERR(written == -1)) + if (BC_ERR(written == -1)) { + + BC_SIG_TRYUNLOCK(lock); + return errno == EPIPE ? BC_STATUS_EOF : BC_STATUS_ERROR_FATAL; + } bytes += (size_t) written; } @@ -109,6 +113,8 @@ BcStatus bc_file_flushErr(BcFile *restrict f, BcFlushType type) { BcStatus s; + BC_SIG_ASSERT_LOCKED; + // If there is stuff to output... if (f->len) { @@ -151,7 +157,12 @@ BcStatus bc_file_flushErr(BcFile *restrict f, BcFlushType type) void bc_file_flush(BcFile *restrict f, BcFlushType type) { - BcStatus s = bc_file_flushErr(f, type); + BcStatus s; + sig_atomic_t lock; + + BC_SIG_TRYLOCK(lock); + + s = bc_file_flushErr(f, type); // If we have an error... if (BC_ERR(s)) { @@ -159,16 +170,23 @@ void bc_file_flush(BcFile *restrict f, BcFlushType type) { // For EOF, set it and jump. if (s == BC_STATUS_EOF) { vm.status = (sig_atomic_t) s; + BC_SIG_TRYUNLOCK(lock); BC_JMP; } // Blow up on fatal error. Okay, not blow up, just quit. else bc_vm_fatalError(BC_ERR_FATAL_IO_ERR); } + + BC_SIG_TRYUNLOCK(lock); } void bc_file_write(BcFile *restrict f, BcFlushType type, const char *buf, size_t n) { + sig_atomic_t lock; + + BC_SIG_TRYLOCK(lock); + // If we have enough to flush, do it. if (n > f->cap - f->len) { bc_file_flush(f, type); @@ -182,15 +200,22 @@ void bc_file_write(BcFile *restrict f, BcFlushType type, memcpy(f->buf + f->len, buf, n); f->len += n; } + + BC_SIG_TRYUNLOCK(lock); } void bc_file_printf(BcFile *restrict f, const char *fmt, ...) { va_list args; + sig_atomic_t lock; + + BC_SIG_TRYLOCK(lock); va_start(args, fmt); bc_file_vprintf(f, fmt, args); va_end(args); + + BC_SIG_TRYUNLOCK(lock); } void bc_file_vprintf(BcFile *restrict f, const char *fmt, va_list args) { @@ -199,6 +224,8 @@ void bc_file_vprintf(BcFile *restrict f, const char *fmt, va_list args) { const char *ptr = fmt; char buf[BC_FILE_ULL_LENGTH]; + BC_SIG_ASSERT_LOCKED; + // This is a poor man's printf(). While I could look up algorithms to make // it as fast as possible, and should when I write the standard library for // a new language, for bc, outputting is not the bottleneck. So we cheese it @@ -287,12 +314,18 @@ void bc_file_puts(BcFile *restrict f, BcFlushType type, const char *str) { void bc_file_putchar(BcFile *restrict f, BcFlushType type, uchar c) { + sig_atomic_t lock; + + BC_SIG_TRYLOCK(lock); + if (f->len == f->cap) bc_file_flush(f, type); assert(f->len < f->cap); f->buf[f->len] = (char) c; f->len += 1; + + BC_SIG_TRYUNLOCK(lock); } void bc_file_init(BcFile *f, int fd, char *buf, size_t cap) { diff --git a/src/history.c b/src/history.c index b5ba0758075c..9f158413efc2 100644 --- a/src/history.c +++ b/src/history.c @@ -375,7 +375,7 @@ static ssize_t bc_history_read(char *buf, size_t n) { ssize_t ret; - BC_SIG_LOCK; + BC_SIG_ASSERT_LOCKED; #ifndef _WIN32 @@ -396,8 +396,6 @@ static ssize_t bc_history_read(char *buf, size_t n) { #endif // _WIN32 - BC_SIG_UNLOCK; - return ret; } @@ -416,8 +414,13 @@ static BcStatus bc_history_readCode(char *buf, size_t buf_len, assert(buf_len >= 1); + BC_SIG_LOCK; + // Read a byte. n = bc_history_read(buf, 1); + + BC_SIG_UNLOCK; + if (BC_ERR(n <= 0)) goto err; // Get the byte. @@ -431,24 +434,36 @@ static BcStatus bc_history_readCode(char *buf, size_t buf_len, assert(buf_len >= 2); + BC_SIG_LOCK; + n = bc_history_read(buf + 1, 1); + BC_SIG_UNLOCK; + if (BC_ERR(n <= 0)) goto err; } else if ((byte & 0xF0) == 0xE0) { assert(buf_len >= 3); + BC_SIG_LOCK; + n = bc_history_read(buf + 1, 2); + BC_SIG_UNLOCK; + if (BC_ERR(n <= 0)) goto err; } else if ((byte & 0xF8) == 0xF0) { assert(buf_len >= 3); + BC_SIG_LOCK; + n = bc_history_read(buf + 1, 3); + BC_SIG_UNLOCK; + if (BC_ERR(n <= 0)) goto err; } else { @@ -606,6 +621,8 @@ static size_t bc_history_cursorPos(void) { char *ptr, *ptr2; size_t cols, rows, i; + BC_SIG_ASSERT_LOCKED; + // Report cursor location. bc_file_write(&vm.fout, bc_flush_none, "\x1b[6n", 4); bc_file_flush(&vm.fout, bc_flush_none); @@ -648,12 +665,8 @@ static size_t bc_history_columns(void) { struct winsize ws; int ret; - BC_SIG_LOCK; - ret = ioctl(vm.fout.fd, TIOCGWINSZ, &ws); - BC_SIG_UNLOCK; - if (BC_ERR(ret == -1 || !ws.ws_col)) { // Calling ioctl() failed. Try to query the terminal itself. @@ -721,6 +734,8 @@ static void bc_history_refresh(BcHistory *h) { char* buf = h->buf.v; size_t colpos, len = BC_HIST_BUF_LEN(h), pos = h->pos, extras_len = 0; + BC_SIG_ASSERT_LOCKED; + bc_file_flush(&vm.fout, bc_flush_none); // Get to the prompt column position from the left. @@ -783,6 +798,8 @@ static void bc_history_refresh(BcHistory *h) { */ static void bc_history_edit_insert(BcHistory *h, const char *cbuf, size_t clen) { + BC_SIG_ASSERT_LOCKED; + bc_vec_grow(&h->buf, clen); // If we are at the end of the line... @@ -836,6 +853,8 @@ static void bc_history_edit_insert(BcHistory *h, const char *cbuf, size_t clen) */ static void bc_history_edit_left(BcHistory *h) { + BC_SIG_ASSERT_LOCKED; + // Stop at the left end. if (h->pos <= 0) return; @@ -850,6 +869,8 @@ static void bc_history_edit_left(BcHistory *h) { */ static void bc_history_edit_right(BcHistory *h) { + BC_SIG_ASSERT_LOCKED; + // Stop at the right end. if (h->pos == BC_HIST_BUF_LEN(h)) return; @@ -866,6 +887,8 @@ static void bc_history_edit_wordEnd(BcHistory *h) { size_t len = BC_HIST_BUF_LEN(h); + BC_SIG_ASSERT_LOCKED; + // Don't overflow. if (!len || h->pos >= len) return; @@ -884,6 +907,8 @@ static void bc_history_edit_wordStart(BcHistory *h) { size_t len = BC_HIST_BUF_LEN(h); + BC_SIG_ASSERT_LOCKED; + // Stop with no data. if (!len) return; @@ -900,6 +925,8 @@ static void bc_history_edit_wordStart(BcHistory *h) { */ static void bc_history_edit_home(BcHistory *h) { + BC_SIG_ASSERT_LOCKED; + // Stop at the beginning. if (!h->pos) return; @@ -914,6 +941,8 @@ static void bc_history_edit_home(BcHistory *h) { */ static void bc_history_edit_end(BcHistory *h) { + BC_SIG_ASSERT_LOCKED; + // Stop at the end of the line. if (h->pos == BC_HIST_BUF_LEN(h)) return; @@ -932,11 +961,11 @@ static void bc_history_edit_next(BcHistory *h, bool dir) { const char *dup, *str; + BC_SIG_ASSERT_LOCKED; + // Stop if there is no history. if (h->history.len <= 1) return; - BC_SIG_LOCK; - // Duplicate the buffer. if (h->buf.v[0]) dup = bc_vm_strdup(h->buf.v); else dup = ""; @@ -944,8 +973,6 @@ static void bc_history_edit_next(BcHistory *h, bool dir) { // Update the current history entry before overwriting it with the next one. bc_vec_replaceAt(&h->history, h->history.len - 1 - h->idx, &dup); - BC_SIG_UNLOCK; - // Show the new entry. h->idx += (dir == BC_HIST_PREV ? 1 : SIZE_MAX); @@ -980,6 +1007,8 @@ static void bc_history_edit_delete(BcHistory *h) { size_t chlen, len = BC_HIST_BUF_LEN(h); + BC_SIG_ASSERT_LOCKED; + // If there is no character, skip. if (!len || h->pos >= len) return; @@ -1005,6 +1034,8 @@ static void bc_history_edit_backspace(BcHistory *h) { size_t chlen, len = BC_HIST_BUF_LEN(h); + BC_SIG_ASSERT_LOCKED; + // If there are no characters, skip. if (!h->pos || !len) return; @@ -1031,6 +1062,8 @@ static void bc_history_edit_deletePrevWord(BcHistory *h) { size_t diff, old_pos = h->pos; + BC_SIG_ASSERT_LOCKED; + // If at the beginning of the line, skip. if (!old_pos) return; @@ -1059,6 +1092,8 @@ static void bc_history_edit_deleteNextWord(BcHistory *h) { size_t next_end = h->pos, len = BC_HIST_BUF_LEN(h); + BC_SIG_ASSERT_LOCKED; + // If at the end of the line, skip. if (next_end == len) return; @@ -1084,6 +1119,8 @@ static void bc_history_swap(BcHistory *h) { size_t pcl, ncl; char auxb[5]; + BC_SIG_ASSERT_LOCKED; + // Get the length of the previous and next characters. pcl = bc_history_prevLen(h->buf.v, h->pos); ncl = bc_history_nextLen(h->buf.v, BC_HIST_BUF_LEN(h), h->pos, NULL); @@ -1126,6 +1163,8 @@ static void bc_history_escape(BcHistory *h) { char c, seq[3]; + BC_SIG_ASSERT_LOCKED; + // Read a character into seq. if (BC_ERR(BC_HIST_READ(seq, 1))) return; @@ -1274,6 +1313,8 @@ static void bc_history_escape(BcHistory *h) { */ static void bc_history_add(BcHistory *h, char *line) { + BC_SIG_ASSERT_LOCKED; + // If there is something already there... if (h->history.len) { @@ -1282,13 +1323,7 @@ static void bc_history_add(BcHistory *h, char *line) { // Check for, and discard, duplicates. if (!strcmp(s, line)) { - - BC_SIG_LOCK; - free(line); - - BC_SIG_UNLOCK; - return; } } @@ -1303,6 +1338,8 @@ static void bc_history_add(BcHistory *h, char *line) { */ static void bc_history_add_empty(BcHistory *h) { + BC_SIG_ASSERT_LOCKED; + const char *line = ""; // If there is something already there... @@ -1324,6 +1361,8 @@ static void bc_history_add_empty(BcHistory *h) { */ static void bc_history_reset(BcHistory *h) { + BC_SIG_ASSERT_LOCKED; + h->oldcolpos = h->pos = h->idx = 0; h->cols = bc_history_columns(); @@ -1345,6 +1384,8 @@ static void bc_history_printCtrl(BcHistory *h, unsigned int c) { char str[3] = "^A"; const char newline[2] = "\n"; + BC_SIG_ASSERT_LOCKED; + // Set the correct character. str[1] = (char) (c + 'A' - BC_ACTION_CTRL_A); @@ -1378,6 +1419,8 @@ static void bc_history_printCtrl(BcHistory *h, unsigned int c) { */ static BcStatus bc_history_edit(BcHistory *h, const char *prompt) { + BC_SIG_LOCK; + bc_history_reset(h); // Don't write the saved output the first time. This is because it has @@ -1404,10 +1447,14 @@ static BcStatus bc_history_edit(BcHistory *h, const char *prompt) { unsigned int c = 0; size_t nread = 0; + BC_SIG_UNLOCK; + // Read a code. s = bc_history_readCode(cbuf, sizeof(cbuf), &c, &nread); if (BC_ERR(s)) return s; + BC_SIG_LOCK; + switch (c) { case BC_ACTION_LINE_FEED: @@ -1415,6 +1462,7 @@ static BcStatus bc_history_edit(BcHistory *h, const char *prompt) { { // Return the line. bc_vec_pop(&h->history); + BC_SIG_UNLOCK; return s; } @@ -1434,6 +1482,7 @@ static BcStatus bc_history_edit(BcHistory *h, const char *prompt) { // Quit if the user wants it. if (!BC_SIGINT) { vm.status = BC_STATUS_QUIT; + BC_SIG_UNLOCK; BC_JMP; } @@ -1460,6 +1509,7 @@ static BcStatus bc_history_edit(BcHistory *h, const char *prompt) { case BC_ACTION_CTRL_D: { bc_history_printCtrl(h, c); + BC_SIG_UNLOCK; return BC_STATUS_EOF; } #endif // _WIN32 @@ -1565,6 +1615,7 @@ static BcStatus bc_history_edit(BcHistory *h, const char *prompt) { bc_history_raise(h, SIGQUIT); #else // _WIN32 vm.status = BC_STATUS_QUIT; + BC_SIG_UNLOCK; BC_JMP; #endif // _WIN32 } @@ -1575,6 +1626,8 @@ static BcStatus bc_history_edit(BcHistory *h, const char *prompt) { } } + BC_SIG_UNLOCK; + return BC_STATUS_SUCCESS; } @@ -1611,22 +1664,22 @@ BcStatus bc_history_line(BcHistory *h, BcVec *vec, const char *prompt) { bc_file_write(&vm.fout, bc_flush_none, "\n", 1); bc_file_flush(&vm.fout, bc_flush_none); + BC_SIG_LOCK; + // If we actually have data... if (h->buf.v[0]) { - BC_SIG_LOCK; - // Duplicate it. line = bc_vm_strdup(h->buf.v); - BC_SIG_UNLOCK; - // Store it. bc_history_add(h, line); } // Add an empty string. else bc_history_add_empty(h); + BC_SIG_UNLOCK; + // Concatenate the line to the return vector. bc_vec_concat(vec, h->buf.v); bc_vec_concat(vec, "\n"); diff --git a/src/lex.c b/src/lex.c index f8b32451aef7..51e9f31bfa11 100644 --- a/src/lex.c +++ b/src/lex.c @@ -258,6 +258,8 @@ void bc_lex_file(BcLex *l, const char *file) { void bc_lex_next(BcLex *l) { + BC_SIG_ASSERT_LOCKED; + assert(l != NULL); l->last = l->t; @@ -294,7 +296,15 @@ static void bc_lex_fixText(BcLex *l, const char *text, size_t len) { bool bc_lex_readLine(BcLex *l) { - bool good = bc_vm_readLine(false); + bool good; + + // These are reversed because they should be already locked, but + // bc_vm_readLine() needs them to be unlocked. + BC_SIG_UNLOCK; + + good = bc_vm_readLine(false); + + BC_SIG_LOCK; bc_lex_fixText(l, vm.buffer.v, vm.buffer.len - 1); @@ -302,10 +312,15 @@ bool bc_lex_readLine(BcLex *l) { } void bc_lex_text(BcLex *l, const char *text, bool is_stdin) { + + BC_SIG_ASSERT_LOCKED; + assert(l != NULL && text != NULL); + bc_lex_fixText(l, text, strlen(text)); l->i = 0; l->t = l->last = BC_LEX_INVALID; l->is_stdin = is_stdin; + bc_lex_next(l); } diff --git a/src/library.c b/src/library.c index e0bd3ee98b85..a9246a025206 100644 --- a/src/library.c +++ b/src/library.c @@ -77,9 +77,14 @@ BclError bcl_init(void) { BclError e = BCL_ERROR_NONE; + BC_SIG_LOCK; + vm.refs += 1; - if (vm.refs > 1) return e; + if (vm.refs > 1) { + BC_SIG_UNLOCK; + return e; + } // Setting these to NULL ensures that if an error occurs, we only free what // is necessary. @@ -89,8 +94,6 @@ BclError bcl_init(void) { vm.abrt = false; - BC_SIG_LOCK; - // The jmp_bufs always has to be initialized first. bc_vec_init(&vm.jmp_bufs, sizeof(sigjmp_buf), BC_DTOR_NONE); @@ -146,11 +149,14 @@ void bcl_free(void) { size_t i; - vm.refs -= 1; + BC_SIG_LOCK; - if (vm.refs) return; + vm.refs -= 1; - BC_SIG_LOCK; + if (vm.refs) { + BC_SIG_UNLOCK; + return; + } bc_rand_free(&vm.rng); bc_vec_free(&vm.out); diff --git a/src/opt.c b/src/opt.c index ddc78362e7b1..971e7e5f3ca5 100644 --- a/src/opt.c +++ b/src/opt.c @@ -235,7 +235,7 @@ static bool bc_opt_longoptsMatch(const char *name, const char *option) { // Can never match a NULL name. if (name == NULL) return false; - // Loop through + // Loop through. for (; *a && *n && *a != '='; ++a, ++n) { if (*a != *n) return false; } diff --git a/src/parse.c b/src/parse.c index ea4c25e8ba10..7fdfa31df4ac 100644 --- a/src/parse.c +++ b/src/parse.c @@ -70,15 +70,11 @@ void bc_parse_addString(BcParse *p) { size_t idx; - BC_SIG_LOCK; - idx = bc_program_addString(p->prog, p->l.str.v, p->fidx); // Push the string info. bc_parse_update(p, BC_INST_STR, p->fidx); bc_parse_pushIndex(p, idx); - - BC_SIG_UNLOCK; } static void bc_parse_addNum(BcParse *p, const char *string) { @@ -88,6 +84,8 @@ static void bc_parse_addNum(BcParse *p, const char *string) { BcConst *c; BcVec *slabs; + BC_SIG_ASSERT_LOCKED; + // Special case 0. if (bc_parse_zero[0] == string[0] && bc_parse_zero[1] == string[1]) { bc_parse_push(p, BC_INST_ZERO); @@ -103,8 +101,6 @@ static void bc_parse_addNum(BcParse *p, const char *string) { // Get the index. idx = consts->len; - BC_SIG_LOCK; - // Get the right slab. slabs = p->fidx == BC_PROG_MAIN || p->fidx == BC_PROG_READ ? &vm.main_const_slab : &vm.other_slabs; @@ -120,8 +116,6 @@ static void bc_parse_addNum(BcParse *p, const char *string) { bc_num_clear(&c->num); bc_parse_update(p, BC_INST_NUM, idx); - - BC_SIG_UNLOCK; } void bc_parse_number(BcParse *p) { @@ -158,9 +152,13 @@ void bc_parse_number(BcParse *p) { void bc_parse_text(BcParse *p, const char *text, bool is_stdin) { + BC_SIG_LOCK; + // Make sure the pointer isn't invalidated. p->func = bc_vec_item(&p->prog->fns, p->fidx); bc_lex_text(&p->l, text, is_stdin); + + BC_SIG_UNLOCK; } void bc_parse_reset(BcParse *p) { diff --git a/src/program.c b/src/program.c index 1ff9c24f323b..bc5b88011638 100644 --- a/src/program.c +++ b/src/program.c @@ -55,6 +55,7 @@ * @param f The new function. */ static inline void bc_program_setVecs(BcProgram *p, BcFunc *f) { + BC_SIG_ASSERT_LOCKED; p->consts = &f->consts; p->strs = &f->strs; } @@ -152,6 +153,8 @@ static void bc_program_popGlobals(BcProgram *p, bool reset) { size_t i; + BC_SIG_ASSERT_LOCKED; + for (i = 0; i < BC_PROG_GLOBALS_LEN; ++i) { BcVec *v = p->globals_v + i; bc_vec_npop(v, reset ? v->len - 1 : 1); @@ -238,12 +241,12 @@ size_t bc_program_search(BcProgram *p, const char *id, bool var) { BcVec *v, *map; size_t i; + BC_SIG_ASSERT_LOCKED; + // Grab the right vector and map. v = var ? &p->vars : &p->arrs; map = var ? &p->var_map : &p->arr_map; - BC_SIG_LOCK; - // We do an insert because the variable might not exist yet. This is because // the parser calls this function. If the insert succeeds, we create a stack // for the variable/array. But regardless, bc_map_insert() gives us the @@ -253,8 +256,6 @@ size_t bc_program_search(BcProgram *p, const char *id, bool var) { bc_array_init(temp, var); } - BC_SIG_UNLOCK; - return ((BcId*) bc_vec_item(map, i))->idx; } @@ -711,7 +712,9 @@ static void bc_program_read(BcProgram *p) { // Parse *one* expression. bc_parse_text(&vm.read_prs, vm.read_buf.v, false); + BC_SIG_LOCK; vm.expr(&vm.read_prs, BC_PARSE_NOREAD | BC_PARSE_NEEDVAL); + BC_SIG_UNLOCK; // We *must* have a valid expression. A semicolon cannot end an expression, // although EOF can. @@ -736,6 +739,9 @@ static void bc_program_read(BcProgram *p) { // We want a return instruction to simplify things. bc_vec_pushByte(&f->code, vm.read_ret); + + // This lock is here to make sure dc's tail calls are the same length. + BC_SIG_LOCK; bc_vec_push(&p->stack, &ip); #if DC_ENABLED @@ -784,6 +790,9 @@ static void bc_program_printChars(const char *str) { const char *nl; size_t len = vm.nchars + strlen(str); + sig_atomic_t lock; + + BC_SIG_TRYLOCK(lock); bc_file_puts(&vm.fout, bc_flush_save, str); @@ -794,6 +803,8 @@ static void bc_program_printChars(const char *str) { if (nl != NULL) len = strlen(nl + 1); vm.nchars = len > UINT16_MAX ? UINT16_MAX : (uint16_t) len; + + BC_SIG_TRYUNLOCK(lock); } /** @@ -830,7 +841,11 @@ static void bc_program_printString(const char *restrict str) { if (ptr != NULL) { // We need to specially handle a newline. - if (c == 'n') vm.nchars = UINT16_MAX; + if (c == 'n') { + BC_SIG_LOCK; + vm.nchars = UINT16_MAX; + BC_SIG_UNLOCK; + } // Grab the actual character. c = bc_program_esc_seqs[(size_t) (ptr - bc_program_esc_chars)]; @@ -1770,6 +1785,8 @@ static void bc_program_return(BcProgram *p, uchar inst) { bc_vec_pop(v); } + BC_SIG_LOCK; + // When we retire, pop all of the unused results. bc_program_retire(p, 1, nresults); @@ -1778,6 +1795,8 @@ static void bc_program_return(BcProgram *p, uchar inst) { // Pop the stack. This is what causes the function to actually "return." bc_vec_pop(&p->stack); + + BC_SIG_UNLOCK; } #endif // BC_ENABLED @@ -2184,8 +2203,10 @@ static void bc_program_nquit(BcProgram *p, uchar inst) { // because these are for tail calls. That means that any executions that // we would not have quit in that position on the stack would have quit // anyway. + BC_SIG_LOCK; bc_vec_npop(&p->stack, i); bc_vec_npop(&p->tail_calls, i); + BC_SIG_UNLOCK; } } @@ -2311,9 +2332,9 @@ static void bc_program_execStr(BcProgram *p, const char *restrict code, // Parse. bc_parse_text(&vm.read_prs, str, false); - vm.expr(&vm.read_prs, BC_PARSE_NOCALL); BC_SIG_LOCK; + vm.expr(&vm.read_prs, BC_PARSE_NOCALL); BC_UNSETJMP; @@ -2329,6 +2350,8 @@ static void bc_program_execStr(BcProgram *p, const char *restrict code, ip.len = p->results.len; ip.func = fidx; + BC_SIG_LOCK; + // Pop the operand. bc_vec_pop(&p->results); @@ -2352,6 +2375,8 @@ static void bc_program_execStr(BcProgram *p, const char *restrict code, // Push the new function onto the execution stack and return. bc_vec_push(&p->stack, &ip); + BC_SIG_UNLOCK; + return; err: @@ -2678,7 +2703,9 @@ void bc_program_exec(BcProgram *p) { code = func->code.v; // Ensure the pointers are correct. + BC_SIG_LOCK; bc_program_setVecs(p, func); + BC_SIG_UNLOCK; #if !BC_HAS_COMPUTED_GOTO @@ -2759,10 +2786,12 @@ void bc_program_exec(BcProgram *p) { // Because we changed the execution stack and where we are // executing, we have to update all of this. + BC_SIG_LOCK; ip = bc_vec_top(&p->stack); func = bc_vec_item(&p->fns, ip->func); code = func->code.v; bc_program_setVecs(p, func); + BC_SIG_UNLOCK; BC_PROG_JUMP(inst, code, ip); } @@ -2792,10 +2821,12 @@ void bc_program_exec(BcProgram *p) { // Because we changed the execution stack and where we are // executing, we have to update all of this. + BC_SIG_LOCK; ip = bc_vec_top(&p->stack); func = bc_vec_item(&p->fns, ip->func); code = func->code.v; bc_program_setVecs(p, func); + BC_SIG_UNLOCK; BC_PROG_JUMP(inst, code, ip); } @@ -2824,10 +2855,12 @@ void bc_program_exec(BcProgram *p) { // Because we changed the execution stack and where we are // executing, we have to update all of this. + BC_SIG_LOCK; ip = bc_vec_top(&p->stack); func = bc_vec_item(&p->fns, ip->func); code = func->code.v; bc_program_setVecs(p, func); + BC_SIG_UNLOCK; BC_PROG_JUMP(inst, code, ip); } @@ -2909,10 +2942,12 @@ void bc_program_exec(BcProgram *p) { // Because we changed the execution stack and where we are // executing, we have to update all of this. + BC_SIG_LOCK; ip = bc_vec_top(&p->stack); func = bc_vec_item(&p->fns, ip->func); code = func->code.v; bc_program_setVecs(p, func); + BC_SIG_UNLOCK; BC_PROG_JUMP(inst, code, ip); } @@ -3086,10 +3121,12 @@ void bc_program_exec(BcProgram *p) { // Because we changed the execution stack and where we are // executing, we have to update all of this. + BC_SIG_LOCK; ip = bc_vec_top(&p->stack); func = bc_vec_item(&p->fns, ip->func); code = func->code.v; bc_program_setVecs(p, func); + BC_SIG_UNLOCK; BC_PROG_JUMP(inst, code, ip); } @@ -3103,10 +3140,12 @@ void bc_program_exec(BcProgram *p) { // Because we changed the execution stack and where we are // executing, we have to update all of this. + BC_SIG_LOCK; ip = bc_vec_top(&p->stack); func = bc_vec_item(&p->fns, ip->func); code = func->code.v; bc_program_setVecs(p, func); + BC_SIG_UNLOCK; BC_PROG_JUMP(inst, code, ip); } @@ -3179,10 +3218,12 @@ void bc_program_exec(BcProgram *p) { // Because we changed the execution stack and where we are // executing, we have to update all of this. + BC_SIG_LOCK; ip = bc_vec_top(&p->stack); func = bc_vec_item(&p->fns, ip->func); code = func->code.v; bc_program_setVecs(p, func); + BC_SIG_UNLOCK; BC_PROG_JUMP(inst, code, ip); } diff --git a/src/rand.c b/src/rand.c index bfc79be7cfb9..a3b8942a6042 100644 --- a/src/rand.c +++ b/src/rand.c @@ -461,16 +461,21 @@ BcRand bc_rand_int(BcRNG *r) { // Get the actual PRNG. BcRNGData *rng = bc_vec_top(&r->v); + BcRand res; // Make sure the PRNG is seeded. if (BC_ERR(BC_RAND_ZERO(rng))) bc_rand_srand(rng); - // This is the important part of the PRNG. This is the stuff from PCG, - // including the return statement. + BC_SIG_LOCK; + + // This is the important part of the PRNG. This is the stuff from PCG. bc_rand_step(rng); bc_rand_propagate(r, rng); + res = bc_rand_output(rng); - return bc_rand_output(rng); + BC_SIG_UNLOCK; + + return res; } BcRand bc_rand_bounded(BcRNG *r, BcRand bound) { diff --git a/src/read.c b/src/read.c index 84621ad3acac..b9cd4db7bb49 100644 --- a/src/read.c +++ b/src/read.c @@ -196,12 +196,16 @@ BcStatus bc_read_chars(BcVec *vec, const char *prompt) { return BC_STATUS_EOF; } + BC_SIG_LOCK; + // Add to the buffer. vm.buf_len += (size_t) r; vm.buf[vm.buf_len] = '\0'; // Read from the buffer. done = bc_read_buf(vec, vm.buf, &vm.buf_len); + + BC_SIG_UNLOCK; } // Terminate the string. @@ -186,9 +186,11 @@ void bc_vm_info(const char* const help) { "disabled"; const char* const prompt = BC_DEFAULT_PROMPT ? "enabled" : "disabled"; + const char* const expr = BC_DEFAULT_EXPR_EXIT ? "to exit" : + "to not exit"; bc_file_printf(&vm.fout, help, vm.name, vm.name, BC_VERSION, - BC_BUILD_TYPE, banner, sigint, tty, prompt); + BC_BUILD_TYPE, banner, sigint, tty, prompt, expr); } #endif // BC_ENABLED @@ -201,9 +203,11 @@ void bc_vm_info(const char* const help) { "disabled"; const char* const prompt = DC_DEFAULT_PROMPT ? "enabled" : "disabled"; + const char* const expr = DC_DEFAULT_EXPR_EXIT ? "to exit" : + "to not exit"; bc_file_printf(&vm.fout, help, vm.name, vm.name, BC_VERSION, - BC_BUILD_TYPE, sigint, tty, prompt); + BC_BUILD_TYPE, sigint, tty, prompt, expr); } #endif // DC_ENABLED } @@ -552,6 +556,8 @@ void bc_vm_shutdown(void) { void bc_vm_addTemp(BcDig *num) { + BC_SIG_ASSERT_LOCKED; + // If we don't have room, just free. if (vm.temps_len == BC_VM_MAX_TEMPS) free(num); else { @@ -563,8 +569,13 @@ void bc_vm_addTemp(BcDig *num) { } BcDig* bc_vm_takeTemp(void) { + + BC_SIG_ASSERT_LOCKED; + if (!vm.temps_len) return NULL; + vm.temps_len -= 1; + return temps_buf[vm.temps_len]; } @@ -660,8 +671,9 @@ char* bc_vm_strdup(const char *str) { void bc_vm_printf(const char *fmt, ...) { va_list args; + sig_atomic_t lock; - BC_SIG_LOCK; + BC_SIG_TRYLOCK(lock); va_start(args, fmt); bc_file_vprintf(&vm.fout, fmt, args); @@ -669,7 +681,7 @@ void bc_vm_printf(const char *fmt, ...) { vm.nchars = 0; - BC_SIG_UNLOCK; + BC_SIG_TRYUNLOCK(lock); } #endif // !BC_ENABLE_LIBRARY @@ -745,6 +757,8 @@ static void bc_vm_clean(void) { BcInstPtr *ip = bc_vec_item(&vm.prog.stack, 0); bool good = ((vm.status && vm.status != BC_STATUS_QUIT) || vm.sig); + BC_SIG_ASSERT_LOCKED; + // If all is good, go ahead and reset. if (good) bc_program_reset(&vm.prog); @@ -816,6 +830,8 @@ static void bc_vm_process(const char *text, bool is_stdin) { do { + BC_SIG_LOCK; + #if BC_ENABLED // If the first token is the keyword define, then we need to do this // specially because bc thinks it may not be able to parse. @@ -825,6 +841,8 @@ static void bc_vm_process(const char *text, bool is_stdin) { // Parse it all. while (BC_PARSE_CAN_PARSE(vm.prs)) vm.parse(&vm.prs); + BC_SIG_UNLOCK; + // Execute if possible. if(BC_IS_DC || !BC_PARSE_NO_EXEC(&vm.prs)) bc_program_exec(&vm.prog); @@ -901,6 +919,8 @@ bool bc_vm_readLine(bool clear) { BcStatus s; bool good; + BC_SIG_ASSERT_NOT_LOCKED; + // Clear the buffer if desired. if (clear) bc_vec_empty(&vm.buffer); @@ -969,7 +989,11 @@ restart: bc_vm_process(vm.buffer.v, true); if (vm.eof) break; - else bc_vm_clean(); + else { + BC_SIG_LOCK; + bc_vm_clean(); + BC_SIG_UNLOCK; + } } #if BC_ENABLED @@ -1022,7 +1046,11 @@ static void bc_vm_load(const char *name, const char *text) { bc_lex_file(&vm.prs.l, name); bc_parse_text(&vm.prs, text, false); + BC_SIG_LOCK; + while (vm.prs.l.t != BC_LEX_EOF) vm.parse(&vm.prs); + + BC_SIG_UNLOCK; } #endif // BC_ENABLED @@ -1172,7 +1200,7 @@ static void bc_vm_exec(void) { BC_SIG_UNLOCK; // Sometimes, executing expressions means we need to quit. - if (!vm.no_exprs && vm.exit_exprs) return; + if (!vm.no_exprs && vm.exit_exprs && BC_EXPR_EXIT) return; } // Process files. @@ -1194,9 +1222,7 @@ static void bc_vm_exec(void) { // We need to keep tty if history is enabled, and we need to keep rpath for // the times when we read from /dev/urandom. - if (BC_TTY && !vm.history.badTerm) { - bc_pledge(bc_pledge_end_history, NULL); - } + if (BC_TTY && !vm.history.badTerm) bc_pledge(bc_pledge_end_history, NULL); else #endif // BC_ENABLE_HISTORY { @@ -1233,6 +1259,8 @@ void bc_vm_boot(int argc, char *argv[]) { bool tty; const char* const env_len = BC_IS_BC ? "BC_LINE_LENGTH" : "DC_LINE_LENGTH"; const char* const env_args = BC_IS_BC ? "BC_ENV_ARGS" : "DC_ENV_ARGS"; + const char* const env_exit = BC_IS_BC ? "BC_EXPR_EXIT" : "DC_EXPR_EXIT"; + int env_exit_def = BC_IS_BC ? BC_DEFAULT_EXPR_EXIT : DC_DEFAULT_EXPR_EXIT; // We need to know which of stdin, stdout, and stderr are tty's. ttyin = isatty(STDIN_FILENO); @@ -1269,6 +1297,8 @@ void bc_vm_boot(int argc, char *argv[]) { // Set the line length by environment variable. vm.line_len = (uint16_t) bc_vm_envLen(env_len); + bc_vm_setenvFlag(env_exit, env_exit_def, BC_FLAG_EXPR_EXIT); + // Clear the files and expressions vectors, just in case. This marks them as // *not* allocated. bc_vec_clear(&vm.files); @@ -1289,26 +1319,22 @@ void bc_vm_boot(int argc, char *argv[]) { bc_program_init(&vm.prog); bc_parse_init(&vm.prs, &vm.prog, BC_PROG_MAIN); + // Set defaults. + vm.flags |= BC_TTY ? BC_FLAG_P | BC_FLAG_R : 0; + vm.flags |= BC_I ? BC_FLAG_Q : 0; + #if BC_ENABLED - // bc checks this environment variable to see if it should run in standard - // mode. if (BC_IS_BC) { + // bc checks this environment variable to see if it should run in + // standard mode. char* var = bc_vm_getenv("POSIXLY_CORRECT"); vm.flags |= BC_FLAG_S * (var != NULL); bc_vm_getenvFree(var); - } -#endif // BC_ENABLED - - // Set defaults. - vm.flags |= BC_TTY ? BC_FLAG_P | BC_FLAG_R : 0; - vm.flags |= BC_I ? BC_FLAG_Q : 0; -#if BC_ENABLED - if (BC_IS_BC && BC_I) { // Set whether we print the banner or not. - bc_vm_setenvFlag("BC_BANNER", BC_DEFAULT_BANNER, BC_FLAG_Q); + if (BC_I) bc_vm_setenvFlag("BC_BANNER", BC_DEFAULT_BANNER, BC_FLAG_Q); } #endif // BC_ENABLED @@ -1349,9 +1375,7 @@ void bc_vm_boot(int argc, char *argv[]) { #if BC_ENABLED // Disable global stacks in POSIX mode. if (BC_IS_POSIX) vm.flags &= ~(BC_FLAG_G); -#endif // BC_ENABLED -#if BC_ENABLED // Print the banner if allowed. We have to be in bc, in interactive mode, // and not be quieted by command-line option or environment variable. if (BC_IS_BC && BC_I && (vm.flags & BC_FLAG_Q)) { |