Val _lib7_Sock_inetany (Task* task, Val arg) { //================== // // Mythryl type: Int -> Internet_Address // // Make an INET_ANY INET socket address, with the given port ID. // // This fn gets bound as inet_any in: // // src/lib/std/src/socket/internet-socket.pkg // ENTER_MYTHRYL_CALLABLE_C_FN("_lib7_Sock_inetany"); struct sockaddr_in addr; memset( &addr, 0, sizeof(struct sockaddr_in) ); addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl( INADDR_ANY ); addr.sin_port = htons( TAGGED_INT_TO_C_INT( arg ) ); // Last use of 'arg'. Val data = make_biwordslots_vector_sized_in_bytes__may_heapclean( task, &addr, sizeof(struct sockaddr_in), NULL ); return make_vector_header(task, UNT8_RO_VECTOR_TAGWORD, data, sizeof(struct sockaddr_in) ); }
Val _lib7_P_IO_read (Task* task, Val arg) { //=============== // // Mythryl type: (Int, Int) -> vector_of_one_byte_unts::Vector // fd nbytes // // Read the specified number of bytes from the specified file, // returning them in a vector. // // This fn gets bound as read' in: // // src/lib/std/src/psx/posix-io.pkg // src/lib/std/src/psx/posix-io-64.pkg ENTER_MYTHRYL_CALLABLE_C_FN(__func__); Val vec; int n; int fd = GET_TUPLE_SLOT_AS_INT( arg, 0 ); int nbytes = GET_TUPLE_SLOT_AS_INT( arg, 1 ); if (nbytes == 0) return ZERO_LENGTH_STRING__GLOBAL; // 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 C space in which to do the read: // Mythryl_Heap_Value_Buffer vec_buf; // { char* c_vec = buffer_mythryl_heap_nonvalue( &vec_buf, nbytes ); // buffer_mythryl_heap_nonvalue is from src/c/main/runtime-state.c do { RELEASE_MYTHRYL_HEAP( task->hostthread, __func__, NULL ); // n = read (fd, c_vec, nbytes); // RECOVER_MYTHRYL_HEAP( task->hostthread, __func__ ); // } while (n < 0 && errno == EINTR); // Restart if interrupted by a SIGALRM or SIGCHLD or whatever. if (n < 0) { unbuffer_mythryl_heap_value( &vec_buf ); return RAISE_SYSERR__MAY_HEAPCLEAN(task, n, NULL); } if (n == 0) { unbuffer_mythryl_heap_value( &vec_buf ); return ZERO_LENGTH_STRING__GLOBAL; } // Allocate the vector. // Note that this might trigger a heapcleaning, moving things around: // vec = allocate_nonempty_wordslots_vector__may_heapclean( task, BYTES_TO_WORDS(n), NULL ); memcpy( PTR_CAST(char*, vec), c_vec, n ); unbuffer_mythryl_heap_value( &vec_buf ); } Val result = make_vector_header(task, STRING_TAGWORD, vec, n); EXIT_MYTHRYL_CALLABLE_C_FN(__func__); return result; }
Val _lib7_Sock_getpeername (Task* task, Val arg) { //====================== // // Mythryl type: Socket -> (Address_Family, Address) // // This function gets bound as get_peer_name' in: // // src/lib/std/src/socket/socket-guts.pkg ENTER_MYTHRYL_CALLABLE_C_FN(__func__); char addr[ MAX_SOCK_ADDR_BYTESIZE ]; socklen_t address_len = MAX_SOCK_ADDR_BYTESIZE; int sockfd = TAGGED_INT_TO_C_INT( arg ); // Last use of 'arg'. RELEASE_MYTHRYL_HEAP( task->hostthread, __func__, NULL ); // int status = getpeername (sockfd, (struct sockaddr *)addr, &address_len); // RECOVER_MYTHRYL_HEAP( task->hostthread, __func__ ); if (status < 0) return RAISE_SYSERR__MAY_HEAPCLEAN(task, status, NULL); Val cdata = make_biwordslots_vector_sized_in_bytes__may_heapclean( task, addr, address_len, NULL ); Val result = make_vector_header(task, UNT8_RO_VECTOR_TAGWORD, cdata, address_len); EXIT_MYTHRYL_CALLABLE_C_FN(__func__); return result; }
static Val pickle_unboxed_value (Task* task, Val root_chunk) { // ==================== // Pickle_Header pickle_header; // Val pickle; Writer* wr; // int bytesize = sizeof( Heapfile_Header ) + sizeof( Pickle_Header ); // Allocate space for the chunk: // pickle = allocate_heap_ram_for_pickle( task, bytesize ); // wr = WR_OpenMem( PTR_CAST( Unt8*, pickle ), bytesize ); heapio__write_image_header( wr, UNBOXED_PICKLE ); // heapio__write_image_header def in src/c/heapcleaner/export-heap-stuff.c pickle_header.smallchunk_sibs_count = 0; pickle_header.hugechunk_sibs_count = 0; pickle_header.hugechunk_quire_count = 0; // pickle_header.contains_code = FALSE; pickle_header.root_chunk = root_chunk; WR_WRITE( wr, &pickle_header, sizeof( pickle_header ) ); if (WR_ERROR(wr)) return HEAP_VOID; WR_FREE(wr); return make_vector_header( task, STRING_TAGWORD, pickle, bytesize ); }
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 _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; }
Val _lib7_Sock_recv (Task* task, Val arg) { //=============== // // Mythryl type: (Socket, Int, Bool, Bool) -> vector_of_one_byte_unts::Vector // // The arguments are: socket, number of bytes, OOB flag and peek flag. // The result is the vector of bytes received. // // This fn gets bound as recv_v' in: // // src/lib/std/src/socket/socket-guts.pkg ENTER_MYTHRYL_CALLABLE_C_FN(__func__); Val vec; ssize_t n; int socket = GET_TUPLE_SLOT_AS_INT( arg, 0 ); int nbytes = GET_TUPLE_SLOT_AS_INT( arg, 1 ); Val oob = GET_TUPLE_SLOT_AS_VAL( arg, 2 ); Val peek = GET_TUPLE_SLOT_AS_VAL( arg, 3 ); int flag = 0; if (oob == HEAP_TRUE) flag |= MSG_OOB; if (peek == 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-world buffer // to read the bytes into: // Mythryl_Heap_Value_Buffer read_buf; // { unsigned char* c_read = buffer_mythryl_heap_nonvalue( &read_buf, nbytes ); // log_if("recv.c/before: socket d=%d nbytes d=%d oob=%s peek=%s\n",socket,nbytes,(oob == HEAP_TRUE)?"TRUE":"FALSE",(peek == HEAP_TRUE)?"TRUE":"FALSE"); errno = 0; RELEASE_MYTHRYL_HEAP( task->hostthread, __func__, NULL ); // do { // Backed out 2010-02-26 CrT: See discussion at bottom of src/c/lib/socket/connect.c // // Restored 2012-08-07 CrT n = recv (socket, c_read, nbytes, flag); // } 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( &read_buf ); if (n < 0) return RAISE_SYSERR__MAY_HEAPCLEAN(task, status, NULL); if (n == 0) return ZERO_LENGTH_STRING__GLOBAL; } // Allocate result vector to hold the bytes read. // NB: This might cause a heapcleaning, moving things around: // vec = allocate_nonempty_wordslots_vector__may_heapclean( task, BYTES_TO_WORDS(n), NULL ); // Copy bytes read into result vector: // memcpy( PTR_CAST(char*, vec), c_read, n); // log_if( "recv.c/after: n d=%d errno d=%d (%s)\n", n, errno, errno ? strerror(errno) : ""); // hexdump_if( "recv.c/after: Received data: ", PTR_CAST(unsigned char*, vec), n ); unbuffer_mythryl_heap_value( &read_buf ); } Val result = make_vector_header( task, STRING_TAGWORD, vec, n ); EXIT_MYTHRYL_CALLABLE_C_FN(__func__); return result; }
static Val pickle_heap_datastructure (Task *task, Val root_chunk, Pickler_Result* result) { // ========================= // Heap* heap = task->heap; int max_age = result->oldest_agegroup_included_in_pickle; Vunt total_sib_buffer_bytesize[ MAX_PLAIN_SIBS ]; Vunt total_bytesize; struct { Vunt base; // Base address of the sib buffer in the heap. Vunt offset; // Relative position in the merged sib buffer. // } adjust[ MAX_AGEGROUPS ][ MAX_PLAIN_SIBS ]; Sib_Header* p; // Sib_Header def in src/c/heapcleaner/runtime-heap-image.h Sib_Header* sib_headers[ TOTAL_SIBS ]; Sib_Header* sib_header_buffer; int sib_header_bytesize; int smallchunk_sibs_count; Val pickle; Writer* wr; // Compute the sib offsets in the heap image: // for (int ilk = 0; ilk < MAX_PLAIN_SIBS; ilk++) { // total_sib_buffer_bytesize[ ilk ] = 0; } // The embedded literals go first: // total_sib_buffer_bytesize[ NONPTR_DATA_SIB ] // pickler__relocate_embedded_literals def in src/c/heapcleaner/datastructure-pickler-cleaner.c = pickler__relocate_embedded_literals( result, NONPTR_DATA_SIB, 0 ); // DEBUG debug_say("%d bytes of string literals\n", total_sib_buffer_bytesize[NONPTR_DATA_SIB]); for (int age = 0; age < max_age; age++) { for (int ilk = 0; ilk < MAX_PLAIN_SIBS; ilk++) { // Sib* sib = heap->agegroup[ age ]->sib[ ilk ]; adjust[ age ][ ilk ].offset = total_sib_buffer_bytesize[ ilk ]; if (!sib_is_active(sib)) { // sib_is_active def in src/c/h/heap.h // adjust[ age ][ ilk ].base = 0; // } else { // total_sib_buffer_bytesize[ ilk ] += (Vunt) sib->tospace.first_free - (Vunt) sib->tospace.start; adjust[ age ][ ilk ].base = (Vunt) sib->tospace.start; } } } // DEBUG for (ilk = 0; ilk < MAX_PLAIN_SIBS; ilk++) debug_say ("sib %d: %d bytes\n", ilk+1, total_sib_buffer_bytesize[ilk]); // WHAT ABOUT THE BIG CHUNKS??? XXX BUGGO FIXME // Compute the total size of the pickled datastructure: // smallchunk_sibs_count = 0; total_bytesize = 0; // for (int ilk = 0; ilk < MAX_PLAIN_SIBS; ilk++) { // if (total_sib_buffer_bytesize[ilk] > 0) { smallchunk_sibs_count++; total_bytesize += total_sib_buffer_bytesize[ilk]; } } total_bytesize += sizeof( Heapfile_Header ) + sizeof( Pickle_Header ) + (smallchunk_sibs_count * sizeof( Sib_Header )); // COUNT SPACE FOR BIG CHUNKS total_bytesize += sizeof(Externs_Header) + heapfile_cfun_table_bytesize( result->cfun_table ); // Include the space for the external symbols (i.e., runtime C functions referenced within the heapgraph). // Allocate the heap bytevector for the pickled // datastructure representation and initialize // the bytevector-writer. // pickle = allocate_heap_ram_for_pickle( task, total_bytesize ); // wr = WR_OpenMem( PTR_CAST(Unt8*, pickle), total_bytesize ); // WR_OpenMem def in src/c/heapcleaner/mem-writer.c // Initialize the sib headers: // sib_header_bytesize = smallchunk_sibs_count * sizeof(Sib_Header); // sib_header_buffer = (Sib_Header*) MALLOC (sib_header_bytesize); // p = sib_header_buffer; // for (int ilk = 0; ilk < MAX_PLAIN_SIBS; ilk++) { // if (total_sib_buffer_bytesize[ ilk ] <= 0) { // sib_headers[ilk] = NULL; // } else { // p->age = 0; p->chunk_ilk = ilk; // p->info.o.base_address = 0; // Not used. p->info.o.bytesize = total_sib_buffer_bytesize[ ilk ]; p->info.o.rounded_bytesize = -1; // Not used. // p->offset = -1; // Not used. sib_headers[ ilk ] = p; p++; } } // What about big chunks? XXX BUGGO FIXME // Write the pickle image header: // if (heapio__write_image_header (wr, NORMAL_DATASTRUCTURE_PICKLE) == FALSE) { // heapio__write_image_header def in src/c/heapcleaner/export-heap-stuff.c // FREE( sib_header_buffer ); return PICKLER_ERROR; } // Write the pickle header: // { Pickle_Header header; header.smallchunk_sibs_count = smallchunk_sibs_count; header.hugechunk_sibs_count = 0; // FIX THIS XXX BUGGO FIXME header.hugechunk_quire_count = 0; // FIX THIS XXX BUGGO FIXME if (!IS_EXTERNAL_TAG( root_chunk )) { Sibid sibid = SIBID_FOR_POINTER( book_to_sibid__global, root_chunk ); if (!SIBID_KIND_IS_CODE(sibid)) { // This is the normal case -- // we're saving a vanilla heap value. Vunt addr = HEAP_POINTER_AS_UNT( root_chunk ); int age = GET_AGE_FROM_SIBID( sibid) - 1; int kind = GET_KIND_FROM_SIBID(sibid) - 1; // GET_KIND_FROM_SIBID def in src/c/h/sibid.h addr -= adjust[ age ][ kind ].base; addr += adjust[ age ][ kind ].offset; header.root_chunk = HIO_TAG_PTR(kind, addr); // HIO_TAG_PTR def in src/c/heapcleaner/runtime-heap-image.h } else { // Embedded_Chunk_Info* p = FIND_EMBEDDED_CHUNK( result->embedded_chunk_table, root_chunk ); if ((p == NULL) || (p->kind == USED_CODE)) { // say_error( "Pickling compiled Mythryl code not implemented\n" ); FREE (sib_header_buffer); return PICKLER_ERROR; } else { header.root_chunk = p->relocated_address; } } } else { // IS_EXTERNAL_TAG( root_chunk ) // ASSERT( smallchunk_sibs_count == 0 ); header.root_chunk = root_chunk; } WR_WRITE(wr, &header, sizeof(header)); // WR_WRITE def in src/c/heapcleaner/writer.h // if (WR_ERROR(wr)) { FREE (sib_header_buffer); return PICKLER_ERROR; } } // Record in the pickle the table of heap-referenced // runtime C functions. May also include // a handful of assembly fns, exceptions // and refcells: // { int bytes_written = heapio__write_cfun_table( wr, result->cfun_table ); // heapio__write_cfun_table def in src/c/heapcleaner/export-heap-stuff.c if (bytes_written == -1) { FREE( sib_header_buffer ); return PICKLER_ERROR; } } // Write the pickle sib headers: // WR_WRITE (wr, sib_header_buffer, sib_header_bytesize); // if (WR_ERROR(wr)) { FREE (sib_header_buffer); return PICKLER_ERROR; } // Write the pickled datastructure proper: // for (int ilk = 0; ilk < MAX_PLAIN_SIBS; ilk++) { // if (ilk == NONPTR_DATA_SIB) { // Write into the pickle the required embedded literals: // pickler__pickle_embedded_literals( wr ); // pickler__pickle_embedded_literals def in src/c/heapcleaner/datastructure-pickler-cleaner.c // Write into the pickle remaining required strings: // for (int age = 0; age < max_age; age++) { // Sib* sib = heap->agegroup[ age ]->sib[ ilk ]; if (sib_is_active(sib)) { // sib_is_active def in src/c/h/heap.h // WR_WRITE( wr, sib->tospace.start, (Vunt) sib->tospace.first_free -(Vunt) sib->tospace.start ); } } } else { for (int age = 0; age < max_age; age++) { // Sib* sib = heap->agegroup[ age ]->sib[ ilk ]; if (sib_is_active( sib )) { // Val* top = sib->tospace.first_free; // for (Val* p = sib->tospace.start; p < top; p++ ){ Val w = *p; if (IS_POINTER(w)) { // Sibid sibid = SIBID_FOR_POINTER( book_to_sibid__global, w ); if (BOOK_IS_UNMAPPED(sibid)) { // w = add_cfun_to_heapfile_cfun_table( result->cfun_table, w); ASSERT (w != HEAP_VOID); } else if (SIBID_KIND_IS_CODE(sibid)) { Embedded_Chunk_Info* chunk_info = FIND_EMBEDDED_CHUNK( result->embedded_chunk_table, w ); if (chunk_info == NULL || chunk_info->kind == USED_CODE ){ die("Pickling of Mythryl compiled code not implemented"); } else { w = chunk_info->relocated_address; } } else { // Adjust the pointer: // int age = GET_AGE_FROM_SIBID( sibid)-1; int kind = GET_KIND_FROM_SIBID(sibid)-1; Vunt addr = HEAP_POINTER_AS_UNT(w); addr -= adjust[ age ][ kind ].base; addr += adjust[ age ][ kind ].offset; w = HIO_TAG_PTR( kind, addr ); } } // if (IS_POINTER(w)) WR_PUT(wr, (Vunt)w); } // for } } } } FREE( sib_header_buffer ); if (WR_ERROR(wr)) return PICKLER_ERROR; return make_vector_header(task, STRING_TAGWORD, pickle, total_bytesize); } // fun pickle_heap_datastructure