git.haldean.org ubik / e2d2d42
fix enqueue order logic for already-queued jobs Haldean Brown 5 years ago
1 changed file(s) with 72 addition(s) and 14 deletion(s). Raw diff Collapse all Expand all
4343
4444 #define dprint(...) do { if (cenv->debug) printf(__VA_ARGS__); } while (0)
4545
46 /* Returns an error if not all imports for the given job are in the compiled
47 * list in the provided environment. */
48 no_ignore static ubik_error
49 ensure_imports_ready(
50 struct ubik_compile_env *cenv,
51 struct ubik_compile_job *job);
52
4653 no_ignore ubik_error
4754 ubik_compile_env_default(
4855 struct ubik_compile_env *cenv,
407414 return OK;
408415 }
409416
417 /* Moves a job to the top of the request stack, along with all of its
418 * dependencies. When we attempt to reenqueue a job that has already been
419 * enqueued, we need to pull it one to the top of the stack; if module A
420 * depends on modules B and C, after loading A's AST you have:
421 *
422 * [bottom] A B C [top]
423 *
424 * If, in the process of loading C's AST, we discover it depends on B, it is
425 * not sufficient to leave the stack as-is, because it will lead to us
426 * attempting to compile C before B, which will raise an error. It means we
427 * need to bring B back up to the top, to make the stack:
428 *
429 * [bottom] A C B [top]
430 */
431 void
432 requeue(struct ubik_compile_env *cenv, size_t i)
433 {
434 struct ubik_compile_job *job;
435 struct ubik_compile_job *check;
436 struct ubik_ast_import_list *import;
437 size_t j;
438 ubik_error err;
439
440 job = cenv->to_compile.elems[i];
441 for (j = i + 1; j < cenv->to_compile.n; j++)
442 cenv->to_compile.elems[j - 1] = cenv->to_compile.elems[j];
443 cenv->to_compile.elems[cenv->to_compile.n - 1] = job;
444
445 /* If we haven't loaded the AST yet, we'll end up making sure the stack
446 * is correct when we load its imports at some point in the future.
447 * There's nothing we can do now. */
448 if (job->status == COMPILE_WAIT_FOR_AST)
449 return;
450
451 /* If all of this job's imports are ready, then we don't have to do
452 * anything to fix this. Otherwise, we need to requeue all of its
453 * dependencies. */
454 err = ensure_imports_ready(cenv, job);
455 if (err == OK)
456 return;
457 free(err);
458
459 import = job->ast->imports;
460 while (import != NULL)
461 {
462 for (j = 0; j < cenv->to_compile.n; j++)
463 {
464 check = cenv->to_compile.elems[j];
465 if (check->request->package_name == NULL)
466 continue;
467 if (strcmp(check->request->package_name,
468 import->canonical))
469 {
470 requeue(cenv, j);
471 break;
472 }
473 }
474 import = import->next;
475 }
476 }
477
410478 no_ignore ubik_error
411479 ubik_compile_enqueue(
412480 struct ubik_compile_env *cenv,
424492 {
425493 check_job = (struct ubik_compile_job *)
426494 cenv->to_compile.elems[i];
427
428 /* TODO: this is not sufficient! if this happens, we need to
429 * pull this one to the top of the stack; if module A depends
430 * on modules B and C, after loading A's AST you have:
431 * [bottom] A B C [top]
432 * If, in the process of loading C's AST, we discover it
433 * depends on B, it is not sufficient to leave the stack as-is,
434 * because it will lead to us attempting to compile C before B,
435 * which will raise an error. It means we need to bring B back
436 * up to the top, to make the stack:
437 * [bottom] A C B [top]
438 */
439 if (strcmp(check_job->request->source_name, src) == 0)
440 return OK;
495 if (strcmp(check_job->request->source_name, src) != 0)
496 continue;
497 requeue(cenv, i);
498 return OK;
441499 }
442500 for (i = 0; i < cenv->compiled.n; i++)
443501 {