Skip to content

Commit 92ca0ea

Browse files
gh-174: Fix serialization.
1 parent cc1fa93 commit 92ca0ea

3 files changed

Lines changed: 151 additions & 28 deletions

File tree

src/builtins.c

Lines changed: 128 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1282,6 +1282,7 @@ typedef struct {
12821282
int next_func_id;
12831283
Thr** thrs;
12841284
char** thr_ids;
1285+
int* thr_state; // 0 = none, 1 = in_progress, 2 = done
12851286
size_t thr_count;
12861287
size_t thr_cap;
12871288
int next_thr_id;
@@ -1303,6 +1304,7 @@ static void ser_ctx_free(SerCtx* ctx) {
13031304
free(ctx->func_state);
13041305
free(ctx->thrs);
13051306
free(ctx->thr_ids);
1307+
free(ctx->thr_state);
13061308
}
13071309

13081310
static const char* ser_env_id(SerCtx* ctx, Env* env, int* state) {
@@ -1357,24 +1359,28 @@ static const char* ser_func_id(SerCtx* ctx, Func* func, int* state) {
13571359
return ctx->func_ids[ctx->func_count - 1];
13581360
}
13591361

1360-
static const char* ser_thr_id(SerCtx* ctx, Thr* thr) {
1362+
static const char* ser_thr_id(SerCtx* ctx, Thr* thr, int* state) {
13611363
for (size_t i = 0; i < ctx->thr_count; i++) {
13621364
if (ctx->thrs[i] == thr) {
1365+
if (state) *state = ctx->thr_state[i];
13631366
return ctx->thr_ids[i];
13641367
}
13651368
}
13661369
if (ctx->thr_count + 1 > ctx->thr_cap) {
13671370
size_t new_cap = ctx->thr_cap == 0 ? 4 : ctx->thr_cap * 2;
13681371
ctx->thrs = realloc(ctx->thrs, new_cap * sizeof(Thr*));
13691372
ctx->thr_ids = realloc(ctx->thr_ids, new_cap * sizeof(char*));
1370-
if (!ctx->thrs || !ctx->thr_ids) { fprintf(stderr, "Out of memory\n"); exit(1); }
1373+
ctx->thr_state = realloc(ctx->thr_state, new_cap * sizeof(int));
1374+
if (!ctx->thrs || !ctx->thr_ids || !ctx->thr_state) { fprintf(stderr, "Out of memory\n"); exit(1); }
13711375
ctx->thr_cap = new_cap;
13721376
}
13731377
ctx->next_thr_id++;
13741378
char buf[32];
13751379
snprintf(buf, sizeof(buf), "t%d", ctx->next_thr_id);
13761380
ctx->thrs[ctx->thr_count] = thr;
13771381
ctx->thr_ids[ctx->thr_count] = strdup(buf);
1382+
ctx->thr_state[ctx->thr_count] = 0;
1383+
if (state) *state = 0;
13781384
ctx->thr_count++;
13791385
return ctx->thr_ids[ctx->thr_count - 1];
13801386
}
@@ -1386,6 +1392,78 @@ static void json_obj_field(JsonBuf* jb, bool* first, const char* key) {
13861392
jb_append_char(jb, ':');
13871393
}
13881394

1395+
typedef struct {
1396+
Thr* target;
1397+
Map** seen_maps;
1398+
size_t seen_map_count;
1399+
size_t seen_map_cap;
1400+
Tensor** seen_tensors;
1401+
size_t seen_tensor_count;
1402+
size_t seen_tensor_cap;
1403+
} ThrContainCtx;
1404+
1405+
static int thr_contain_seen_map(ThrContainCtx* ctx, Map* map) {
1406+
for (size_t i = 0; i < ctx->seen_map_count; i++) {
1407+
if (ctx->seen_maps[i] == map) return 1;
1408+
}
1409+
if (ctx->seen_map_count + 1 > ctx->seen_map_cap) {
1410+
size_t new_cap = ctx->seen_map_cap == 0 ? 4 : ctx->seen_map_cap * 2;
1411+
ctx->seen_maps = realloc(ctx->seen_maps, new_cap * sizeof(Map*));
1412+
if (!ctx->seen_maps) { fprintf(stderr, "Out of memory\n"); exit(1); }
1413+
ctx->seen_map_cap = new_cap;
1414+
}
1415+
ctx->seen_maps[ctx->seen_map_count++] = map;
1416+
return 0;
1417+
}
1418+
1419+
static int thr_contain_seen_tensor(ThrContainCtx* ctx, Tensor* tns) {
1420+
for (size_t i = 0; i < ctx->seen_tensor_count; i++) {
1421+
if (ctx->seen_tensors[i] == tns) return 1;
1422+
}
1423+
if (ctx->seen_tensor_count + 1 > ctx->seen_tensor_cap) {
1424+
size_t new_cap = ctx->seen_tensor_cap == 0 ? 4 : ctx->seen_tensor_cap * 2;
1425+
ctx->seen_tensors = realloc(ctx->seen_tensors, new_cap * sizeof(Tensor*));
1426+
if (!ctx->seen_tensors) { fprintf(stderr, "Out of memory\n"); exit(1); }
1427+
ctx->seen_tensor_cap = new_cap;
1428+
}
1429+
ctx->seen_tensors[ctx->seen_tensor_count++] = tns;
1430+
return 0;
1431+
}
1432+
1433+
static int value_contains_thr_rec(ThrContainCtx* ctx, Value v) {
1434+
if (!ctx || !ctx->target) return 0;
1435+
switch (v.type) {
1436+
case VAL_THR:
1437+
return v.as.thr == ctx->target;
1438+
case VAL_MAP:
1439+
if (!v.as.map) return 0;
1440+
if (thr_contain_seen_map(ctx, v.as.map)) return 0;
1441+
for (size_t i = 0; i < v.as.map->count; i++) {
1442+
if (value_contains_thr_rec(ctx, v.as.map->items[i].key)) return 1;
1443+
if (value_contains_thr_rec(ctx, v.as.map->items[i].value)) return 1;
1444+
}
1445+
return 0;
1446+
case VAL_TNS:
1447+
if (!v.as.tns) return 0;
1448+
if (thr_contain_seen_tensor(ctx, v.as.tns)) return 0;
1449+
for (size_t i = 0; i < v.as.tns->length; i++) {
1450+
if (value_contains_thr_rec(ctx, v.as.tns->data[i])) return 1;
1451+
}
1452+
return 0;
1453+
default:
1454+
return 0;
1455+
}
1456+
}
1457+
1458+
static int value_contains_thr(Value v, Thr* target) {
1459+
ThrContainCtx ctx = {0};
1460+
ctx.target = target;
1461+
int found = value_contains_thr_rec(&ctx, v);
1462+
free(ctx.seen_maps);
1463+
free(ctx.seen_tensors);
1464+
return found;
1465+
}
1466+
13891467
static void ser_loc(JsonBuf* jb, int line, int col) {
13901468
jb_append_char(jb, '{');
13911469
bool first = true;
@@ -1404,7 +1482,7 @@ static void ser_expr(JsonBuf* jb, SerCtx* ctx, Interpreter* interp, Expr* expr);
14041482
static void ser_stmt(JsonBuf* jb, SerCtx* ctx, Interpreter* interp, Stmt* stmt);
14051483
static void ser_value(JsonBuf* jb, SerCtx* ctx, Interpreter* interp, Value v);
14061484

1407-
static void ser_env(JsonBuf* jb, SerCtx* ctx, Interpreter* interp, Env* env) {
1485+
static void ser_env(JsonBuf* jb, SerCtx* ctx, Interpreter* interp, Env* env, Thr* omit_thr) {
14081486
if (!env) {
14091487
jb_append_str(jb, "null");
14101488
return;
@@ -1445,6 +1523,9 @@ static void ser_env(JsonBuf* jb, SerCtx* ctx, Interpreter* interp, Env* env) {
14451523
for (size_t i = 0; i < env->count; i++) {
14461524
EnvEntry* entry = &env->entries[i];
14471525
if (!entry->initialized && !entry->alias_target) continue;
1526+
if (omit_thr && entry->initialized && !entry->alias_target && value_contains_thr(entry->value, omit_thr)) {
1527+
continue;
1528+
}
14481529
if (!val_first) jb_append_char(jb, ',');
14491530
val_first = false;
14501531
jb_append_json_string(jb, entry->name);
@@ -1458,7 +1539,7 @@ static void ser_env(JsonBuf* jb, SerCtx* ctx, Interpreter* interp, Env* env) {
14581539
jb_append_json_string(jb, entry->alias_target);
14591540
json_obj_field(jb, &pf, "env");
14601541
Env* owner = env_find_owner(env, entry->alias_target);
1461-
ser_env(jb, ctx, interp, owner ? owner : env);
1542+
ser_env(jb, ctx, interp, owner ? owner : env, omit_thr);
14621543
json_obj_field(jb, &pf, "value_type");
14631544
jb_append_json_string(jb, decl_type_name(entry->decl_type));
14641545
jb_append_char(jb, '}');
@@ -1505,7 +1586,7 @@ static void ser_env(JsonBuf* jb, SerCtx* ctx, Interpreter* interp, Env* env) {
15051586
jb_append_char(jb, ']');
15061587

15071588
json_obj_field(jb, &def_first, "parent");
1508-
ser_env(jb, ctx, interp, env->parent);
1589+
ser_env(jb, ctx, interp, env->parent, omit_thr);
15091590

15101591
jb_append_char(jb, '}');
15111592
jb_append_char(jb, '}');
@@ -2271,7 +2352,7 @@ static void ser_value(JsonBuf* jb, SerCtx* ctx, Interpreter* interp, Value v) {
22712352
json_obj_field(jb, &df, "body");
22722353
ser_stmt(jb, ctx, interp, fn->body);
22732354
json_obj_field(jb, &df, "closure");
2274-
ser_env(jb, ctx, interp, fn->closure);
2355+
ser_env(jb, ctx, interp, fn->closure, NULL);
22752356
jb_append_char(jb, '}');
22762357
jb_append_char(jb, '}');
22772358
for (size_t i = 0; i < ctx->func_count; i++) {
@@ -2284,7 +2365,9 @@ static void ser_value(JsonBuf* jb, SerCtx* ctx, Interpreter* interp, Value v) {
22842365
Value thv = value_null();
22852366
thv.type = VAL_THR;
22862367
thv.as.thr = th;
2287-
const char* id = ser_thr_id(ctx, th);
2368+
int state = 0;
2369+
const char* id = ser_thr_id(ctx, th, &state);
2370+
(void)state;
22882371
jb_append_char(jb, '{');
22892372
bool first = true;
22902373
json_obj_field(jb, &first, "t");
@@ -2300,9 +2383,9 @@ static void ser_value(JsonBuf* jb, SerCtx* ctx, Interpreter* interp, Value v) {
23002383
json_obj_field(jb, &first, "finished");
23012384
jb_append_str(jb, value_thr_get_finished(thv) ? "true" : "false");
23022385
json_obj_field(jb, &first, "stop");
2303-
jb_append_str(jb, value_thr_get_finished(thv) ? "true" : "false");
2386+
jb_append_str(jb, value_thr_get_stop_requested(thv) ? "true" : "false");
23042387
json_obj_field(jb, &first, "env");
2305-
ser_env(jb, ctx, interp, th->env);
2388+
ser_env(jb, ctx, interp, th->env, th);
23062389
json_obj_field(jb, &first, "block");
23072390
if (th->body) ser_stmt(jb, ctx, interp, th->body);
23082391
else jb_append_str(jb, "null");
@@ -2465,12 +2548,14 @@ static Expr* deser_expr(JsonValue* obj, UnserCtx* ctx, Interpreter* interp, cons
24652548
JsonValue* val = json_obj_get(obj, "value");
24662549
const char* lt = (lit_type && lit_type->type == JSON_STR) ? lit_type->as.str : "INT";
24672550
if (strcmp(lt, "BOOL") == 0) {
2468-
if (val && val->type == JSON_BOOL) return expr_bool(val->as.boolean != 0, line, col);
2469-
if (val && val->type == JSON_STR) {
2470-
if (strcmp(val->as.str, "TRUE") == 0 || strcmp(val->as.str, "true") == 0) return expr_bool(true, line, col);
2471-
if (strcmp(val->as.str, "FALSE") == 0 || strcmp(val->as.str, "false") == 0) return expr_bool(false, line, col);
2472-
}
2473-
return expr_bool(false, line, col);
2551+
if (!val) { *err = "UNSER: invalid BOOL value"; return NULL; }
2552+
if (val->type == JSON_BOOL) return expr_bool(val->as.boolean != 0, line, col);
2553+
if (val->type == JSON_STR) {
2554+
if (strcmp(val->as.str, "TRUE") == 0 || strcmp(val->as.str, "true") == 0) return expr_bool(true, line, col);
2555+
if (strcmp(val->as.str, "FALSE") == 0 || strcmp(val->as.str, "false") == 0) return expr_bool(false, line, col);
2556+
}
2557+
*err = "UNSER: invalid BOOL value";
2558+
return NULL;
24742559
}
24752560
if (strcmp(lt, "INT") == 0) {
24762561
int64_t i = 0;
@@ -2866,12 +2951,14 @@ static Value deser_val(JsonValue* obj, UnserCtx* ctx, Interpreter* interp, const
28662951
}
28672952
if (strcmp(tp, "BOOL") == 0) {
28682953
JsonValue* v = json_obj_get(obj, "v");
2869-
if (v && v->type == JSON_BOOL) return value_bool(v->as.boolean != 0);
2870-
if (v && v->type == JSON_STR) {
2954+
if (!v) { *err = "UNSER: invalid BOOL value"; return value_null(); }
2955+
if (v->type == JSON_BOOL) return value_bool(v->as.boolean != 0);
2956+
if (v->type == JSON_STR) {
28712957
if (strcmp(v->as.str, "TRUE") == 0 || strcmp(v->as.str, "true") == 0) return value_bool(true);
28722958
if (strcmp(v->as.str, "FALSE") == 0 || strcmp(v->as.str, "false") == 0) return value_bool(false);
28732959
}
2874-
return value_bool(false);
2960+
*err = "UNSER: invalid BOOL value";
2961+
return value_null();
28752962
}
28762963
if (strcmp(tp, "FLT") == 0) {
28772964
JsonValue* v = json_obj_get(obj, "v");
@@ -2899,14 +2986,22 @@ static Value deser_val(JsonValue* obj, UnserCtx* ctx, Interpreter* interp, const
28992986
return value_null();
29002987
}
29012988
size_t ndim = shape->as.arr.count;
2902-
size_t* shp = malloc(sizeof(size_t) * (ndim > 0 ? ndim : 1));
2903-
if (!shp) { *err = "Out of memory"; return value_null(); }
2989+
if (ndim == 0) { *err = "UNSER: invalid TNS shape"; return value_null(); }
2990+
// Compute expected element count and validate dims
2991+
size_t expected_total = 1;
29042992
for (size_t i = 0; i < ndim; i++) {
29052993
JsonValue* it = shape->as.arr.items[i];
2906-
size_t sv = (size_t)((it && it->type == JSON_NUM) ? it->as.num : 0);
2907-
shp[i] = sv;
2994+
if (!it || it->type != JSON_NUM) { *err = "UNSER: invalid TNS shape"; return value_null(); }
2995+
size_t sv = (size_t)it->as.num;
2996+
if (sv == 0) { *err = "UNSER: invalid TNS shape"; return value_null(); }
2997+
if (expected_total > 0 && sv > 0 && expected_total > (SIZE_MAX / sv)) { *err = "UNSER: TNS size overflow"; return value_null(); }
2998+
expected_total *= sv;
29082999
}
29093000
size_t total = flat->as.arr.count;
3001+
if (expected_total != total) { *err = "UNSER: invalid TNS element count"; return value_null(); }
3002+
size_t* shp = malloc(sizeof(size_t) * ndim);
3003+
if (!shp) { *err = "Out of memory"; return value_null(); }
3004+
for (size_t i = 0; i < ndim; i++) shp[i] = (size_t)shape->as.arr.items[i]->as.num;
29103005
Value* items = malloc(sizeof(Value) * (total > 0 ? total : 1));
29113006
if (!items) { free(shp); *err = "Out of memory"; return value_null(); }
29123007
DeclType elem_type = TYPE_UNKNOWN;
@@ -3046,16 +3141,24 @@ static Value deser_val(JsonValue* obj, UnserCtx* ctx, Interpreter* interp, const
30463141
}
30473142
}
30483143
Value thr = value_thr_new();
3049-
value_thr_set_finished(thr, 1);
3050-
value_thr_set_paused(thr, json_obj_get(obj, "paused") && json_obj_get(obj, "paused")->type == JSON_BOOL ? json_obj_get(obj, "paused")->as.boolean : 0);
3144+
// Set lifecycle flags from serialized form. Default to not finished/not stopped/not started.
3145+
JsonValue* finished_j = json_obj_get(obj, "finished");
3146+
JsonValue* stop_j = json_obj_get(obj, "stop");
3147+
JsonValue* paused_j = json_obj_get(obj, "paused");
3148+
int finished_flag = (finished_j && finished_j->type == JSON_BOOL) ? finished_j->as.boolean : 0;
3149+
int stop_flag = (stop_j && stop_j->type == JSON_BOOL) ? stop_j->as.boolean : 0;
3150+
int paused_flag = (paused_j && paused_j->type == JSON_BOOL) ? paused_j->as.boolean : 0;
3151+
value_thr_set_finished(thr, finished_flag);
3152+
value_thr_set_stop_requested(thr, stop_flag);
3153+
value_thr_set_paused(thr, paused_flag);
30513154
value_thr_set_started(thr, 0);
30523155
thr.as.thr->body = NULL;
30533156
thr.as.thr->env = NULL;
3157+
if (id) unser_thr_set(ctx, id, thr.as.thr);
30543158
JsonValue* blk = json_obj_get(obj, "block");
30553159
JsonValue* envv = json_obj_get(obj, "env");
30563160
if (blk && blk->type == JSON_OBJ) thr.as.thr->body = deser_stmt(blk, ctx, interp, err);
30573161
if (envv && envv->type == JSON_OBJ) thr.as.thr->env = deser_env(envv, ctx, interp, err);
3058-
if (id) unser_thr_set(ctx, id, thr.as.thr);
30593162
return thr;
30603163
}
30613164

src/value.c

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ Value value_thr_new(void) {
5555
if (!t) { fprintf(stderr, "Out of memory\n"); exit(1); }
5656
t->finished = 0;
5757
t->paused = 0;
58+
t->stop_requested = 0;
5859
t->refcount = 1;
5960
t->started = 0;
6061
t->body = NULL;
@@ -66,11 +67,27 @@ Value value_thr_new(void) {
6667

6768
int value_thr_is_running(Value v) {
6869
if (v.type != VAL_THR || !v.as.thr) return 0;
69-
int finished = 0;
70+
int finished_or_stopping = 0;
7071
mtx_lock(&v.as.thr->state_lock);
71-
finished = v.as.thr->finished;
72+
finished_or_stopping = v.as.thr->finished || v.as.thr->stop_requested;
73+
mtx_unlock(&v.as.thr->state_lock);
74+
return finished_or_stopping ? 0 : 1;
75+
}
76+
77+
void value_thr_set_stop_requested(Value v, int stop_requested) {
78+
if (v.type != VAL_THR || !v.as.thr) return;
79+
mtx_lock(&v.as.thr->state_lock);
80+
v.as.thr->stop_requested = stop_requested ? 1 : 0;
81+
mtx_unlock(&v.as.thr->state_lock);
82+
}
83+
84+
int value_thr_get_stop_requested(Value v) {
85+
if (v.type != VAL_THR || !v.as.thr) return 0;
86+
int stop = 0;
87+
mtx_lock(&v.as.thr->state_lock);
88+
stop = v.as.thr->stop_requested;
7289
mtx_unlock(&v.as.thr->state_lock);
73-
return finished ? 0 : 1;
90+
return stop;
7491
}
7592

7693
void value_thr_set_finished(Value v, int finished) {

src/value.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ struct Value; // forward declare Value for Tensor.data
2626
typedef struct Thr {
2727
int finished; // 0 = running, 1 = finished/stopped
2828
int paused;
29+
int stop_requested;
2930
int refcount;
3031
#if 1
3132
int started;
@@ -119,6 +120,8 @@ void value_thr_set_finished(Value v, int finished);
119120
int value_thr_get_finished(Value v);
120121
void value_thr_set_paused(Value v, int paused);
121122
int value_thr_get_paused(Value v);
123+
void value_thr_set_stop_requested(Value v, int stop_requested);
124+
int value_thr_get_stop_requested(Value v);
122125
void value_thr_set_started(Value v, int started);
123126
int value_thr_get_started(Value v);
124127
// Note: pointer semantics are implemented at the EnvEntry (alias) level; no PTR Value type.

0 commit comments

Comments
 (0)