#ifndef lint static char sccsid[] = "@(#)processes.c 9.10 88/02/10"; #endif /* * Copyright (c) 1987 by Sun Microsystems, Inc. */ /* Routines for manipulating PostScript processes processes.c, Mon Mar 18 10:38:11 1985 James Gosling, Sun Microsystems */ #ifdef REF #include #include #endif #include "PostScript.h" #include "input.h" extern char **environ; struct execution_environment *process_free_list;/* process carcasses that are waiting to have new life breathed into them */ struct execution_environment *waiting_procs; /* The set of processes waiting for activity in another process */ struct execution_environment *process_set; /* The PostScript run Q */ int process_population; /* The number of processes that currently exist */ static struct body *ProcessDied_keyword; /* Create a new PostScript process */ struct execution_environment * create_process() { register struct execution_environment *ee; int retainpath; process_population++; if (ee = process_free_list) { process_free_list = ee->next; retainpath = 1; } else { ee = (struct execution_environment *) snoopalloc("processes.c", sizeof *ee); ee->execution_stack = (struct execution_stack *) snoopalloc("processes.c", 100 * sizeof (struct execution_stack)); ee->operand_stack = new_array_body(20); ee->operand_stack->refcnt = maximum_refcnt; ee->dictionary_stack = (struct dictstack_ent *) snoopalloc ("processes.c", 10 * sizeof (struct dictstack_ent)); ee->dict_limit = ee->dictionary_stack+10; ee->static_buffer = 0; ee->bufsize = 0; retainpath = 0; ee->body_handle = new_body(process); ee->body_handle->type = process_type; } ee->interests = 0; ee->eq_head = 0; ee->eq_tail = 0; ee->body_handle->body.process.env = ee; clear_object(&ee->body_handle->body.process.terminal_value); clear_object(&ee->execee); ee->body_handle->refcnt = 1; ee->underflow = &ee->operand_stack->body.array.objects[0]; ee->overflow = &ee->operand_stack->body.array.objects[ee->operand_stack->body.array.size]; ee->optop = ee->underflow; ee->dict_top = ee->dictionary_stack; ee->pos = ee->execution_stack; ee->limit = ee->pos + (100 - 1); ee->last_executed.type = null_type; ee->fill = 0; ee->event = 0; ee->seeking_token = 0; ee->stdprnt = stdio_file; ee->stddiag = stdio_file; incref(stdio_file); incref(stdio_file); ee->restart_state = 0; ee->winevents = 0; ee->next = 0; ee->pgnext = ee; ee->pgprev = ee; enqueue_process(ee); ee->arrstart = -1; cs_initcontext(&ee->gontext,empty_pixrect,retainpath); ee->error_code = no_error_code; ee->error_detail = 0; ee->dict_top->body = system_dictionary; ee->dict_top->obj = 0; ee->seeking_token = 0; ee->detail_desired = 0; ee->dict_top++; incref(system_dictionary); if (verbose) printf("Created process %o\n", ee); return ee; } #define MAX_PROCESS_STACK_SIZE 1500 grow_stack(ee, n) register struct execution_environment *ee; { register new = ee->operand_stack->body.array.size + n; register top = ee->optop - ee->underflow; if (new > MAX_PROCESS_STACK_SIZE) return -1; new = (new * 3)>>1; if (new > MAX_PROCESS_STACK_SIZE) new = MAX_PROCESS_STACK_SIZE; if (!extend_growable(ee->operand_stack, new)) return -1; ee->underflow = &ee->operand_stack->body.array.objects[0]; ee->overflow = &ee->operand_stack->body.array.objects [ee->operand_stack->body.array.size - 1]; ee->optop = &ee->underflow[top]; return 0; } free_process(ee) register struct execution_environment *ee; { register struct input_region *p; register struct input_event_handler *ep; register struct input_region_set *irs; if (ee->pgnext == 0) return; assert(ee->dict_top <= ee->dict_limit); #ifdef EStackDebug assert(ee->dict_limit - ee->dictionary_stack == 10 || Enlarged(ee)); #endif ee->pgnext->pgprev = ee->pgprev; ee->pgprev->pgnext = ee->pgnext; ee->pgnext = 0; ee->pgprev = 0; if (ee->event > 0) process_readers[ee->event] = 0; if (ee->event == process_activity_wait) { register struct execution_environment **p = &waiting_procs; while (*p) if (*p == ee) { *p = ee->next; ee->event = 0; ee->next = 0; break; } else p = &(*p)->next; assert(ee->event == 0); } while (ee->pos > ee->execution_stack) { switch (ee->pos->type) { case forall_execution: object_decref(&ee->pos->env.forall); break; case monitor_execution: disentangle_monitor(ee, body_of(&ee->pos->env.monitor)); break; case buildimage_execution: pr_destroy(ee->pos->env.image.image); break; } object_decref(&ee->pos->executed); ee->pos--; } ee->pos = 0; { /* Create the ProcessDied event */ register struct body *b; b = createevent(); set_typed_bodied_object(&b->body.event.name, keyword_type, ProcessDied_keyword); set_typed_bodied_object(&b->body.event.action, process_type, ee->body_handle); incref(ee->body_handle); b->body.event.time = last_event_time; enqueueEvent(b); } if (ee->body_handle && ee->body_handle->refcnt > 0) { if (ee->optop > ee->underflow) ee->body_handle->body.process.terminal_value = *--ee->optop; else clear_object(&ee->body_handle->body.process.terminal_value); } while (--ee->optop >= ee->underflow) object_decref(ee->optop); while (ee->dict_top > ee->dictionary_stack) { ee->dict_top--; if (ee->dict_top->obj) { decref(ee->dict_top->obj); } else decref(ee->dict_top->body); } if (ee->bufsize > 0) { free(ee->static_buffer); ee->bufsize = 0; ee->static_buffer = 0; } cs_grestoreall(&ee->gontext); cs_setcanvas(&ee->gontext, (struct canvas *) 0); cs_setfont(&ee->gontext, (struct psfont *) 0); cs_newpath(&ee->gontext); assert(ee->stdprnt); decref(ee->stdprnt); ee->stdprnt = 0; assert(ee->stddiag); decref(ee->stddiag); ee->stddiag = 0; while (ee->eq_head) { register struct body *next = ee->eq_head->body.event.next; decref(ee->eq_head); ee->eq_head = next; } dequeue_process(ee); { extern struct execution_environment *event_logger; if (ee == event_logger) event_logger = 0; } assert(ee->body_handle); if (ee->body_handle->refcnt > 0) { if (verbose) printf("Process %o in limbo\n", ee); ee->event = zombie_process; } else { if (verbose) printf("Process %o died\n", ee); ee->event = dead_process; ee->next = process_free_list; process_free_list = ee; } if (--process_population <= 0) { printf("Sic transit gloria PostScript\n"); restore_keyboard(); exit(0); } while (ee->interests) untangle_event(ee->interests); { register struct execution_environment **p = &waiting_procs; register struct execution_environment *ne; while (ne = *p) if (ne->arrstart == (int) ee) { assert(ne->event == process_activity_wait); ee->arrstart = -1; *p = ne->next; ne->next = 0; ne->event = 0; /* DEBUG */ enqueue_process(ne); if (verbose) printf("Waking %o\n", ne); } else p = &ne->next; } } static kill_one_process(p) register struct execution_environment *p; { p->error_code = killprocess_error_code; switch (p->event) { case process_activity_wait: { register struct execution_environment **waitp = &waiting_procs; while (*waitp) if (*waitp == p) { *waitp = p->next; p->event = 0; p->next = 0; break; } else waitp = &(*waitp)->next; assert(p->event == 0); } break; case monitor_wait: disentangle_monitor(p, body_of(&p->pos->env.monitor)); p->event = 0; break; } p->restart_state = 0; enqueue_process(p); } kill_process_group(ee) register struct execution_environment *ee; { register struct execution_environment *p = ee; do { kill_one_process(p); p = p->pgnext; } while (p && p != ee); } enqueue_process(ee) register struct execution_environment *ee; { assert(ee->event != process_activity_wait); assert(ee->event != monitor_wait); if (ee->next == 0 && ee->event != dead_process && ee->event != zombie_process) { if (process_set) { ee->next = process_set->next; process_set->next = ee; } else ee->next = ee; process_set = ee; } } dequeue_process(ee) register struct execution_environment *ee; { if (ee->next) { register struct execution_environment *ep; assert(process_set != 0); ep = process_set; do { if (ep->next == ee) { ep->next = ee->next; ee->next = 0; if (process_set == ee) process_set = ee != ep ? ep : 0; break; } } while ((ep = ep->next) != process_set); } assert(ee->next == 0); } echodiagnostics(ee) register struct execution_environment *ee; { incref(ee->stdprnt); decref(ee->stddiag); ee->stddiag = ee->stdprnt; } toggleverbose(ee) struct execution_environment *ee; { verbose = !verbose; psio_fprintf (ee->stddiag->body.file.outbuf, verbose ? "I'll let you know what's happening\n" : "OK, I can take a hint, I'll shut up\n"); } spawn_unix_process(ee) register struct execution_environment *ee; { register struct object *optop = ee->optop; if (optop[-1].type != string_type) { ee->error_code = typecheck_error_code; return; } if (osi_spawn_process(body_of(optop - 1)->body.string.chars + optop[-1].value.substring.start, optop[-1].value.substring.length)) ee->error_code = undefinedfilename_error_code; else { ee->optop--; object_decref(optop - 1); } } currentprocess(ee) register struct execution_environment *ee; { set_typed_bodied_object(ee->optop, process_type, ee->body_handle); object_incref(ee->optop); ee->optop++; } newprocessgroup(ee) register struct execution_environment *ee; { ee->pgnext->pgprev = ee->pgprev; ee->pgprev->pgnext = ee->pgnext; ee->pgnext = ee; ee->pgprev = ee; } killprocessgroup(ee) register struct execution_environment *ee; { register struct object *optop = ee->optop; if (optop[-1].type != process_type) { ee->error_code = typecheck_error_code; return; } ee->optop--; object_decref(ee->optop); kill_process_group(body_of(optop-1)->body.process.env); } killprocess(ee) register struct execution_environment *ee; { if (ee->optop[-1].type != process_type) { ee->error_code = typecheck_error_code; return; } ee->optop--; kill_one_process(body_of(ee->optop)->body.process.env); object_decref(ee->optop); } suspendprocess(ee) register struct execution_environment *ee; { register struct execution_environment *ne; register struct object *optop = ee->optop; if (optop[-1].type != process_type) { ee->error_code = typecheck_error_code; return; } ne = body_of(optop-1)->body.process.env; if (ne->next == 0) { ee->error_code = invalidaccess_error_code; return; } ee->optop--; dequeue_process (ne); ne->event = suspended_process; object_decref(ee->optop); } continueprocess(ee) register struct execution_environment *ee; { register struct execution_environment *ne; register struct object *optop = ee->optop; if (optop[-1].type != process_type) { ee->error_code = typecheck_error_code; return; } ee->optop--; ne = body_of(optop-1)->body.process.env; if (ne->event != suspended_process) { ee->error_code = invalidaccess_error_code; return; } ne->event = 0; enqueue_process (ne); object_decref(ee->optop); } #ifdef EStackDebug static struct execution_environment **enp; static struct execution_environment *enl[200]; static Enlarged(ee) register struct execution_environment *ee; { register struct execution_environment **p; for (p = enl; *p; p++) if (*p == ee) return 1; return 0; } #endif /* Ensure that the dictionary stack of process "ee" has room for "n" new entries; fails only if we're running out of memory */ enlarge_dict_space(ee, n) register struct execution_environment *ee; register n; { if (ee->dict_top + n >= ee->dict_limit) { register offset = ee->dict_top - ee->dictionary_stack; register ns = offset + 2 + n; register struct dictstack_ent *new; new = (struct dictstack_ent *) snooprealloc("operators.h", ee->dictionary_stack, ns * sizeof *ee->dictionary_stack); #ifdef EStackDebug if (enp == 0) enp = enl; *enp++ = ee; /* psio_fprintf(psio_stdout, "0x%x->0x%x in 0x%x\n", ee->dictionary_stack, new, ee); */ #endif if (new == 0) { if (current_process) current_process->error_code = VMerror_error_code; return 0; } ee->dictionary_stack = new; ee->dict_top = new + offset; ee->dict_limit = new + ns; } return 1; } initialize_processes () { define_operator("verbose", toggleverbose, 0, 0, 0); define_operator("forkunix", spawn_unix_process, 0, 1, 0); define_operator("currentprocess", currentprocess, 0, 0, 1); define_operator("newprocessgroup", newprocessgroup, 0, 0, 0); define_operator("killprocessgroup", killprocessgroup, 0, 1, 0); define_operator("killprocess", killprocess, 0, 1, 0); define_operator("suspendprocess", suspendprocess, 0, 1, 0); define_operator("continueprocess", continueprocess, 0, 1, 0); ProcessDied_keyword = get_name("ProcessDied", -1); }