aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/args.c2
-rw-r--r--src/bc_lex.c2
-rw-r--r--src/bc_parse.c21
-rw-r--r--src/dc_lex.c2
-rw-r--r--src/dc_parse.c5
-rw-r--r--src/file.c37
-rw-r--r--src/history.c95
-rw-r--r--src/lex.c17
-rw-r--r--src/library.c18
-rw-r--r--src/opt.c2
-rw-r--r--src/parse.c14
-rw-r--r--src/program.c53
-rw-r--r--src/rand.c11
-rw-r--r--src/read.c4
-rw-r--r--src/vm.c68
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.
diff --git a/src/vm.c b/src/vm.c
index 853dff0820dd..ef2257644f52 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -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)) {