struct buf* buf_new ( struct vnode * vp, lblkno_t blkno ) { struct buf *bp; LIST *pBufHead = &vp->v_mount->mnt_buflist; for (bp = (struct buf *) LIST_TAIL (pBufHead); bp != NULL; bp = (struct buf *) LIST_PREV (&bp->b_node)) { if ((bp->b_flags & B_BUSY) == 0) { bp->b_flags = B_BUSY; bp->b_lblkno = 0; bp->b_count = 0; bp->b_dev = -1; bp->b_vp = NULL; bp->b_error = OK; bp->b_resid = 0; return (bp); } } return (NULL); }
Val _lib7_P_Process_exece (Task* task, Val arg) { //===================== // // _lib7_P_Process_exece : String * String list * String list -> 'a // // Overlay a new process image, using specified environment. // // This fn gets bound as exece in: // // src/lib/std/src/posix-1003.1b/posix-process.pkg Val path = GET_TUPLE_SLOT_AS_VAL( arg, 0 ); Val arglst = GET_TUPLE_SLOT_AS_VAL( arg, 1 ); Val envlst = GET_TUPLE_SLOT_AS_VAL( arg, 2 ); // Use the heap for temp space for // the argv[] and envp[] vectors: // char** cp = (char**)(task->heap_allocation_pointer); #ifdef SIZES_C_64_MYTHRYL_32 // // 8-byte align it: // cp = (char**) ROUND_UP_TO_POWER_OF_TWO((Unt2)cp, POINTER_BYTESIZE); #endif char** argv = cp; // for (Val p = arglst; p != LIST_NIL; p = LIST_TAIL(p)) { *cp++ = HEAP_STRING_AS_C_STRING(LIST_HEAD(p)); } *cp++ = 0; // Terminate the argv[]. char** envp = cp; // for (Val p = envlst; p != LIST_NIL; p = LIST_TAIL(p)) { *cp++ = HEAP_STRING_AS_C_STRING(LIST_HEAD(p)); } *cp++ = 0; // Terminate the envp[]. int status = execve( HEAP_STRING_AS_C_STRING(path), argv, envp ); CHECK_RETURN (task, status) }
static void init_world_terrain( WORLD *world, int x, int y, int cw, int ch ) { int i, sx, sy; int mw, mh; FIELD *f, *fs, *fm, *fe, *field; sx = x / (world->tile_width * cw); sy = y / (world->tile_height * ch); mw = world->map->w / cw; mh = world->map->h / ch; for (i = 0; i < mh; i++) { f = process_world_row(world, i, mw, sx, sy, cw, ch, (i + 1) % 2); if (f != NULL) fm = f; } fs = (FIELD *) LIST_HEAD(&world->fieldList); fe = (FIELD *) LIST_TAIL(&world->fieldList); for(field = (FIELD *) LIST_TAIL(&world->fieldList); field != NULL; field = (FIELD *) LIST_PREV(&field->listNode)) { f = (FIELD *) LIST_PREV(&field->listNode); if (f == NULL) break; add_world_road_to(world, field, f); add_world_road_to(world, field, fs); add_world_road_to(world, field, fm); add_world_road_to(world, field, fe); } reveal_world_terrain(world, x, y); }
Val _lib7_P_Process_exec (Task* task, Val arg) { //===================== // // Mythryl type: (String, List(String) -> X // // Overlay a new process image // // This fn gets bound as exec in: // // src/lib/std/src/posix-1003.1b/posix-process.pkg ENTER_MYTHRYL_CALLABLE_C_FN("_lib7_P_Process_exec"); Val path = GET_TUPLE_SLOT_AS_VAL(arg, 0); Val arglst = GET_TUPLE_SLOT_AS_VAL(arg, 1); // Use the heap for temp space for the argv[] vector // char** cp = (char**) (task->heap_allocation_pointer); #ifdef SIZES_C_64_MYTHRYL_32 // // 8-byte align it: // cp = (char **)ROUNDUP((Unt2)cp, POINTER_BYTESIZE); #endif char** argv = cp; // for (Val p = arglst; p != LIST_NIL; p = LIST_TAIL(p)) { // *cp++ = HEAP_STRING_AS_C_STRING(LIST_HEAD(p)); } *cp++ = 0; // Terminate the argv[]. int status = execv(HEAP_STRING_AS_C_STRING(path), argv); RETURN_STATUS_EXCEPT_RAISE_SYSERR_ON_NEGATIVE_STATUS__MAY_HEAPCLEAN(task, status, NULL); }
static Val read_in_compiled_file_list__may_heapclean ( // ========================================= // Task* task, const char* compiled_files_to_load_filename, int* return_max_boot_path_len, Roots* extra_roots ){ // Open given file and read from it the list of // filenames of compiled_files to be later loaded. // Return them as a Mythryl list of Mythryl strings: #define BUF_LEN 1024 // "This should be plenty for two numbers." "640K should be enough for anyone." char buf[ BUF_LEN ]; // Val* file_names = NULL; char* name_buf = NULL; int max_num_boot_files = MAX_NUMBER_OF_BOOT_FILES; int max_boot_path_len = MAX_LENGTH_FOR_A_BOOTFILE_PATHNAME; int file_count = 0; FILE* list_fd = open_file( compiled_files_to_load_filename, FALSE ); fprintf ( stderr, " load-compiledfiles.c: Reading file %s\n", compiled_files_to_load_filename ); if (log_fd) { // fprintf ( log_fd, " load-compiledfiles.c: Reading file %s\n", compiled_files_to_load_filename ); } Val file_list = LIST_NIL; Roots roots1 = { &file_list, extra_roots }; if (list_fd) { // Read header: // for (;;) { // if (!fgets (buf, BUF_LEN, list_fd)) { die ( "compiled_files_to_load file \"%s\" ends before end-of-header (first empty line)", compiled_files_to_load_filename ); } { char* p = buf; while (*p == ' ' || *p == '\t') ++p; // Skip leading whitespace. if (p[0] == '\n') break; // Header ends at first empty line. if (p[0] == '#') continue; // Ignore comment lines. if (strstr( p,"FILES=") == p) { // max_num_boot_files = strtoul(p+6, NULL, 0); continue; } if (strstr(p,"MAX_LINE_LENGTH=") == p) { // max_boot_path_len = strtoul(p+16, NULL, 0) +2; continue; } die ( "compiled_files_to_load file \"%s\" contains unrecognized header line \"%s\"", compiled_files_to_load_filename, p ); } } if (max_num_boot_files < 0) { // die("compiled_files_to_load file \"%s\" contains negative files count?! (%d)", compiled_files_to_load_filename, max_num_boot_files ); } if (max_boot_path_len < 0) { // die("compiled_file_to_load file \"%s\" contains negative boot path len?! (%d)", compiled_files_to_load_filename, max_boot_path_len ); } *return_max_boot_path_len = max_boot_path_len; // Tell the calling function. if (!(name_buf = MALLOC( max_boot_path_len ))) { // die ("unable to allocate space for .compiled file filenames"); } // if (!(file_names = MALLOC( max_num_boot_files * sizeof(char*) ))) { // // // die ("Unable to allocate space for compiledfiles-to-load name table"); // } // Read in the file names, converting them to // Mythryl strings and saving them in a list: // while (fgets( name_buf, max_boot_path_len, list_fd )) { // Skip leading whitespace: // char* p = name_buf; while (*p == ' ' || *p == '\t') ++p; // Ignore empty lines and comment lines: // if (*p == '\n') continue; if (*p == '#') continue; // Strip any trailing newline: // { int j = strlen(p)-1; // if (p[j] == '\n') p[j] = '\0'; } if (file_count >= max_num_boot_files) die ("too many files\n"); // If our agegroup0 buffer is more than half full, // empty it by doing a heapcleaning. This is very // conservative -- which is the way I like it. *grin* // if (agegroup0_freespace_in_bytes( task ) < agegroup0_usedspace_in_bytes( task ) ){ call_heapcleaner_with_extra_roots( task, 0, &roots1 ); } Val file_name = make_ascii_string_from_c_string__may_heapclean(task, p, &roots1 ); file_list = LIST_CONS(task, file_name, file_list); } if (name_buf) FREE( name_buf ); fclose( list_fd ); } // Reverse filename list (to restore // original order) and return it: // { Val file_list2 = LIST_NIL; Roots roots2 = { &file_list2, &roots1 }; // for (; file_list != LIST_NIL; file_list = LIST_TAIL(file_list)) { // Val file_name = LIST_HEAD(file_list); // file_list2 = LIST_CONS(task, file_name, file_list2); // Again, if our agegroup0 buffer is more than // half full, empty it by doing a heapcleaning: // if (agegroup0_freespace_in_bytes( task ) < agegroup0_usedspace_in_bytes( task ) ){ call_heapcleaner_with_extra_roots( task, 0, &roots2 ); } } return file_list2; } }
void load_compiled_files__may_heapclean ( // ================================== // const char* compiled_files_to_load_filename, Heapcleaner_Args* heap_parameters, // See struct cleaner_args in src/c/h/heap.h Roots* extra_roots ){ // Load into the runtime heap all the .compiled files // listed one per line in given compiled_files_to_load file: // // This function is called from exactly one spot, in // // src/c/main/runtime-main.c int max_boot_path_len; char* filename_buf; int seen_runtime_package_picklehash = FALSE; // FALSE until we see the picklehash naming our runtime. open_logfile(); Task* task = make_task( // make_task def in src/c/main/runtime-state.c TRUE, // is_boot heap_parameters ); // Set up handlers for ^C, divide-by-zero, // integer overflow etc: // set_up_fault_handlers (); // set_up_fault_handlers def in src/c/machine-dependent/posix-arithmetic-trap-handlers.c // set_up_fault_handlers def in src/c/machine-dependent/win32-fault.c // set_up_fault_handlers def in src/c/machine-dependent/cygwin-fault.c // Set up RunVec in CStruct in // // runtime_package__global. // // This constitutes an ersatz exports list implementing // // src/lib/core/init/runtime.api // // which we will later substitute for the (useless) code from // // src/lib/core/init/runtime.pkg // // thus providing access to critical assembly fns including // // find_cfun // // implemented in one of // // src/c/machine-dependent/prim.sparc32.asm // src/c/machine-dependent/prim.pwrpc32.asm // src/c/machine-dependent/prim.intel32.asm // src/c/machine-dependent/prim.intel32.masm // construct_runtime_package__global( task ); // construct_runtime_package__global def in src/c/main/construct-runtime-package.c // Construct the list of files to be loaded: // Val compiled_file_list = read_in_compiled_file_list__may_heapclean ( task, compiled_files_to_load_filename, &max_boot_path_len, extra_roots ); Roots roots1 = { &compiled_file_list, extra_roots }; // This space is ultimately wasted: XXX BUGGO FIXME // if (! (filename_buf = MALLOC( max_boot_path_len ))) { // die ("unable to allocate space for boot file names"); } // Load all requested compiled_files into the heap: // while (compiled_file_list != LIST_NIL) { // char* filename = filename_buf; // Need to make a copy of the filename because // load_compiled_file__may_heapclean is going to scribble into it: // strcpy( filename_buf, HEAP_STRING_AS_C_STRING( LIST_HEAD( compiled_file_list ))); compiled_file_list = LIST_TAIL( compiled_file_list ); // Remove above filename from list of files to process. // If 'filename' does not begin with "RUNTIME_PACKAGE_PICKLEHASH=" ... // if (strstr(filename,"RUNTIME_PACKAGE_PICKLEHASH=") != filename) { // // ... then we can load it normally: // load_compiled_file__may_heapclean( task, filename, &roots1 ); } else { // We're processing the // // RUNTIME_PACKAGE_PICKLEHASH=... // // set up for us by // // src/app/makelib/mythryl-compiler-compiler/find-set-of-compiledfiles-for-executable.pkg while (*filename++ != '='); // Step over "RUNTIME_PACKAGE_PICKLEHASH=" prefix. if (seen_runtime_package_picklehash) { // if (log_fd) fclose( log_fd ); die ("Runtime system picklehash registered more than once!\n"); exit(1); // Just for gcc's sake -- cannot exectute. } // Most parts of the Mythryl implementation treat the C-coded // runtime functions as being just like library functions // coded in Mythryl -- to avoid special cases, we go to great // lengths to hide the differences. // // But this is one of the places where the charade breaks // down -- there isn't actually any (useful) .compiled file // corresponding to the runtime picklehash: Instead, we // must link runtime calls directly down into our C code. // // For more info, see the comments in // src/lib/core/init/runtime.pkg // // So here we implement some of that special handling: // Register the runtime system under the given picklehash: // Picklehash picklehash; int l = strlen( filename ); for (int i = 0; i < PICKLEHASH_BYTES; i++) { // int i2 = 2 * i; if (i2 + 1 < l) { int c1 = filename[i2+0]; int c2 = filename[i2+1]; picklehash.bytes[i] = (hex(c1) << 4) + hex(c2); } } fprintf( log_fd ? log_fd : stderr, "\n load-compiledfiles.c: Runtime system picklehash is %s\n\n", filename ); register_compiled_file_exports__may_heapclean( task, &picklehash, runtime_package__global, &roots1 ); seen_runtime_package_picklehash = TRUE; // Make sure that we register the runtime system picklehash only once. } } if (log_fd) fclose( log_fd ); } // load_compiled_files__may_heapclean
Val make_package_literals_via_bytecode_interpreter (Task* task, Unt8* bytecode_vector, int bytecode_vector_length_in_bytes) { //============== // // NOTE: We allocate all of the chunks in agegroup 1, // but allocate the vector of literals in agegroup0. // // This fn gets exported to the Mythryl level as // // make_package_literals_via_bytecode_interpreter // in // src/lib/compiler/execution/code-segments/code-segment.pkg // via // src/c/lib/heap/make-package-literals-via-bytecode-interpreter.c // // Our ultimate invocation is in // // src/lib/compiler/execution/main/execute.pkg int pc = 0; // Check that sufficient space is available for the // literal chunk that we are about to allocate. // Note that the cons cell has already been accounted // for in space_available (but not in space_needed). // #define GC_CHECK \ do { \ if (space_needed > space_available \ && need_to_call_heapcleaner( task, space_needed + LIST_CONS_CELL_BYTESIZE) \ ){ \ call_heapcleaner_with_extra_roots (task, 0, (Val *)&bytecode_vector, &stk, NULL); \ space_available = 0; \ \ } else { \ \ space_available -= space_needed; \ } \ } while (0) #ifdef DEBUG_LITERALS debug_say("make_package_literals_via_bytecode_interpreter: bytecode_vector = %#x, bytecode_vector_length_in_bytes = %d\n", bytecode_vector, bytecode_vector_length_in_bytes); #endif if (bytecode_vector_length_in_bytes <= 8) return HEAP_NIL; Val_Sized_Unt magic = GET32(bytecode_vector); pc += 4; Val_Sized_Unt max_depth /* This variable is currently unused, so suppress 'unused var' compiler warning: */ __attribute__((unused)) = GET32(bytecode_vector); pc += 4; if (magic != V1_MAGIC) { die("bogus literal magic number %#x", magic); } Val stk = HEAP_NIL; int space_available = 0; for (;;) { // ASSERT(pc < bytecode_vector_length_in_bytes); space_available -= LIST_CONS_CELL_BYTESIZE; // Space for stack cons cell. if (space_available < ONE_K_BINARY) { // if (need_to_call_heapcleaner(task, 64*ONE_K_BINARY)) { // call_heapcleaner_with_extra_roots (task, 0, (Val *)&bytecode_vector, &stk, NULL); } space_available = 64*ONE_K_BINARY; } switch (bytecode_vector[ pc++ ]) { // case I_INT: { int i = GET32(bytecode_vector); pc += 4; #ifdef DEBUG_LITERALS debug_say("[%2d]: INT(%d)\n", pc-5, i); #endif LIST_CONS(task, stk, TAGGED_INT_FROM_C_INT(i), stk); } break; case I_RAW32: { int i = GET32(bytecode_vector); pc += 4; #ifdef DEBUG_LITERALS debug_say("[%2d]: RAW32[%d]\n", pc-5, i); #endif Val result; INT1_ALLOC(task, result, i); LIST_CONS(task, stk, result, stk); space_available -= 2*WORD_BYTESIZE; } break; case I_RAW32L: { int n = GET32(bytecode_vector); pc += 4; #ifdef DEBUG_LITERALS debug_say("[%2d]: RAW32L(%d) [...]\n", pc-5, n); #endif ASSERT(n > 0); int space_needed = 4*(n+1); GC_CHECK; LIB7_AllocWrite (task, 0, MAKE_TAGWORD(n, FOUR_BYTE_ALIGNED_NONPOINTER_DATA_BTAG)); for (int j = 1; j <= n; j++) { // int i = GET32(bytecode_vector); pc += 4; LIB7_AllocWrite (task, j, (Val)i); } Val result = LIB7_Alloc(task, n ); LIST_CONS(task, stk, result, stk); } break; case I_RAW64: { double d = get_double(&(bytecode_vector[pc])); pc += 8; Val result; REAL64_ALLOC(task, result, d); #ifdef DEBUG_LITERALS debug_say("[%2d]: RAW64[%f] @ %#x\n", pc-5, d, result); #endif LIST_CONS(task, stk, result, stk); space_available -= 4*WORD_BYTESIZE; // Extra 4 bytes for alignment padding. } break; case I_RAW64L: { int n = GET32(bytecode_vector); pc += 4; #ifdef DEBUG_LITERALS debug_say("[%2d]: RAW64L(%d) [...]\n", pc-5, n); #endif ASSERT(n > 0); int space_needed = 8*(n+1); GC_CHECK; #ifdef ALIGN_FLOAT64S // Force FLOAT64_BYTESIZE alignment (descriptor is off by one word) // task->heap_allocation_pointer = (Val*)((Punt)(task->heap_allocation_pointer) | WORD_BYTESIZE); #endif int j = 2*n; // Number of words. LIB7_AllocWrite (task, 0, MAKE_TAGWORD(j, EIGHT_BYTE_ALIGNED_NONPOINTER_DATA_BTAG)); Val result = LIB7_Alloc(task, j ); for (int j = 0; j < n; j++) { // PTR_CAST(double*, result)[j] = get_double(&(bytecode_vector[pc])); pc += 8; } LIST_CONS(task, stk, result, stk); } break; case I_STR: { int n = GET32(bytecode_vector); pc += 4; #ifdef DEBUG_LITERALS debug_say("[%2d]: STR(%d) [...]", pc-5, n); #endif if (n == 0) { #ifdef DEBUG_LITERALS debug_say("\n"); #endif LIST_CONS(task, stk, ZERO_LENGTH_STRING__GLOBAL, stk); break; } int j = BYTES_TO_WORDS(n+1); // '+1' to include space for '\0'. // The space request includes space for the data-chunk header word and // the sequence header chunk. // int space_needed = WORD_BYTESIZE*(j+1+3); GC_CHECK; // Allocate the data chunk: // LIB7_AllocWrite(task, 0, MAKE_TAGWORD(j, FOUR_BYTE_ALIGNED_NONPOINTER_DATA_BTAG)); LIB7_AllocWrite (task, j, 0); // So word-by-word string equality works. Val result = LIB7_Alloc (task, j); #ifdef DEBUG_LITERALS debug_say(" @ %#x (%d words)\n", result, j); #endif memcpy (PTR_CAST(void*, result), &bytecode_vector[pc], n); pc += n; // Allocate the header chunk: // SEQHDR_ALLOC(task, result, STRING_TAGWORD, result, n); // Push on stack: // LIST_CONS(task, stk, result, stk); } break; case I_LIT: { int n = GET32(bytecode_vector); pc += 4; Val result = stk; for (int j = 0; j < n; j++) { // result = LIST_TAIL(result); } #ifdef DEBUG_LITERALS debug_say("[%2d]: LIT(%d) = %#x\n", pc-5, n, LIST_HEAD(result)); #endif LIST_CONS(task, stk, LIST_HEAD(result), stk); } break; case I_VECTOR: { int n = GET32(bytecode_vector); pc += 4; #ifdef DEBUG_LITERALS debug_say("[%2d]: VECTOR(%d) [", pc-5, n); #endif if (n == 0) { #ifdef DEBUG_LITERALS debug_say("]\n"); #endif LIST_CONS(task, stk, ZERO_LENGTH_VECTOR__GLOBAL, stk); break; } // The space request includes space // for the data-chunk header word and // the sequence header chunk. // int space_needed = WORD_BYTESIZE*(n+1+3); GC_CHECK; // Allocate the data chunk: // LIB7_AllocWrite(task, 0, MAKE_TAGWORD(n, RO_VECTOR_DATA_BTAG)); // Top of stack is last element in vector: // for (int j = n; j > 0; j--) { // LIB7_AllocWrite(task, j, LIST_HEAD(stk)); stk = LIST_TAIL(stk); } Val result = LIB7_Alloc(task, n ); // Allocate the header chunk: // SEQHDR_ALLOC(task, result, TYPEAGNOSTIC_RO_VECTOR_TAGWORD, result, n); #ifdef DEBUG_LITERALS debug_say("...] @ %#x\n", result); #endif LIST_CONS(task, stk, result, stk); } break; case I_RECORD: { int n = GET32(bytecode_vector); pc += 4; #ifdef DEBUG_LITERALS debug_say("[%2d]: RECORD(%d) [", pc-5, n); #endif if (n == 0) { #ifdef DEBUG_LITERALS debug_say("]\n"); #endif LIST_CONS(task, stk, HEAP_VOID, stk); break; } else { int space_needed = 4*(n+1); GC_CHECK; LIB7_AllocWrite(task, 0, MAKE_TAGWORD(n, PAIRS_AND_RECORDS_BTAG)); } // Top of stack is last element in record: // for (int j = n; j > 0; j--) { // LIB7_AllocWrite(task, j, LIST_HEAD(stk)); stk = LIST_TAIL(stk); } Val result = LIB7_Alloc(task, n ); #ifdef DEBUG_LITERALS debug_say("...] @ %#x\n", result); #endif LIST_CONS(task, stk, result, stk); } break; case I_RETURN: ASSERT(pc == bytecode_vector_length_in_bytes); #ifdef DEBUG_LITERALS debug_say("[%2d]: RETURN(%#x)\n", pc-5, LIST_HEAD(stk)); #endif return LIST_HEAD( stk ); break; default: die ("bogus literal opcode #%x @ %d", bytecode_vector[pc-1], pc-1); } // switch } // while } // fun make_package_literals_via_bytecode_interpreter