aboutsummaryrefslogtreecommitdiff
path: root/src/solvers/h48/solve.h
diff options
context:
space:
mode:
authorSebastiano Tronto <sebastiano@tronto.net>2025-05-23 16:48:58 +0200
committerSebastiano Tronto <sebastiano@tronto.net>2025-05-23 16:54:59 +0200
commitc6a77f30f64be73a5e55e06336975f2ecfbb2324 (patch)
tree3c243fbee268b824f18c5dc4d5bff9a9413b9407 /src/solvers/h48/solve.h
parent62d87e063318cc4c842b1b2d8c184f48aeaf6659 (diff)
downloadnissy-core-c6a77f30f64be73a5e55e06336975f2ecfbb2324.tar.gz
nissy-core-c6a77f30f64be73a5e55e06336975f2ecfbb2324.zip
Do all loggin in main thread
Before this committ, the solver (via the generic solution-appender routines in src/solve/solutions.h) and the H48 data generator did some logging in the worker threads, without using any locks. This was not nice, but in practice it did not cause any problem, because the log messages were rare. However, this turned out to be a problem when building to WASM, because web workers do not have access to the main JS memory, and therefore they cannot call functions from the main JS. This includes not only the callback functions for logging, but also those for polling the status of the solver (run / pause / stop). This commit fixes this at the cost or being somewhat inelegant: the solutions are not logged as they are found, but only every 500ms.
Diffstat (limited to 'src/solvers/h48/solve.h')
-rw-r--r--src/solvers/h48/solve.h136
1 files changed, 79 insertions, 57 deletions
diff --git a/src/solvers/h48/solve.h b/src/solvers/h48/solve.h
index 2818c09..4d3c451 100644
--- a/src/solvers/h48/solve.h
+++ b/src/solvers/h48/solve.h
@@ -35,10 +35,8 @@ typedef struct {
35 solve_h48_task_t *tasks; 35 solve_h48_task_t *tasks;
36 int thread_id; 36 int thread_id;
37 pthread_mutex_t *solutions_mutex; 37 pthread_mutex_t *solutions_mutex;
38 int (*poll_status)(void *); 38 _Atomic int *status;
39 void *poll_status_data; 39 _Atomic bool thread_done;
40 _Atomic bool cancelled;
41 _Atomic bool cantsleep;
42} dfsarg_solve_h48_t; 40} dfsarg_solve_h48_t;
43 41
44typedef struct { 42typedef struct {
@@ -58,9 +56,9 @@ STATIC_INLINE bool solve_h48_stop(dfsarg_solve_h48_t [static 1]);
58STATIC int64_t solve_h48_maketasks( 56STATIC int64_t solve_h48_maketasks(
59 dfsarg_solve_h48_t [static 1], dfsarg_solve_h48_maketasks_t [static 1], 57 dfsarg_solve_h48_t [static 1], dfsarg_solve_h48_maketasks_t [static 1],
60 solve_h48_task_t [static STARTING_CUBES], int [static 1]); 58 solve_h48_task_t [static STARTING_CUBES], int [static 1]);
61STATIC bool solve_h48_runthread_continue(dfsarg_solve_h48_t *);
62STATIC void *solve_h48_runthread(void *); 59STATIC void *solve_h48_runthread(void *);
63STATIC int64_t solve_h48_dfs(dfsarg_solve_h48_t [static 1]); 60STATIC int64_t solve_h48_dfs(dfsarg_solve_h48_t [static 1]);
61STATIC void solve_h48_log_solutions(solution_list_t [static 1], size_t);
64STATIC int64_t solve_h48(oriented_cube_t, uint8_t, uint8_t, uint8_t, uint8_t, 62STATIC int64_t solve_h48(oriented_cube_t, uint8_t, uint8_t, uint8_t, uint8_t,
65 uint8_t, uint64_t, const unsigned char *, size_t n, char [n], 63 uint8_t, uint64_t, const unsigned char *, size_t n, char [n],
66 long long [static NISSY_SIZE_SOLVE_STATS], int (*)(void *), void *); 64 long long [static NISSY_SIZE_SOLVE_STATS], int (*)(void *), void *);
@@ -201,7 +199,7 @@ solve_h48_dfs(dfsarg_solve_h48_t arg[static 1])
201 return 0; 199 return 0;
202 pthread_mutex_lock(arg->solutions_mutex); 200 pthread_mutex_lock(arg->solutions_mutex);
203 ret = appendsolution(arg->solution_moves, 201 ret = appendsolution(arg->solution_moves,
204 arg->solution_settings, arg->solution_list, true, "H48"); 202 arg->solution_settings, arg->solution_list);
205 pthread_mutex_unlock(arg->solutions_mutex); 203 pthread_mutex_unlock(arg->solutions_mutex);
206 return ret; 204 return ret;
207 } 205 }
@@ -271,41 +269,20 @@ solve_h48_dfs(dfsarg_solve_h48_t arg[static 1])
271 return ret; 269 return ret;
272} 270}
273 271
274STATIC bool
275solve_h48_runthread_continue(dfsarg_solve_h48_t *arg)
276{
277 int status;
278
279 for (status = NISSY_STATUS_PAUSE; status == NISSY_STATUS_PAUSE; ) {
280 status = arg->poll_status == NULL ? NISSY_STATUS_RUN :
281 arg->poll_status(arg->poll_status_data);
282 msleep(500);
283 }
284
285 return status == NISSY_STATUS_RUN;
286}
287
288STATIC void * 272STATIC void *
289solve_h48_runthread(void *arg) 273solve_h48_runthread(void *arg)
290{ 274{
291 int i, j, status; 275 int i, j;
292 solve_h48_task_t task; 276 solve_h48_task_t task;
293 dfsarg_solve_h48_t *dfsarg; 277 dfsarg_solve_h48_t *dfsarg;
294 278
295 dfsarg = (dfsarg_solve_h48_t *)arg; 279 dfsarg = (dfsarg_solve_h48_t *)arg;
296 280
297 for (i = dfsarg->thread_id; i < dfsarg->ntasks; i += dfsarg->threads) { 281 for (i = dfsarg->thread_id; i < dfsarg->ntasks; i += dfsarg->threads) {
298 status = dfsarg->poll_status == NULL ? NISSY_STATUS_RUN : 282 if (*dfsarg->status == NISSY_STATUS_STOP)
299 dfsarg->poll_status(dfsarg->poll_status_data); 283 goto solve_h48_runthread_end;
300 switch (status) { 284 while (*dfsarg->status == NISSY_STATUS_PAUSE)
301 case NISSY_STATUS_STOP: 285 msleep(BASE_SLEEP_TIME);
302 goto solve_h48_runthread_cancel;
303 case NISSY_STATUS_PAUSE:
304 if (!NISSY_CANSLEEP)
305 goto solve_h48_runthread_cantsleep;
306 if (!solve_h48_runthread_continue(dfsarg))
307 goto solve_h48_runthread_cancel;
308 }
309 286
310 task = dfsarg->tasks[i]; 287 task = dfsarg->tasks[i];
311 288
@@ -329,12 +306,8 @@ solve_h48_runthread(void *arg)
329 solve_h48_dfs(dfsarg); 306 solve_h48_dfs(dfsarg);
330 } 307 }
331 308
332 return NULL; 309solve_h48_runthread_end:
333 310 dfsarg->thread_done = true;
334solve_h48_runthread_cantsleep:
335 dfsarg->cantsleep = true;
336solve_h48_runthread_cancel:
337 dfsarg->cancelled = true;
338 return NULL; 311 return NULL;
339} 312}
340 313
@@ -366,7 +339,7 @@ solve_h48_maketasks(
366 maketasks_arg->moves, maketasks_arg->nmoves); 339 maketasks_arg->moves, maketasks_arg->nmoves);
367 340
368 appret = appendsolution(&moves, solve_arg->solution_settings, 341 appret = appendsolution(&moves, solve_arg->solution_settings,
369 solve_arg->solution_list, true, "H48"); 342 solve_arg->solution_list);
370 return appret < 0 ? appret : NISSY_OK; 343 return appret < 0 ? appret : NISSY_OK;
371 } 344 }
372 345
@@ -410,6 +383,22 @@ solve_h48_maketasks(
410 return NISSY_OK; 383 return NISSY_OK;
411} 384}
412 385
386STATIC void
387solve_h48_log_solutions(solution_list_t s[static 1], size_t e)
388{
389 size_t i;
390 char b;
391 while (e != s->used) {
392 LOG("[h48 solve] Found solution: ");
393 for (i = e; s->buf[i] != '\n' && s->buf[i] != '\0'; i++) ;
394 b = s->buf[i];
395 s->buf[i] = '\0';
396 LOG("%s\n", s->buf + e);
397 s->buf[i] = b;
398 e = i + 1;
399 }
400}
401
413STATIC int64_t 402STATIC int64_t
414solve_h48( 403solve_h48(
415 oriented_cube_t oc, 404 oriented_cube_t oc,
@@ -427,8 +416,10 @@ solve_h48(
427 void *poll_status_data 416 void *poll_status_data
428) 417)
429{ 418{
430 bool anycancelled, anycantsleep;
431 int i, ntasks, eoesep_table_index; 419 int i, ntasks, eoesep_table_index;
420 bool td, fp;
421 _Atomic int status;
422 size_t lastused;
432 int8_t d; 423 int8_t d;
433 dfsarg_solve_h48_t arg[THREADS]; 424 dfsarg_solve_h48_t arg[THREADS];
434 solve_h48_task_t tasks[STARTING_CUBES]; 425 solve_h48_task_t tasks[STARTING_CUBES];
@@ -508,10 +499,7 @@ solve_h48(
508 .threads = threads, 499 .threads = threads,
509 .thread_id = i, 500 .thread_id = i,
510 .solutions_mutex = &solutions_mutex, 501 .solutions_mutex = &solutions_mutex,
511 .poll_status = poll_status, 502 .status = &status,
512 .poll_status_data = poll_status_data,
513 .cancelled = false,
514 .cantsleep = false,
515 }; 503 };
516 504
517 } 505 }
@@ -538,35 +526,69 @@ solve_h48(
538 526
539 LOG("[H48 solve] Prepared %d tasks\n", ntasks); 527 LOG("[H48 solve] Prepared %d tasks\n", ntasks);
540 528
541 anycancelled = anycantsleep = false; 529 solve_h48_log_solutions(&sollist, 0);
530 lastused = sollist.used;
531 status = poll_status == NULL ? NISSY_STATUS_RUN :
532 poll_status(poll_status_data);
533 if (!NISSY_CANSLEEP) {
534 LOG("[solve h48] Pause / Stop / Resume functionality won't "
535 "be available on this system (can't sleep()).\n");
536 }
542 for ( 537 for (
543 d = MAX(minmoves, STARTING_MOVES + 1); 538 d = MAX(minmoves, STARTING_MOVES + 1);
544 !(solutions_done(&sollist, &settings, d) || anycancelled); 539 !(solutions_done(&sollist, &settings, d)) &&
540 status != NISSY_STATUS_STOP;
545 d++ 541 d++
546 ) { 542 ) {
547 if (d >= 15) 543 if (d >= 15) {
548 LOG("[H48 solve] Found %" PRId64 " solutions, " 544 LOG("[H48 solve] Found %" PRId64 " solutions, "
549 "searching at depth %" PRId8 "\n", 545 "searching at depth %" PRId8 "\n",
550 sollist.nsols, d); 546 sollist.nsols, d);
547 }
548
551 for (i = 0; i < threads; i++) { 549 for (i = 0; i < threads; i++) {
552 arg[i].target_depth = d; 550 arg[i].target_depth = d;
551 arg[i].thread_done = false;
553 pthread_create( 552 pthread_create(
554 &thread[i], NULL, solve_h48_runthread, &arg[i]); 553 &thread[i], NULL, solve_h48_runthread, &arg[i]);
555 } 554 }
556 for (i = 0; i < threads; i++) { 555
557 pthread_join(thread[i], NULL); 556 /* Log solutions and handle pause / stop / resume */
558 anycancelled = anycancelled || arg[i].cancelled; 557 if (d >= 15 && NISSY_CANSLEEP) {
559 anycantsleep = anycantsleep || arg[i].cantsleep; 558 td = false;
559 fp = true;
560 while (!td && status != NISSY_STATUS_STOP) {
561 msleep(BASE_SLEEP_TIME);
562
563 pthread_mutex_lock(&solutions_mutex);
564 solve_h48_log_solutions(&sollist, lastused);
565 lastused = sollist.used;
566 pthread_mutex_unlock(&solutions_mutex);
567
568 if (poll_status == NULL)
569 continue;
570
571 status = poll_status(poll_status_data);
572 if (status == NISSY_STATUS_PAUSE && fp) {
573 LOG("[H48 solve] Paused\n");
574 fp = false;
575 }
576 if (status == NISSY_STATUS_RUN)
577 fp = true;
578
579 for (td = true, i = 0; i < threads; i++)
580 td = td && arg[i].thread_done;
581 }
560 } 582 }
561 }
562 583
563 if (anycantsleep) { 584 for (i = 0; i < threads; i++)
564 LOG("[H48 solve] Received pause request, but this feature is " 585 pthread_join(thread[i], NULL);
565 "not available on this system. " 586
566 "Taking it as a stop request.\n"); 587 solve_h48_log_solutions(&sollist, lastused);
588 lastused = sollist.used;
567 } 589 }
568 590
569 if (anycancelled) { 591 if (status == NISSY_STATUS_STOP) {
570 LOG("[H48 solve] Received stop request, ending solution " 592 LOG("[H48 solve] Received stop request, ending solution "
571 "search early.\n"); 593 "search early.\n");
572 } 594 }

Generated with cgit - Back to sebastiano.tronto.net