Val _lib7_Time_timeofday (Task* task, Val arg) { //==================== // // Mythryl type: Void -> (one_word_int::Int, Int) // // Return the time of day. // NOTE: gettimeofday() is not POSIX (time() returns seconds, and is POSIX and ISO C). // // This fn gets bound as get_time_of_day in: // // src/lib/std/src/time-guts.pkg ENTER_MYTHRYL_CALLABLE_C_FN(__func__); int c_microseconds; Val lib7_seconds; RELEASE_MYTHRYL_HEAP( task->hostthread, __func__, NULL ); // int c_seconds = _lib7_time_gettimeofday( &c_microseconds ); // RECOVER_MYTHRYL_HEAP( task->hostthread, __func__ ); lib7_seconds = make_one_word_int(task, c_seconds ); Val result = make_two_slot_record(task, lib7_seconds, TAGGED_INT_FROM_C_INT( c_microseconds ) ); EXIT_MYTHRYL_CALLABLE_C_FN(__func__); return result; }
Val _lib7_P_IO_pipe (Task* task, Val arg) { //=============== // // Mythryl type: Void -> (Int, Int) // // Create a pipe and return its input and output descriptors. // // This fn gets bound as pipe' in: // // src/lib/std/src/psx/posix-io.pkg // src/lib/std/src/psx/posix-io-64.pkg ENTER_MYTHRYL_CALLABLE_C_FN(__func__); int status; int fds[2]; RELEASE_MYTHRYL_HEAP( task->hostthread, __func__, NULL ); // status = pipe(fds); // RECOVER_MYTHRYL_HEAP( task->hostthread, __func__ ); // printf("Created pipe %d -> %d -- pipe.c thread id %lx\n", fds[0], fds[1], pth__get_hostthread_id); fflush(stdout); Val result; if (status == -1) result = RAISE_SYSERR__MAY_HEAPCLEAN(task, -1, NULL); else result = make_two_slot_record( task, TAGGED_INT_FROM_C_INT(fds[0]), TAGGED_INT_FROM_C_INT(fds[1]) ); EXIT_MYTHRYL_CALLABLE_C_FN(__func__); return result; }
Val _lib7_Sock_accept (Task* task, Val arg) { //================= // // Mythryl type: Socket -> (Socket, Address) // // This fn gets bound as accept' in: // // src/lib/std/src/socket/socket-guts.pkg ENTER_MYTHRYL_CALLABLE_C_FN("_lib7_Sock_accept"); int socket = TAGGED_INT_TO_C_INT( arg ); // Last use of 'arg'. char address_buf[ MAX_SOCK_ADDR_BYTESIZE ]; socklen_t address_len = MAX_SOCK_ADDR_BYTESIZE; int new_socket; RELEASE_MYTHRYL_HEAP( task->pthread, "_lib7_Sock_accept", NULL ); // /* do { */ /* Backed out 2010-02-26 CrT: See discussion at bottom of src/c/lib/socket/connect.c */ new_socket = accept (socket, (struct sockaddr*) address_buf, &address_len); /* } while (new_socket < 0 && errno == EINTR); */ /* Restart if interrupted by a SIGALRM or SIGCHLD or whatever. */ // RECOVER_MYTHRYL_HEAP( task->pthread, "_lib7_Sock_accept" ); if (new_socket == -1) { // return RAISE_SYSERR__MAY_HEAPCLEAN( task, new_socket, NULL); // } else { // Val data = make_biwordslots_vector_sized_in_bytes__may_heapclean( task, address_buf, address_len, NULL ); Val address = make_vector_header( task, UNT8_RO_VECTOR_TAGWORD, data, address_len); return make_two_slot_record(task, TAGGED_INT_FROM_C_INT( new_socket ), address); } }
Val _lib7_Sock_frominetaddr (Task* task, Val arg) { //======================= // // Mythryl type: Internet_Address -> (Internet_Address, Int) // // Given a INET-domain socket address, return the INET address and port number. // // This fn gets bound as from_inet_addr in: // // src/lib/std/src/socket/internet-socket.pkg ENTER_MYTHRYL_CALLABLE_C_FN("_lib7_Sock_frominetaddr"); struct sockaddr_in* addr = GET_VECTOR_DATACHUNK_AS( struct sockaddr_in*, arg ); // Last use of 'arg'. ASSERT( addr->sin_family == AF_INET ); Val data = make_biwordslots_vector_sized_in_bytes__may_heapclean( task, &(addr->sin_addr), sizeof(struct in_addr), NULL ); Val inAddr = make_vector_header( task, UNT8_RO_VECTOR_TAGWORD, data, sizeof(struct in_addr) ); return make_two_slot_record(task, inAddr, TAGGED_INT_FROM_C_INT(ntohs(addr->sin_port)) ); }
Val raise_error__may_heapclean ( //========================== // Task* task, const char* altMsg, const char* at, // C sourcefile and line number raising this error: "<foo.c:37>" Roots* extra_roots ) { // Raise the Mythryl exception RUNTIME_EXCEPTION, which is defined as: // // exception RUNTIME_EXCEPTION (String, Null_Or(System_Error) ); // // We normally get invoked via either the // RAISE_SYSERR__MAY_HEAPCLEAN or RAISE_ERROR__MAY_HEAPCLEAN macro from // // src/c/lib/raise-error.h // // For the time being, we use the errno value as the System_Error; eventually that // will be represented by an (Int, String) pair. If alt_msg is non-zero, // then use it as the error string and use NULL for the System_Error. int error_number = errno; // Various calls can trash this value so preserve it early. const char* msg; char buf[32]; Val null_or_errno; if (altMsg != NULL) { // msg = altMsg; null_or_errno = OPTION_NULL; } else if ((msg = strerror(error_number)) != NULL) { null_or_errno = OPTION_THE( task, TAGGED_INT_FROM_C_INT(error_number) ); } else { sprintf(buf, "<unknown error %d>", error_number); msg = buf; null_or_errno = OPTION_THE( task, TAGGED_INT_FROM_C_INT(error_number) ); } #if (defined(DEBUG_OS_INTERFACE) || defined(DEBUG_TRACE_CCALL)) debug_say ("RaiseSysError: errno = %d, msg = \"%s\"\n", (altMsg != NULL) ? -1 : error_number, msg); #endif Roots roots1 = { &null_or_errno, extra_roots }; Val errno_string = make_ascii_string_from_c_string__may_heapclean (task, msg, &roots1 ); Val at_list; // [] or [ "<foo.c:187>" ]. // if (at != NULL) { // Roots roots2 = { &errno_string, &roots1 }; Val at_cstring = make_ascii_string_from_c_string__may_heapclean (task, at, &roots2 ); at_list = LIST_CONS(task, at_cstring, LIST_NIL); } else { at_list = LIST_NIL; } Val arg = make_two_slot_record( task, errno_string, null_or_errno); Val syserr_exception = MAKE_EXCEPTION(task, PTR_CAST( Val, RUNTIME_EXCEPTION__GLOBAL), arg, at_list); // Modify the task state so that 'syserr_exception' // will be raised when Mythryl execution resumes: // raise_mythryl_exception( task, syserr_exception ); // raise_mythryl_exception is from src/c/main/run-mythryl-code-and-runtime-eventloop.c return syserr_exception; } // fun raise_error__may_heapclean
Val _lib7_Sock_recvbuffrom (Task* task, Val arg) { //====================== // // Mythryl type: (Socket, rw_vector_of_one_byte_unts::Rw_Vector, Int, Int, Bool, Bool) -> (Int, Addr) // // The arguments are: // socket, // data buffer, // start position, // number of bytes, // OOB flag // peek flag. // // The result is: // number of bytes read // source address. // // This fn gets bound as recv_from_a in: // // src/lib/std/src/socket/socket-guts.pkg ENTER_MYTHRYL_CALLABLE_C_FN(__func__); char address_buf[ MAX_SOCK_ADDR_BYTESIZE ]; socklen_t address_len = MAX_SOCK_ADDR_BYTESIZE; int socket = GET_TUPLE_SLOT_AS_INT( arg, 0); // Val buf = GET_TUPLE_SLOT_AS_VAL( arg, 1); // Mythryl buffer to read bytes into. // We'll fetch this after the call, since it may move around during the call. int offset = GET_TUPLE_SLOT_AS_INT( arg, 2); // Offset within buf to read bytes into. int nbytes = GET_TUPLE_SLOT_AS_INT( arg, 3); // Number of bytes to read. int flag = 0; int n; if (GET_TUPLE_SLOT_AS_VAL(arg, 4) == HEAP_TRUE) flag |= MSG_OOB; if (GET_TUPLE_SLOT_AS_VAL(arg, 5) == HEAP_TRUE) flag |= MSG_PEEK; // We cannot reference anything on the Mythryl heap // between RELEASE_MYTHRYL_HEAP and RECOVER_MYTHRYL_HEAP // because garbage collection might be moving // it around, so allocate a C-side read buffer: // Mythryl_Heap_Value_Buffer readbuf_buf; // { char* c_readbuf = buffer_mythryl_heap_nonvalue( &readbuf_buf, nbytes ); RELEASE_MYTHRYL_HEAP( task->hostthread, __func__, &arg ); // 'arg' is still live here! // do { // n = recvfrom( socket, c_readbuf, nbytes, flag, (struct sockaddr *)address_buf, &address_len ); } while (n < 0 && errno == EINTR); // Restart if interrupted by a SIGALRM or SIGCHLD or whatever. // RECOVER_MYTHRYL_HEAP( task->hostthread, __func__ ); if (n < 0) { unbuffer_mythryl_heap_value( &readbuf_buf ); return RAISE_SYSERR__MAY_HEAPCLEAN(task, status, NULL); } Val buf = GET_TUPLE_SLOT_AS_VAL( arg, 1); // Mythryl buffer to read bytes into. char* bufstart = HEAP_STRING_AS_C_STRING(buf) + offset; memcpy( bufstart, c_readbuf, n); unbuffer_mythryl_heap_value( &readbuf_buf ); } Val data = make_biwordslots_vector_sized_in_bytes__may_heapclean( task, address_buf, address_len, NULL ); Val address = make_vector_header( task, UNT8_RO_VECTOR_TAGWORD, data, address_len); Val result = make_two_slot_record(task, TAGGED_INT_FROM_C_INT(n), address); EXIT_MYTHRYL_CALLABLE_C_FN(__func__); return result; }
Task* import_heap_image__may_heapclean (const char* fname, Heapcleaner_Args* params, Roots* extra_roots) { // ================================ // // This fn is called (only) by load_and_run_heap_image__may_heapclean in src/c/main/load-and-run-heap-image.c // Task* task; Heapfile_Header image_header; Heap_Header heap_header; Val *externs; Pthread_Image image; Inbuf inbuf; if (fname != NULL) { // // Resolve the name of the image. // If the file exists use it, otherwise try the // pathname with the machine ID as an extension. if ((inbuf.file = fopen(fname, "rb"))) { // if (verbosity__global > 0) say("loading %s ", fname); } else { // if ((inbuf.file = fopen(fname, "rb"))) { // if (verbosity__global > 0) say("loading %s ", fname); } else { die ("unable to open heap image \"%s\"\n", fname); } } inbuf.needs_to_be_byteswapped = FALSE; inbuf.buf = NULL; inbuf.nbytes = 0; } else { // // fname == NULL, so try to find // an in-core heap image: #if defined(DLOPEN) && !defined(OPSYS_WIN32) // void *lib = dlopen (NULL, RTLD_LAZY); void *vimg, *vimglenptr; if ((vimg = dlsym(lib,HEAP_IMAGE_SYMBOL )) == NULL) die("no in-core heap image found\n"); if ((vimglenptr = dlsym(lib,HEAP_IMAGE_LEN_SYMBOL)) == NULL) die("unable to find length of in-core heap image\n"); inbuf.file = NULL; inbuf.needs_to_be_byteswapped = FALSE; inbuf.base = vimg; inbuf.buf = inbuf.base; inbuf.nbytes = *(long*)vimglenptr; #else die("in-core heap images not implemented\n"); #endif } READ(&inbuf, image_header); if (image_header.byte_order != ORDER) die ("incorrect byte order in heap image\n"); if (image_header.magic != IMAGE_MAGIC) die ("bad magic number (%#x) in heap image\n", image_header.magic); if ((image_header.kind != EXPORT_HEAP_IMAGE) && (image_header.kind != EXPORT_FN_IMAGE)) die ("bad image kind (%d) in heap image\n", image_header.kind); READ(&inbuf, heap_header); // Check for command-line overrides of heap parameters: // if (params->agegroup0_buffer_bytesize == 0) { params->agegroup0_buffer_bytesize = heap_header.agegroup0_buffer_bytesize; } if (params->active_agegroups < heap_header.active_agegroups) { params->active_agegroups = heap_header.active_agegroups; } if (params->oldest_agegroup_retaining_fromspace_sibs_between_heapcleanings < 0) { params->oldest_agegroup_retaining_fromspace_sibs_between_heapcleanings = heap_header.oldest_agegroup_retaining_fromspace_sibs_between_heapcleanings; } task = make_task( /*is_boot:*/FALSE, params ); // make_task def in src/c/main/runtime-state.c // Get the run-time pointers into the heap: // *PTR_CAST( Val*, PERVASIVE_PACKAGE_PICKLE_LIST_REFCELL__GLOBAL ) = heap_header.pervasive_package_pickle_list; // This carefully constructed fake looks like a normal // compiled package from the Mythryl side but actually // links to compile C code -- see the hack in // // src/c/main/load-compiledfiles.c // runtime_package__global = heap_header.runtime_pseudopackage; #ifdef ASM_MATH mathvec__global = heap_header.math_package; #endif externs = heapio__read_externs_table (&inbuf); // Read the externals table. READ(&inbuf, image); // Read and initialize the Mythryl state info. // if (image_header.kind == EXPORT_HEAP_IMAGE) { // Load the live registers: // ASSIGN( POSIX_INTERPROCESS_SIGNAL_HANDLER_REFCELL__GLOBAL, image.posix_interprocess_signal_handler ); // task->argument = image.stdArg; task->fate = image.stdCont; task->current_closure = image.stdClos; task->program_counter = image.pc; task->exception_fate = image.exception_fate; task->current_thread = image.current_thread; // task->callee_saved_registers[0] = image.calleeSave[0]; task->callee_saved_registers[1] = image.calleeSave[1]; task->callee_saved_registers[2] = image.calleeSave[2]; read_heap (&inbuf, &heap_header, task, externs); // Read the Mythryl heap. /* heapcleaner_messages_are_enabled__global = TRUE; */ // Heapcleaning messages are on by default for interactive images. } else { // EXPORT_FN_IMAGE // Restore the signal handler: // ASSIGN( POSIX_INTERPROCESS_SIGNAL_HANDLER_REFCELL__GLOBAL, image.posix_interprocess_signal_handler ); // Read the Mythryl heap: // task->argument = image.stdArg; read_heap (&inbuf, &heap_header, task, externs); // Initialize the calling context (taken from run_mythryl_function__may_heapclean): // run_mythryl_function__may_heapclean def in src/c/main/run-mythryl-code-and-runtime-eventloop.c // Val function_to_run = task->argument; // task->exception_fate = PTR_CAST( Val, handle_uncaught_exception_closure_v + 1 ); task->current_thread = HEAP_VOID; // task->fate = PTR_CAST( Val, return_to_c_level_c ); task->current_closure = function_to_run; // task->program_counter = task->link_register = GET_CODE_ADDRESS_FROM_CLOSURE( function_to_run ); // Last use of 'function_to_run'. // Set up the arguments to the imported function: // Val program_name = make_ascii_string_from_c_string__may_heapclean(task, mythryl_program_name__global, extra_roots); Roots roots1 = { &program_name, extra_roots }; // Val args = make_ascii_strings_from_vector_of_c_strings__may_heapclean (task, commandline_args_without_argv0_or_runtime_args__global, &roots1 ); task->argument = make_two_slot_record( task, program_name, args ); // debug_say("arg = %#x : [%#x, %#x]\n", task->argument, GET_TUPLE_SLOT_AS_VAL(task->argument, 0), GET_TUPLE_SLOT_AS_VAL(task->argument, 1)); // Heapcleaner messages are off by // default for spawn_to_disk images: // heapcleaner_messages_are_enabled__global = FALSE; } FREE( externs ); if (inbuf.file) fclose (inbuf.file); if (verbosity__global > 0) say(" done\n"); return task; } // fun import_heap_image__may_heapclean