Exemplo n.º 1
0
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) );
}
Exemplo n.º 2
0
Val   _lib7_Sock_getATMARK   (Task* task,  Val arg)   {
    //====================
    //
    // Mythryl type:   Socket_Fd -> Int
    //
    // This fn gets bound as   get_atmark'   in:
    //
    //     src/lib/std/src/socket/socket-guts.pkg
    //

											ENTER_MYTHRYL_CALLABLE_C_FN(__func__);

    int device = TAGGED_INT_TO_C_INT( arg );						// Last use of 'arg'.

    RELEASE_MYTHRYL_HEAP( task->hostthread, __func__, NULL );
	//
	int	                                         n;
	int status = ioctl (device, SIOCATMARK, (char*) &n );
	//
    RECOVER_MYTHRYL_HEAP( task->hostthread, __func__ );

    if (status < 0)     return RAISE_SYSERR__MAY_HEAPCLEAN(task, status, NULL);

									    EXIT_MYTHRYL_CALLABLE_C_FN(__func__);
    return    n ? HEAP_TRUE : HEAP_FALSE;
}
Exemplo n.º 3
0
Val   _lib7_netdb_get_protocol_by_number   (Task* task,  Val arg)   {
    //==================================
    //
    // Mythryl type:  Int -> Null_Or(  (String, List(String), Int)   )
    //
    // This fn gets bound as   get_prot_by_number'   in:
    //
    //     src/lib/std/src/socket/net-protocol-db.pkg

															ENTER_MYTHRYL_CALLABLE_C_FN(__func__);

    int number = TAGGED_INT_TO_C_INT( arg );										// Last use of 'arg'.

    RELEASE_MYTHRYL_HEAP( task->hostthread, __func__, NULL );
	//
	struct protoent*  pentry =   getprotobynumber( number );
	//
    RECOVER_MYTHRYL_HEAP( task->hostthread, __func__ );


    if (pentry == NULL)   return OPTION_NULL;


    Val name    =  make_ascii_string_from_c_string__may_heapclean	     (task, pentry->p_name,	NULL   );				Roots roots1 = { &name, NULL };

    Val aliases =  make_ascii_strings_from_vector_of_c_strings__may_heapclean(task, pentry->p_aliases, &roots1 );

    Val result	=  make_three_slot_record( task,   name,  aliases,  TAGGED_INT_FROM_C_INT(pentry->p_proto)  );

    result =  OPTION_THE( task, result );

									    EXIT_MYTHRYL_CALLABLE_C_FN(__func__);
    return result;
}
Exemplo n.º 4
0
Val   _lib7_P_IO_fsync   (Task* task,  Val arg)   {
    //================
    //
    // Mythryl type:   Sy_Int -> Void
    //
    // Synchronize  a  file's in-core state with storage
    //
    // This fn gets bound as   fsync'   in:
    //
    //     src/lib/std/src/posix-1003.1b/posix-io.pkg
    //     src/lib/std/src/posix-1003.1b/posix-io-64.pkg

									    ENTER_MYTHRYL_CALLABLE_C_FN("_lib7_P_IO_fsync");

    int status;
    int fd = TAGGED_INT_TO_C_INT(arg);

    RELEASE_MYTHRYL_HEAP( task->pthread, "_lib7_P_IO_fsync", NULL );
	//
	status = fsync(fd);
	//
    RECOVER_MYTHRYL_HEAP( task->pthread, "_lib7_P_IO_fsync" );

    RETURN_VOID_EXCEPT_RAISE_SYSERR_ON_NEGATIVE_STATUS__MAY_HEAPCLEAN(task, status, NULL);
}
Exemplo n.º 5
0
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;
}
Exemplo n.º 6
0
Val   _lib7_P_TTY_tcgetattr   (Task* task,  Val arg)   {
    //=====================
    //
    // Mythryl type:   Int -> (Unt, Unt, Unt, Unt, String, Unt, Unt)
    //
    // Get parameters associated with tty.
    //
    // NOTE: the calls to cfget[io] speed by making the code more OS-dependent
    // and using the package of struct termios.
    //
    // This fn gets bound as   tcgetattr   in:
    //
    //     src/lib/std/src/psx/posix-tty.pkg

									    ENTER_MYTHRYL_CALLABLE_C_FN(__func__);

    int fd = TAGGED_INT_TO_C_INT( arg );

    struct termios  data;

    RELEASE_MYTHRYL_HEAP( task->hostthread, __func__, NULL);
	//
	int status =  tcgetattr( fd, &data );
	//
    RECOVER_MYTHRYL_HEAP( task->hostthread, __func__ );

    if (status < 0)   return RAISE_SYSERR__MAY_HEAPCLEAN(task, status, NULL);

    Val iflag  =  make_one_word_unt(task, data.c_iflag  );			Roots roots1 = { &iflag,   NULL   };
    Val oflag  =  make_one_word_unt(task, data.c_oflag  );			Roots roots2 = { &oflag,  &roots1 };
    Val cflag  =  make_one_word_unt(task, data.c_cflag  );			Roots roots3 = { &cflag,  &roots2 };
    Val lflag  =  make_one_word_unt(task, data.c_lflag  );			Roots roots4 = { &lflag,  &roots3 };

    Val ispeed =  make_one_word_unt(task, cfgetispeed (&data) );		Roots roots5 = { &ispeed, &roots4 };
    Val ospeed =  make_one_word_unt(task, cfgetospeed (&data) );		Roots roots6 = { &ospeed, &roots5 };
    
    Val cc = allocate_nonempty_ascii_string__may_heapclean (task, NCCS, &roots6 );

    memcpy(
	GET_VECTOR_DATACHUNK_AS( void*, cc ),
        data.c_cc,
	NCCS
    );

    // Construct the result vector:
    //
    set_slot_in_nascent_heapchunk   (task, 0, MAKE_TAGWORD(PAIRS_AND_RECORDS_BTAG, 7));
    set_slot_in_nascent_heapchunk   (task, 1, iflag);
    set_slot_in_nascent_heapchunk   (task, 2, oflag);
    set_slot_in_nascent_heapchunk   (task, 3, cflag);
    set_slot_in_nascent_heapchunk   (task, 4, lflag);
    set_slot_in_nascent_heapchunk   (task, 5, cc);
    set_slot_in_nascent_heapchunk   (task, 6, ispeed);
    set_slot_in_nascent_heapchunk   (task, 7, ospeed);

    Val result = commit_nascent_heapchunk (task, 7);

									    EXIT_MYTHRYL_CALLABLE_C_FN(__func__);
    return result;
}
Exemplo n.º 7
0
Val   _lib7_P_ProcEnv_isatty   (Task* task,  Val arg)   {
    //======================
    //
    // Mythryl type:  Int -> Bool
    //
    // Is file descriptor associated with a terminal device?
    //
    // This fn gets bound as   isatty'   in:
    //
    //     src/lib/std/src/posix-1003.1b/posix-id.pkg

    return (isatty(TAGGED_INT_TO_C_INT(arg)) ? HEAP_TRUE : HEAP_FALSE);
}
Exemplo n.º 8
0
Val   _lib7_Sock_setprintiffd   (Task* task,  Val arg)   {
    //=======================
    //
    // Mythryl type:   Int -> Void
    //
    // This fn gets bound as   set_printif_fd   in:
    //
    //     src/lib/std/src/socket/internet-socket.pkg

									    ENTER_MYTHRYL_CALLABLE_C_FN("_lib7_Sock_setprintiffd");

    int fd    =  TAGGED_INT_TO_C_INT(arg);

    log_if_fd = fd;

    return HEAP_VOID;
}
Val   get_or_set_socket_nodelay_option   (Task* task,  Val arg)   {
    //================================
    //
    // Mythryl type:   (Int,  Null_Or(Bool)) -> Bool
    //
    // NOTE: this is a TCP level option, so we cannot use the utility function.
    //
    // This fn gets bound as   ctl_delay   in:
    //
    //     src/lib/std/src/socket/internet-socket.pkg

													ENTER_MYTHRYL_CALLABLE_C_FN("get_or_set_socket_nodelay_option");

    int	socket =  GET_TUPLE_SLOT_AS_INT( arg, 0 );
    Val	ctl    =  GET_TUPLE_SLOT_AS_VAL( arg, 1 );							// Last use of 'arg'.
    //
    Bool flag;
    int status;

    if (ctl == OPTION_NULL) {
        //
	socklen_t opt_size = sizeof(int);

	RELEASE_MYTHRYL_HEAP( task->pthread, "get_or_set_socket_nodelay_option", NULL );
	    //
	    status = getsockopt (socket, IPPROTO_TCP, TCP_NODELAY, (sockoptval_t)&flag, &opt_size);
	    //
	RECOVER_MYTHRYL_HEAP( task->pthread, "get_or_set_socket_nodelay_option" );

	ASSERT((status < 0) || (opt_size == sizeof(int)));

    } else {

	flag = (Bool) TAGGED_INT_TO_C_INT(OPTION_GET(ctl));

	RELEASE_MYTHRYL_HEAP( task->pthread, "get_or_set_socket_nodelay_option", NULL );
	    //
	    status = setsockopt (socket, IPPROTO_TCP, TCP_NODELAY, (sockoptval_t)&flag, sizeof(int));
	    //
	RECOVER_MYTHRYL_HEAP( task->pthread, "get_or_set_socket_nodelay_option" );
    }

    if (status < 0)     return RAISE_SYSERR__MAY_HEAPCLEAN(task, status, NULL);
    else		return (flag ? HEAP_TRUE : HEAP_FALSE);
}
Exemplo n.º 10
0
Val   _lib7_P_Error_errmsg   (Task* task, Val arg)   {
    //====================
    //
    // Mythryl type:   Int -> String
    //
    // Return the OS-dependent error message associated with error.
    //
    // This fn gets bound as   errmsg   in:
    //
    //     src/lib/std/src/psx/posix-error.pkg

									    ENTER_MYTHRYL_CALLABLE_C_FN(__func__);

    int errnum =  TAGGED_INT_TO_C_INT( arg );
    Val result;

    #if defined( HAS_STRERROR )
	//
	char* msg = strerror( errnum );
	//
	if (msg != 0) {
	    //
	    result = make_ascii_string_from_c_string__may_heapclean( task, msg, NULL );				// make_ascii_string_from_c_string__may_heapclean	def in    src/c/heapcleaner/make-strings-and-vectors-etc.c
	} else {
	    char     buf[64];
	    sprintf( buf, "<unknown error %d>", errnum);				// XXX SUCKO FIXME should use a modern fn proof against buffer overrun.
	    result = make_ascii_string_from_c_string__may_heapclean (task, buf, NULL );
	}
    #else
	if (0 <= errnum  &&  errnum < sys_nerr) {
	    //
	    result = make_ascii_string_from_c_string__may_heapclean (task, sys_errlist[errnum], NULL );
	    //
	} else {
	    //
	    char     buf[64];
	    snprintf( buf, 64, "<unknown error %d>", errnum);
	    result = make_ascii_string_from_c_string__may_heapclean (task, buf, NULL );
	}
    #endif
									    EXIT_MYTHRYL_CALLABLE_C_FN(__func__);

    return result;
}
Exemplo n.º 11
0
Val   _lib7_NetDB_getrpcbynum   (Task* task,  Val arg)   {
    //=======================
    //
    // Mythryl type:  Int ->   Null_Or(   (String, List(String), Int)   )
    //
    // This fn is NOWHERE INVOKED.  Nor listed in   src/c/lib/socket/cfun-list.h   Presumably should be either called or deleted:  XXX BUGGO FIXME.

    struct rpcent*  rentry
	=
        getrpcbynumber( TAGGED_INT_TO_C_INT( arg ));

    if (rentry == NULL)   return OPTION_NULL;

    Val name    =  make_ascii_string_from_c_string(     task, rentry->r_name   );
    Val aliases =  make_ascii_strings_from_vector_of_c_strings( task, rentry->r_aliases);

    Val                result;
    REC_ALLOC3(  task, result, name, aliases, TAGGED_INT_FROM_C_INT(rentry->r_number));
    OPTION_THE( task, result, result);
    return             result;
}
Exemplo n.º 12
0
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);
    }
}
Exemplo n.º 13
0
Val   _lib7_P_IO_dup   (Task* task,  Val arg)   {
    //==============
    //
    // Mythryl type:   Int -> Int
    //
    // Duplicate an open file descriptor
    //
    // This fn gets bound as   dup'   in:
    //
    //     src/lib/std/src/posix-1003.1b/posix-io.pkg
    //     src/lib/std/src/posix-1003.1b/posix-io-64.pkg

    int             fd0 = TAGGED_INT_TO_C_INT(arg);
    int             fd1;

/*  do { */						// Backed out 2010-02-26 CrT: See discussion at bottom of src/c/lib/socket/connect.c

        fd1 = dup(fd0);

/*  } while (fd1 < 0 && errno == EINTR);	*/	// Restart if interrupted by a SIGALRM or SIGCHLD or whatever.

    CHECK_RETURN(task, fd1)
}
Exemplo n.º 14
0
Val   _lib7_P_TTY_tcdrain   (Task* task,  Val arg)   {
    //===================
    //
    // Mythryl type:   Int -> Void
    //
    // Wait for all output to be transmitted.
    //
    // This fn gets bound as   tcdrain   in:
    //
    //     src/lib/std/src/posix-1003.1b/posix-tty.pkg

									    ENTER_MYTHRYL_CALLABLE_C_FN("_lib7_P_TTY_tcdrain");

    int fd     =  TAGGED_INT_TO_C_INT( arg );

    RELEASE_MYTHRYL_HEAP( task->pthread, "_lib7_P_TTY_tcdrain", NULL );
	//
	int status =  tcdrain( fd );
	//
    RECOVER_MYTHRYL_HEAP( task->pthread, "_lib7_P_TTY_tcdrain" );

    RETURN_VOID_EXCEPT_RAISE_SYSERR_ON_NEGATIVE_STATUS__MAY_HEAPCLEAN(task, status, NULL);
}
Exemplo n.º 15
0
Val   _lib7_P_TTY_tcgetpgrp   (Task* task,  Val arg)   {
    //=====================
    //
    // Mythryl type:   Int -> Int
    //
    // Get foreground process group id of tty.
    //
    // This fn gets bound as   tcgetpgrp   in:
    //
    //     src/lib/std/src/posix-1003.1b/posix-tty.pkg

    ENTER_MYTHRYL_CALLABLE_C_FN("_lib7_P_TTY_tcgetpgrp");

    int fd = TAGGED_INT_TO_C_INT( arg );

    RELEASE_MYTHRYL_HEAP( task->pthread, "_lib7_P_TTY_tcgetpgrp", NULL );
    //
    int result = tcgetpgrp( fd );
    //
    RECOVER_MYTHRYL_HEAP( task->pthread, "_lib7_P_TTY_tcgetpgrp" );

    return TAGGED_INT_FROM_C_INT( result );
}
Exemplo n.º 16
0
Val   _lib7_Sock_getNREAD   (Task* task,  Val arg)   {
    //===================
    //
    // Mythryl type:   Socket -> Int
    //
    // This fn gets bound as   get_nread'   in:
    //
    //     src/lib/std/src/socket/socket-guts.pkg

    ENTER_MYTHRYL_CALLABLE_C_FN("_lib7_Sock_getNREAD");

    int device = TAGGED_INT_TO_C_INT( arg );						// Last use of 'arg'.

    RELEASE_MYTHRYL_HEAP( task->pthread, "_lib7_Sock_getNREAD", NULL );
    //
    int	                                       n;
    int status = ioctl( device, FIONREAD, (char*) &n );
    //
    RECOVER_MYTHRYL_HEAP( task->pthread, "_lib7_Sock_getNREAD" );

    if (status < 0)     return RAISE_SYSERR__MAY_HEAPCLEAN(task, status, NULL);

    return   TAGGED_INT_FROM_C_INT( n );
}
Exemplo n.º 17
0
Val   _lib7_P_ProcEnv_ttyname   (Task* task,  Val arg)   {
    //=======================
    //
    // Mythryl type:   Int -> String
    //
    // Return terminal name associated with file descriptor, if any.
    //
    // This fn gets bound as   ttyname'   in:
    //
    //     src/lib/std/src/psx/posix-id.pkg

											ENTER_MYTHRYL_CALLABLE_C_FN(__func__);
    RELEASE_MYTHRYL_HEAP( task->hostthread, __func__, NULL );
	//
	char* name = ttyname(TAGGED_INT_TO_C_INT(arg));
	//
    RECOVER_MYTHRYL_HEAP( task->hostthread, __func__ );

    if (name == NULL)   return RAISE_ERROR__MAY_HEAPCLEAN(task, "not a terminal device", NULL);
    //  
    Val result = make_ascii_string_from_c_string__may_heapclean( task, name, NULL );
											EXIT_MYTHRYL_CALLABLE_C_FN(__func__);
    return result;
}
void   partition_agegroup0_buffer_between_pthreads   (Pthread *pthread_table[]) {	// pthread_table is always   pthread_table__global
    // ===========================================
    //
    // Outside of this file, this fn is called (only) from
    //
    //     make_task   in   src/c/main/runtime-state.c
    //
    // Divide the agegroup0 buffer into smaller disjoint
    // buffers for use by the parallel pthreads.
    //
    // Typically at this point
    //
    //     task0->heap->agegroup0_buffer_bytesize
    //
    // will at this point have been set to
    //
    //	   DEFAULT_AGEGROUP0_BUFFER_BYTESIZE  				// DEFAULT_AGEGROUP0_BUFFER_BYTESIZE is defined at 256K in   src/c/h/runtime-configuration.h
    //     *
    //     MAX_PTHREADS							// MAX_PTHREADS is defined as something like 8 or 16    in   src/c/mythryl-config.h
    //
    // by the logic in
    //
    //     src/c/heapcleaner/heapcleaner-initialization.c
    //     


    int poll_freq
	=
	TAGGED_INT_TO_C_INT(
	    DEREF(
		SOFTWARE_GENERATED_PERIODIC_EVENT_INTERVAL_REFCELL__GLOBAL
	    )
	);

    Task* task;
    Task* task0 =  pthread_table[ 0 ]->task;

    int per_thread_agegroup0_buffer_bytesize
	=
	task0->heap->agegroup0_buffer_bytesize
        /
        MAX_PTHREADS;

    Val* start_of_agegroup0_buffer_for_next_pthread
	=
	task0->heap->agegroup0_buffer;

    for (int pthread = 0;   pthread < MAX_PTHREADS;   pthread++) {
        //
	task =  pthread_table[ pthread ]->task;

	#ifdef NEED_PTHREAD_SUPPORT_DEBUG
	    debug_say ("pthread_table[%d]->task-> (heap_allocation_pointer %x/heap_allocation_limit %x) changed to ", pthread, task->heap_allocation_pointer, task->heap_allocation_limit);
	#endif

	task->heap                       =  task0->heap;
	task->heap_allocation_pointer    =  start_of_agegroup0_buffer_for_next_pthread;
	task->real_heap_allocation_limit =  HEAP_ALLOCATION_LIMIT_SIZE( start_of_agegroup0_buffer_for_next_pthread, per_thread_agegroup0_buffer_bytesize );

	#if !NEED_PTHREAD_SUPPORT_FOR_SOFTWARE_GENERATED_PERIODIC_EVENTS
	    //
	    task->heap_allocation_limit
		=
		HEAP_ALLOCATION_LIMIT_SIZE(					// HEAP_ALLOCATION_LIMIT_SIZE	def in   src/c/h/heap.h
		    //								// This macro basically just subtracts a MIN_FREE_BYTES_IN_AGEGROUP0_BUFFER safety margin from the actual buffer limit.
		    start_of_agegroup0_buffer_for_next_pthread,
		    per_thread_agegroup0_buffer_bytesize
		);
	#else
	    if (poll_freq <= 0) {
		//
		task->heap_allocation_limit = task->real_heap_allocation_limit;
		//
	    } else {
		//
		// In order to generate software events at (approximately)
		// the desired frequency, we (may) here artificially decrease
		// the heaplimit pointer to trigger an early heapcleaner call,
		// at which point our logic will regain control.
		//
		#ifdef NEED_PTHREAD_SUPPORT_DEBUG
		    debug_say ("(with poll_freq=%d) ", poll_freq);
		#endif

		task->heap_allocation_limit
		    =
		    start_of_agegroup0_buffer_for_next_pthread
		    +
		    poll_freq * PERIODIC_EVENT_TIME_GRANULARITY_IN_NEXTCODE_INSTRUCTIONS;

		task->heap_allocation_limit
		    =
		    (task->heap_allocation_limit > task->real_heap_allocation_limit)
			? task->real_heap_allocation_limit
			: task->heap_allocation_limit;

	    }
	#endif

	#ifdef NEED_PTHREAD_SUPPORT_DEBUG
	    debug_say ("%x/%x\n",task->heap_allocation_pointer, task->heap_allocation_limit);
	#endif

	// Step over this pthread's buffer to
	// get start of next pthread's buffer:
	//
	start_of_agegroup0_buffer_for_next_pthread
	    =
	    (Val*) ( ((Punt) start_of_agegroup0_buffer_for_next_pthread)
                     +
                     per_thread_agegroup0_buffer_bytesize
                   );
    }										// for (int pthread = 0;   pthread < MAX_PTHREADS;   pthread++)
}										// fun partition_agegroup0_buffer_between_pthreads
Val   get_or_set_socket_linger_option   (Task* task,  Val arg)   {
    //===============================
    //
    // Mythryl type: (Socket_Fd, Null_Or(Null_Or(Int))) -> Null_Or(Int)
    //
    // Set/get the SO_LINGER option as follows:
    //   NULL		=> get current setting
    //   THE(NULL)	=> disable linger
    //   THE(THE t)	=> enable linger with timeout t.
    //
    // This function gets bound as   ctl_linger   in:
    //
    //     src/lib/std/src/socket/socket-guts.pkg
    //

													ENTER_MYTHRYL_CALLABLE_C_FN(__func__);

    int  socket = GET_TUPLE_SLOT_AS_INT( arg, 0 );
    Val	    ctl = GET_TUPLE_SLOT_AS_VAL( arg, 1 );							// Last use of 'arg'.

    struct linger   optVal;
    int		    status;

    if (ctl == OPTION_NULL) {
        //
	socklen_t  optSz =  sizeof( struct linger );

	RELEASE_MYTHRYL_HEAP( task->hostthread, __func__, NULL );
	    //
	    status =  getsockopt( socket, SOL_SOCKET, SO_LINGER, (sockoptval_t)&optVal, &optSz );
	    //
	RECOVER_MYTHRYL_HEAP( task->hostthread, __func__ );

	ASSERT( status < 0  ||  optSz == sizeof( struct linger ));
	//
    } else {
	//
	ctl = OPTION_GET(ctl);

	if (ctl == OPTION_NULL) {
	    optVal.l_onoff = 0;	    // Argument is THE(NULL); disable linger.
	} else {
	    optVal.l_onoff = 1;	    // argument is THE t; enable linger.
	    optVal.l_linger = TAGGED_INT_TO_C_INT(OPTION_GET(ctl));
	}

	RELEASE_MYTHRYL_HEAP( task->hostthread, __func__, NULL );
	    //
	    status = setsockopt (socket, SOL_SOCKET, SO_LINGER, (sockoptval_t)&optVal, sizeof(struct linger));
	    //
	RECOVER_MYTHRYL_HEAP( task->hostthread, __func__ );
    }

    if (status < 0)  		return RAISE_SYSERR__MAY_HEAPCLEAN(task, status, NULL);
    if (optVal.l_onoff == 0)    return OPTION_NULL;

    Val result =   OPTION_THE(  task,  TAGGED_INT_FROM_C_INT( optVal.l_linger )  );

									    EXIT_MYTHRYL_CALLABLE_C_FN(__func__);
    return result;
}