2016-09-28 14:40:37 +00:00
/*
* $ Id $
*
2018-02-07 14:13:13 +00:00
Copyright ( c ) 2016 - 2018 Chung , Hyung - Hwan . All rights reserved .
2016-09-28 14:40:37 +00:00
Redistribution and use in source and binary forms , with or without
modification , are permitted provided that the following conditions
are met :
1. Redistributions of source code must retain the above copyright
notice , this list of conditions and the following disclaimer .
2. Redistributions in binary form must reproduce the above copyright
notice , this list of conditions and the following disclaimer in the
documentation and / or other materials provided with the distribution .
THIS SOFTWARE IS PROVIDED BY THE AUTHOR " AS IS " AND ANY EXPRESS OR
IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED .
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT , INDIRECT ,
INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT
NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE ,
DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*/
# include "hcl-prv.h"
2016-10-04 17:56:28 +00:00
# define PROC_STATE_RUNNING 3
# define PROC_STATE_WAITING 2
# define PROC_STATE_RUNNABLE 1
# define PROC_STATE_SUSPENDED 0
# define PROC_STATE_TERMINATED -1
2020-10-15 12:57:05 +00:00
static const char * io_type_str [ ] =
{
" input " ,
" output "
} ;
2018-02-08 09:21:18 +00:00
static HCL_INLINE const char * proc_state_to_string ( int state )
{
static const hcl_bch_t * str [ ] =
{
" TERMINATED " ,
" SUSPENDED " ,
" RUNNABLE " ,
" WAITING " ,
" RUNNING "
} ;
return str [ state + 1 ] ;
}
# define PROC_MAP_INC 64
2020-10-15 12:57:05 +00:00
/* TODO: adjust these max semaphore pointer buffer capacity,
* proably depending on the object memory size ? */
2016-10-04 17:56:28 +00:00
# define SEM_LIST_INC 256
# define SEM_HEAP_INC 256
2020-10-15 12:57:05 +00:00
# define SEM_IO_TUPLE_INC 256
2016-10-04 17:56:28 +00:00
# define SEM_LIST_MAX (SEM_LIST_INC * 1000)
# define SEM_HEAP_MAX (SEM_HEAP_INC * 1000)
2020-10-15 12:57:05 +00:00
# define SEM_IO_TUPLE_MAX (SEM_IO_TUPLE_INC * 1000)
# define SEM_IO_MAP_ALIGN 1024 /* this must a power of 2 */
2016-10-04 17:56:28 +00:00
# define SEM_HEAP_PARENT(x) (((x) - 1) / 2)
# define SEM_HEAP_LEFT(x) ((x) * 2 + 1)
# define SEM_HEAP_RIGHT(x) ((x) * 2 + 2)
# define SEM_HEAP_EARLIER_THAN(stx,x,y) ( \
2020-10-15 12:57:05 +00:00
( HCL_OOP_TO_SMOOI ( ( x ) - > u . timed . ftime_sec ) < HCL_OOP_TO_SMOOI ( ( y ) - > u . timed . ftime_sec ) ) | | \
( HCL_OOP_TO_SMOOI ( ( x ) - > u . timed . ftime_sec ) = = HCL_OOP_TO_SMOOI ( ( y ) - > u . timed . ftime_sec ) & & HCL_OOP_TO_SMOOI ( ( x ) - > u . timed . ftime_nsec ) < HCL_OOP_TO_SMOOI ( ( y ) - > u . timed . ftime_nsec ) ) \
2016-10-04 17:56:28 +00:00
)
# define LOAD_IP(hcl, v_ctx) ((hcl)->ip = HCL_OOP_TO_SMOOI((v_ctx)->ip))
# define STORE_IP(hcl, v_ctx) ((v_ctx)->ip = HCL_SMOOI_TO_OOP((hcl)->ip))
# define LOAD_SP(hcl, v_ctx) ((hcl)->sp = HCL_OOP_TO_SMOOI((v_ctx)->sp))
# define STORE_SP(hcl, v_ctx) ((v_ctx)->sp = HCL_SMOOI_TO_OOP((hcl)->sp))
# define LOAD_ACTIVE_IP(hcl) LOAD_IP(hcl, (hcl)->active_context)
# define STORE_ACTIVE_IP(hcl) STORE_IP(hcl, (hcl)->active_context)
# define LOAD_ACTIVE_SP(hcl) LOAD_SP(hcl, (hcl)->processor->active)
# define STORE_ACTIVE_SP(hcl) STORE_SP(hcl, (hcl)->processor->active)
# define SWITCH_ACTIVE_CONTEXT(hcl,v_ctx) \
do \
{ \
STORE_ACTIVE_IP ( hcl ) ; \
( hcl ) - > active_context = ( v_ctx ) ; \
2020-10-05 09:37:26 +00:00
( hcl ) - > active_function = ( hcl ) - > active_context - > origin - > receiver_or_base ; \
2020-10-04 18:21:05 +00:00
( hcl ) - > active_code = HCL_FUNCTION_GET_CODE_BYTE ( ( hcl ) - > active_function ) ; \
2016-10-04 17:56:28 +00:00
LOAD_ACTIVE_IP ( hcl ) ; \
( hcl ) - > processor - > active - > current_context = ( hcl ) - > active_context ; \
} while ( 0 )
2020-10-04 18:21:05 +00:00
/*#define FETCH_BYTE_CODE(hcl) ((hcl)->code.bc.arr->slot[(hcl)->ip++])*/
# define FETCH_BYTE_CODE(hcl) ((hcl)->active_code[(hcl)->ip++])
2016-10-04 17:56:28 +00:00
# define FETCH_BYTE_CODE_TO(hcl, v_oow) (v_oow = FETCH_BYTE_CODE(hcl))
2021-01-29 12:39:31 +00:00
# if (HCL_CODE_LONG_PARAM_SIZE == 2)
2016-10-04 17:56:28 +00:00
# define FETCH_PARAM_CODE_TO(hcl, v_oow) \
do { \
v_oow = FETCH_BYTE_CODE ( hcl ) ; \
v_oow = ( v_oow < < 8 ) | FETCH_BYTE_CODE ( hcl ) ; \
} while ( 0 )
# else
# define FETCH_PARAM_CODE_TO(hcl, v_oow) (v_oow = FETCH_BYTE_CODE(hcl))
# endif
# if defined(HCL_DEBUG_VM_EXEC)
2018-02-05 15:59:32 +00:00
# define LOG_MASK_INST (HCL_LOG_IC | HCL_LOG_MNEMONIC | HCL_LOG_INFO)
2016-10-04 17:56:28 +00:00
2016-10-06 17:49:47 +00:00
# define LOG_INST_0(hcl,fmt) HCL_LOG1(hcl, LOG_MASK_INST, "%010zd " fmt "\n", fetched_instruction_pointer)
# define LOG_INST_1(hcl,fmt,a1) HCL_LOG2(hcl, LOG_MASK_INST, "%010zd " fmt "\n",fetched_instruction_pointer, a1)
# define LOG_INST_2(hcl,fmt,a1,a2) HCL_LOG3(hcl, LOG_MASK_INST, "%010zd " fmt "\n", fetched_instruction_pointer, a1, a2)
# define LOG_INST_3(hcl,fmt,a1,a2,a3) HCL_LOG4(hcl, LOG_MASK_INST, "%010zd " fmt "\n", fetched_instruction_pointer, a1, a2, a3)
2020-10-04 18:21:05 +00:00
# define LOG_INST_4(hcl,fmt,a1,a2,a3,a4) HCL_LOG5(hcl, LOG_MASK_INST, "%010zd " fmt "\n", fetched_instruction_pointer, a1, a2, a3, a4)
2016-10-04 17:56:28 +00:00
# else
# define LOG_INST_0(hcl,fmt)
# define LOG_INST_1(hcl,fmt,a1)
# define LOG_INST_2(hcl,fmt,a1,a2)
# define LOG_INST_3(hcl,fmt,a1,a2,a3)
2020-11-15 09:56:06 +00:00
# define LOG_INST_4(hcl,fmt,a1,a2,a3,a4)
2016-10-04 17:56:28 +00:00
# endif
2020-10-15 12:57:05 +00:00
static int delete_sem_from_sem_io_tuple ( hcl_t * hcl , hcl_oop_semaphore_t sem , int force ) ;
static void signal_io_semaphore ( hcl_t * hcl , hcl_ooi_t io_handle , hcl_ooi_t mask ) ;
/* ------------------------------------------------------------------------- */
static HCL_INLINE int vm_startup ( hcl_t * hcl )
2016-10-04 17:56:28 +00:00
{
2018-03-10 17:53:44 +00:00
hcl_cb_t * cb ;
2020-10-15 12:57:05 +00:00
hcl_oow_t i ;
2018-02-08 15:04:07 +00:00
HCL_DEBUG1 ( hcl , " VM started up at IP %zd \n " , hcl - > ip ) ;
2016-10-04 17:56:28 +00:00
2018-03-10 17:53:44 +00:00
for ( cb = hcl - > cblist ; cb ; cb = cb - > next )
{
if ( cb - > vm_startup & & cb - > vm_startup ( hcl ) < = - 1 )
{
for ( cb = cb - > prev ; cb ; cb = cb - > prev )
{
if ( cb - > vm_cleanup ) cb - > vm_cleanup ( hcl ) ;
}
return - 1 ;
}
}
2020-10-15 12:57:05 +00:00
for ( i = 0 ; i < hcl - > sem_io_map_capa ; i + + )
{
hcl - > sem_io_map [ i ] = - 1 ;
}
# if defined(ENABLE_GCFIN)
2020-11-15 10:26:14 +00:00
hcl - > sem_gcfin = ( moo_oop_semaphore_t ) hcl - > _nil ;
hcl - > sem_gcfin_sigreq = 0 ;
2020-10-15 12:57:05 +00:00
# endif
hcl - > vmprim . vm_gettime ( hcl , & hcl - > exec_start_time ) ; /* raw time. no adjustment */
2016-10-04 17:56:28 +00:00
2018-02-08 14:40:56 +00:00
return 0 ;
2016-10-04 17:56:28 +00:00
}
static void vm_cleanup ( hcl_t * hcl )
{
2018-03-10 17:53:44 +00:00
hcl_cb_t * cb ;
2020-10-15 12:57:05 +00:00
hcl_oow_t i ;
for ( i = 0 ; i < hcl - > sem_io_map_capa ; )
{
hcl_ooi_t sem_io_index ;
if ( ( sem_io_index = hcl - > sem_io_map [ i ] ) > = 0 )
{
HCL_ASSERT ( hcl , sem_io_index < hcl - > sem_io_tuple_count ) ;
HCL_ASSERT ( hcl , hcl - > sem_io_tuple [ sem_io_index ] . sem [ HCL_SEMAPHORE_IO_TYPE_INPUT ] | |
hcl - > sem_io_tuple [ sem_io_index ] . sem [ HCL_SEMAPHORE_IO_TYPE_OUTPUT ] ) ;
if ( hcl - > sem_io_tuple [ sem_io_index ] . sem [ HCL_SEMAPHORE_IO_TYPE_INPUT ] )
{
delete_sem_from_sem_io_tuple ( hcl , hcl - > sem_io_tuple [ sem_io_index ] . sem [ HCL_SEMAPHORE_IO_TYPE_INPUT ] , 1 ) ;
}
if ( hcl - > sem_io_tuple [ sem_io_index ] . sem [ HCL_SEMAPHORE_IO_TYPE_OUTPUT ] )
{
delete_sem_from_sem_io_tuple ( hcl , hcl - > sem_io_tuple [ sem_io_index ] . sem [ HCL_SEMAPHORE_IO_TYPE_OUTPUT ] , 1 ) ;
}
HCL_ASSERT ( hcl , hcl - > sem_io_map [ i ] < = - 1 ) ;
}
else
{
i + + ;
}
}
HCL_ASSERT ( hcl , hcl - > sem_io_tuple_count = = 0 ) ;
HCL_ASSERT ( hcl , hcl - > sem_io_count = = 0 ) ;
hcl - > vmprim . vm_gettime ( hcl , & hcl - > exec_end_time ) ; /* raw time. no adjustment */
2018-03-10 17:53:44 +00:00
for ( cb = hcl - > cblist ; cb ; cb = cb - > next )
{
if ( cb - > vm_cleanup ) cb - > vm_cleanup ( hcl ) ;
}
2020-10-15 12:57:05 +00:00
# if defined(ENABLE_GCFIN)
2020-11-15 10:26:14 +00:00
hcl - > sem_gcfin = ( moo_oop_semaphore_t ) hcl - > _nil ;
hcl - > sem_gcfin_sigreq = 0 ;
2020-10-15 12:57:05 +00:00
/* deregister all pending finalizable objects pending just in case these
* have not been removed for various reasons . ( e . g . sudden VM abortion )
*/
hcl_deregallfinalizables ( hcl ) ;
# endif
HCL_DEBUG0 ( hcl , " VM cleaned up \n " ) ;
}
static HCL_INLINE void vm_gettime ( hcl_t * hcl , hcl_ntime_t * now )
{
hcl - > vmprim . vm_gettime ( hcl , now ) ;
/* in vm_startup(), hcl->exec_start_time has been set to the time of
* that moment . time returned here get offset by hcl - > exec_start_time and
* thus becomes relative to it . this way , it is kept small such that it
* can be represented in a small integer with leaving almost zero chance
* of overflow . */
HCL_SUB_NTIME ( now , now , & hcl - > exec_start_time ) ; /* now = now - exec_start_time */
}
static HCL_INLINE int vm_sleep ( hcl_t * hcl , const hcl_ntime_t * dur )
{
/* TODO: return 1 if it gets into the halting state */
hcl - > vmprim . vm_sleep ( hcl , dur ) ;
return 0 ;
}
static HCL_INLINE void vm_muxwait ( hcl_t * hcl , const hcl_ntime_t * dur )
{
hcl - > vmprim . vm_muxwait ( hcl , dur , signal_io_semaphore ) ;
2016-10-04 17:56:28 +00:00
}
2018-03-11 11:16:28 +00:00
static void vm_checkbc ( hcl_t * hcl , hcl_oob_t bcode )
2018-03-10 17:53:44 +00:00
{
hcl_cb_t * cb ;
for ( cb = hcl - > cblist ; cb ; cb = cb - > next )
{
2018-03-11 11:16:28 +00:00
if ( cb - > vm_checkbc ) cb - > vm_checkbc ( hcl , bcode ) ;
2018-03-10 17:53:44 +00:00
}
}
2020-10-15 12:57:05 +00:00
2016-10-04 17:56:28 +00:00
/* ------------------------------------------------------------------------- */
2020-10-15 12:57:05 +00:00
static HCL_INLINE hcl_oop_context_t make_context ( hcl_t * hcl , hcl_ooi_t ntmprs )
2016-10-04 17:56:28 +00:00
{
2018-02-05 10:43:25 +00:00
HCL_ASSERT ( hcl , ntmprs > = 0 ) ;
2020-10-15 12:57:05 +00:00
return ( hcl_oop_context_t ) hcl_allocoopobj ( hcl , HCL_BRAND_CONTEXT , HCL_CONTEXT_NAMED_INSTVARS + ( hcl_oow_t ) ntmprs ) ;
2016-10-04 17:56:28 +00:00
}
2021-02-01 03:32:09 +00:00
static HCL_INLINE hcl_oop_function_t make_function ( hcl_t * hcl , hcl_oow_t lfsize , const hcl_oob_t * bptr , hcl_oow_t blen , hcl_dbgi_t * dbgi )
2020-10-04 18:21:05 +00:00
{
2021-01-29 12:39:31 +00:00
hcl_oop_function_t func ;
2020-10-04 18:21:05 +00:00
/* the literal frame is placed in the variable part.
* the byte code is placed in the trailer space */
2021-01-29 12:39:31 +00:00
func = ( hcl_oop_function_t ) hcl_allocoopobjwithtrailer ( hcl , HCL_BRAND_FUNCTION , HCL_FUNCTION_NAMED_INSTVARS + lfsize , bptr , blen ) ;
if ( HCL_UNLIKELY ( ! func ) ) return HCL_NULL ;
2021-02-01 03:32:09 +00:00
if ( dbgi )
2021-01-29 12:39:31 +00:00
{
hcl_oop_t tmp ;
hcl_pushvolat ( hcl , ( hcl_oop_t * ) & func ) ;
2021-02-01 03:32:09 +00:00
tmp = hcl_makebytearray ( hcl , ( hcl_oob_t * ) dbgi , HCL_SIZEOF ( * dbgi ) * blen ) ;
2021-01-29 12:39:31 +00:00
hcl_popvolat ( hcl ) ;
if ( tmp ) func - > dbgi = tmp ;
}
return func ;
2020-10-04 18:21:05 +00:00
}
2020-10-04 19:34:53 +00:00
static HCL_INLINE void fill_function_data ( hcl_t * hcl , hcl_oop_function_t func , hcl_ooi_t nargs , hcl_ooi_t ntmprs , hcl_oop_context_t homectx , const hcl_oop_t * lfptr , hcl_oow_t lfsize )
2020-10-04 18:21:05 +00:00
{
/* Although this function could be integrated into make_function(),
* this function has been separated from make_function ( ) to make GC handling simpler */
hcl_oow_t i ;
2020-10-09 07:14:32 +00:00
HCL_ASSERT ( hcl , nargs > = 0 & & nargs < = HCL_SMOOI_MAX ) ;
HCL_ASSERT ( hcl , ntmprs > = 0 & & ntmprs < = HCL_SMOOI_MAX ) ;
HCL_ASSERT ( hcl , nargs < = ntmprs ) ;
2020-10-04 18:21:05 +00:00
/* copy literal frames */
HCL_ASSERT ( hcl , lfsize < = HCL_OBJ_GET_SIZE ( func ) - HCL_FUNCTION_NAMED_INSTVARS ) ;
2020-10-05 14:49:54 +00:00
for ( i = 0 ; i < lfsize ; i + + )
{
func - > literal_frame [ i ] = lfptr [ i ] ;
2020-10-15 12:57:05 +00:00
#if 0
2020-10-05 14:49:54 +00:00
HCL_DEBUG2 ( hcl , " literal frame %d => %O \n " , ( int ) i , lfptr [ i ] ) ;
2020-10-15 12:57:05 +00:00
# endif
2020-10-05 14:49:54 +00:00
}
2020-10-04 18:21:05 +00:00
/* initialize other fields */
func - > home = homectx ;
func - > nargs = HCL_SMOOI_TO_OOP ( nargs ) ;
func - > ntmprs = HCL_SMOOI_TO_OOP ( ntmprs ) ;
}
2020-10-09 07:14:32 +00:00
static HCL_INLINE hcl_oop_block_t make_block ( hcl_t * hcl )
{
/* create a base block used for creation of a block context */
2020-10-15 12:57:05 +00:00
return ( hcl_oop_block_t ) hcl_allocoopobj ( hcl , HCL_BRAND_BLOCK , HCL_BLOCK_NAMED_INSTVARS ) ;
2020-10-09 07:14:32 +00:00
}
static HCL_INLINE void fill_block_data ( hcl_t * hcl , hcl_oop_block_t blk , hcl_ooi_t nargs , hcl_ooi_t ntmprs , hcl_ooi_t ip , hcl_oop_context_t homectx )
{
HCL_ASSERT ( hcl , nargs > = 0 & & nargs < = HCL_SMOOI_MAX ) ;
HCL_ASSERT ( hcl , ntmprs > = 0 & & ntmprs < = HCL_SMOOI_MAX ) ;
HCL_ASSERT ( hcl , nargs < = ntmprs ) ;
HCL_ASSERT ( hcl , ip > = 0 & & nargs < = HCL_SMOOI_MAX ) ;
blk - > home = homectx ;
blk - > nargs = HCL_SMOOI_TO_OOP ( nargs ) ;
blk - > ntmprs = HCL_SMOOI_TO_OOP ( ntmprs ) ;
blk - > ip = HCL_SMOOI_TO_OOP ( ip ) ;
}
2018-02-08 09:21:18 +00:00
static HCL_INLINE int prepare_to_alloc_pid ( hcl_t * hcl )
{
hcl_oow_t new_capa ;
hcl_ooi_t i , j ;
hcl_oop_t * tmp ;
HCL_ASSERT ( hcl , hcl - > proc_map_free_first < = - 1 ) ;
HCL_ASSERT ( hcl , hcl - > proc_map_free_last < = - 1 ) ;
new_capa = hcl - > proc_map_capa + PROC_MAP_INC ;
if ( new_capa > HCL_SMOOI_MAX )
{
if ( hcl - > proc_map_capa > = HCL_SMOOI_MAX )
{
# if defined(HCL_DEBUG_VM_PROCESSOR)
HCL_LOG0 ( hcl , HCL_LOG_IC | HCL_LOG_FATAL , " Processor - too many processes \n " ) ;
# endif
2018-02-15 15:36:15 +00:00
hcl_seterrbfmt ( hcl , HCL_EPFULL , " maximum number(%zd) of processes reached " , HCL_SMOOI_MAX ) ;
2018-02-08 09:21:18 +00:00
return - 1 ;
}
new_capa = HCL_SMOOI_MAX ;
}
2018-02-26 15:24:45 +00:00
tmp = ( hcl_oop_t * ) hcl_reallocmem ( hcl , hcl - > proc_map , HCL_SIZEOF ( hcl_oop_t ) * new_capa ) ;
2018-02-08 09:21:18 +00:00
if ( ! tmp ) return - 1 ;
hcl - > proc_map_free_first = hcl - > proc_map_capa ;
for ( i = hcl - > proc_map_capa , j = hcl - > proc_map_capa + 1 ; j < new_capa ; i + + , j + + )
{
tmp [ i ] = HCL_SMOOI_TO_OOP ( j ) ;
}
tmp [ i ] = HCL_SMOOI_TO_OOP ( - 1 ) ;
hcl - > proc_map_free_last = i ;
hcl - > proc_map = tmp ;
hcl - > proc_map_capa = new_capa ;
return 0 ;
}
static HCL_INLINE void alloc_pid ( hcl_t * hcl , hcl_oop_process_t proc )
{
hcl_ooi_t pid ;
pid = hcl - > proc_map_free_first ;
proc - > id = HCL_SMOOI_TO_OOP ( pid ) ;
HCL_ASSERT ( hcl , HCL_OOP_IS_SMOOI ( hcl - > proc_map [ pid ] ) ) ;
hcl - > proc_map_free_first = HCL_OOP_TO_SMOOI ( hcl - > proc_map [ pid ] ) ;
if ( hcl - > proc_map_free_first < = - 1 ) hcl - > proc_map_free_last = - 1 ;
hcl - > proc_map [ pid ] = ( hcl_oop_t ) proc ;
2020-10-15 12:57:05 +00:00
hcl - > proc_map_used + + ;
2018-02-08 09:21:18 +00:00
}
static HCL_INLINE void free_pid ( hcl_t * hcl , hcl_oop_process_t proc )
{
hcl_ooi_t pid ;
pid = HCL_OOP_TO_SMOOI ( proc - > id ) ;
HCL_ASSERT ( hcl , pid < hcl - > proc_map_capa ) ;
2020-10-15 12:57:05 +00:00
HCL_ASSERT ( hcl , hcl - > proc_map_used > 0 ) ;
2018-02-08 09:21:18 +00:00
hcl - > proc_map [ pid ] = HCL_SMOOI_TO_OOP ( - 1 ) ;
if ( hcl - > proc_map_free_last < = - 1 )
{
HCL_ASSERT ( hcl , hcl - > proc_map_free_first < = - 1 ) ;
hcl - > proc_map_free_first = pid ;
}
else
{
hcl - > proc_map [ hcl - > proc_map_free_last ] = HCL_SMOOI_TO_OOP ( pid ) ;
}
hcl - > proc_map_free_last = pid ;
2020-10-15 12:57:05 +00:00
hcl - > proc_map_used - - ;
2018-02-08 09:21:18 +00:00
}
2016-10-04 17:56:28 +00:00
static hcl_oop_process_t make_process ( hcl_t * hcl , hcl_oop_context_t c )
{
hcl_oop_process_t proc ;
hcl_oow_t stksize ;
2020-10-15 12:57:05 +00:00
hcl_ooi_t total_count ;
hcl_ooi_t suspended_count ;
total_count = HCL_OOP_TO_SMOOI ( hcl - > processor - > total_count ) ;
if ( total_count > = HCL_SMOOI_MAX )
{
# if defined(HCL_DEBUG_VM_PROCESSOR)
HCL_LOG0 ( hcl , HCL_LOG_IC | HCL_LOG_FATAL , " Processor - too many processes \n " ) ;
# endif
hcl_seterrbfmt ( hcl , HCL_EPFULL , " maximum number(%zd) of processes reached " , HCL_SMOOI_MAX ) ;
return HCL_NULL ;
}
2016-10-04 17:56:28 +00:00
2018-02-08 09:21:18 +00:00
if ( hcl - > proc_map_free_first < = - 1 & & prepare_to_alloc_pid ( hcl ) < = - 1 ) return HCL_NULL ;
2016-10-04 17:56:28 +00:00
stksize = hcl - > option . dfl_procstk_size ;
if ( stksize > HCL_TYPE_MAX ( hcl_oow_t ) - HCL_PROCESS_NAMED_INSTVARS )
stksize = HCL_TYPE_MAX ( hcl_oow_t ) - HCL_PROCESS_NAMED_INSTVARS ;
2020-12-31 17:48:47 +00:00
hcl_pushvolat ( hcl , ( hcl_oop_t * ) & c ) ;
2020-10-04 18:21:05 +00:00
proc = ( hcl_oop_process_t ) hcl_allocoopobj ( hcl , HCL_BRAND_PROCESS , HCL_PROCESS_NAMED_INSTVARS + stksize ) ;
2020-12-31 17:48:47 +00:00
hcl_popvolat ( hcl ) ;
2020-10-04 18:21:05 +00:00
if ( HCL_UNLIKELY ( ! proc ) ) return HCL_NULL ;
2016-10-04 17:56:28 +00:00
2020-10-15 12:57:05 +00:00
#if 0
////////////////////
//// HCL_OBJ_SET_FLAGS_PROC (proc, proc_flags); /* a special flag to indicate an object is a process instance */
////////////////////
# endif
proc - > state = HCL_SMOOI_TO_OOP ( PROC_STATE_SUSPENDED ) ;
2018-02-08 09:21:18 +00:00
/* assign a process id to the process */
alloc_pid ( hcl , proc ) ;
2016-10-04 17:56:28 +00:00
proc - > initial_context = c ;
proc - > current_context = c ;
proc - > sp = HCL_SMOOI_TO_OOP ( - 1 ) ;
2018-02-05 10:43:25 +00:00
HCL_ASSERT ( hcl , ( hcl_oop_t ) c - > sender = = hcl - > _nil ) ;
2016-10-04 17:56:28 +00:00
# if defined(HCL_DEBUG_VM_PROCESSOR)
2018-02-08 09:21:18 +00:00
HCL_LOG2 ( hcl , HCL_LOG_IC | HCL_LOG_DEBUG , " Processor - process[%zd] **CREATED**->%hs \n " , HCL_OOP_TO_SMOOI ( proc - > id ) , proc_state_to_string ( HCL_OOP_TO_SMOOI ( proc - > state ) ) ) ;
2016-10-04 17:56:28 +00:00
# endif
2020-10-15 12:57:05 +00:00
/* a process is created in the SUSPENDED state. chain it to the suspended process list */
suspended_count = HCL_OOP_TO_SMOOI ( hcl - > processor - > suspended . count ) ;
HCL_APPEND_TO_OOP_LIST ( hcl , & hcl - > processor - > suspended , hcl_oop_process_t , proc , ps ) ;
suspended_count + + ;
hcl - > processor - > suspended . count = HCL_SMOOI_TO_OOP ( suspended_count ) ;
total_count + + ;
hcl - > processor - > total_count = HCL_SMOOI_TO_OOP ( total_count ) ;
2016-10-04 17:56:28 +00:00
return proc ;
}
static HCL_INLINE void sleep_active_process ( hcl_t * hcl , int state )
{
STORE_ACTIVE_SP ( hcl ) ;
2020-10-15 12:57:05 +00:00
/* store the current active context to the current process.
* it is the suspended context of the process to be suspended */
HCL_ASSERT ( hcl , hcl - > processor - > active ! = hcl - > nil_process ) ;
2018-02-08 09:21:18 +00:00
# if defined(HCL_DEBUG_VM_PROCESSOR)
HCL_LOG3 ( hcl , HCL_LOG_IC | HCL_LOG_DEBUG , " Processor - process[%zd] %hs->%hs in sleep_active_process \n " , HCL_OOP_TO_SMOOI ( hcl - > processor - > active - > id ) , proc_state_to_string ( HCL_OOP_TO_SMOOI ( hcl - > processor - > active - > state ) ) , proc_state_to_string ( state ) ) ;
# endif
2016-10-04 17:56:28 +00:00
hcl - > processor - > active - > current_context = hcl - > active_context ;
hcl - > processor - > active - > state = HCL_SMOOI_TO_OOP ( state ) ;
}
2020-10-15 12:57:05 +00:00
static HCL_INLINE void wake_process ( hcl_t * hcl , hcl_oop_process_t proc )
2016-10-04 17:56:28 +00:00
{
2018-02-08 09:21:18 +00:00
# if defined(HCL_DEBUG_VM_PROCESSOR)
HCL_LOG2 ( hcl , HCL_LOG_IC | HCL_LOG_DEBUG , " Processor - process[%zd] %hs->RUNNING in wake_process \n " , HCL_OOP_TO_SMOOI ( proc - > id ) , proc_state_to_string ( HCL_OOP_TO_SMOOI ( proc - > state ) ) ) ;
# endif
2016-10-04 17:56:28 +00:00
/* activate the given process */
2020-10-15 12:57:05 +00:00
HCL_ASSERT ( hcl , proc - > state = = HCL_SMOOI_TO_OOP ( PROC_STATE_RUNNABLE ) ) ;
2016-10-04 17:56:28 +00:00
proc - > state = HCL_SMOOI_TO_OOP ( PROC_STATE_RUNNING ) ;
hcl - > processor - > active = proc ;
LOAD_ACTIVE_SP ( hcl ) ;
/* activate the suspended context of the new process */
SWITCH_ACTIVE_CONTEXT ( hcl , proc - > current_context ) ;
2018-02-08 09:21:18 +00:00
# if defined(HCL_DEBUG_VM_PROCESSOR) && (HCL_DEBUG_VM_PROCESSOR >= 2)
HCL_LOG3 ( hcl , HCL_LOG_IC | HCL_LOG_DEBUG , " Processor - woke up process[%zd] context %O ip=%zd \n " , HCL_OOP_TO_SMOOI ( hcl - > processor - > active - > id ) , hcl - > active_context , hcl - > ip ) ;
2016-10-04 17:56:28 +00:00
# endif
}
static void switch_to_process ( hcl_t * hcl , hcl_oop_process_t proc , int new_state_for_old_active )
{
/* the new process must not be the currently active process */
2018-02-05 10:43:25 +00:00
HCL_ASSERT ( hcl , hcl - > processor - > active ! = proc ) ;
2016-10-04 17:56:28 +00:00
/* the new process must be in the runnable state */
2018-02-05 10:43:25 +00:00
HCL_ASSERT ( hcl , proc - > state = = HCL_SMOOI_TO_OOP ( PROC_STATE_RUNNABLE ) | |
2016-10-04 17:56:28 +00:00
proc - > state = = HCL_SMOOI_TO_OOP ( PROC_STATE_WAITING ) ) ;
sleep_active_process ( hcl , new_state_for_old_active ) ;
2020-10-15 12:57:05 +00:00
wake_process ( hcl , proc ) ;
2016-10-04 17:56:28 +00:00
hcl - > proc_switched = 1 ;
}
2020-10-15 12:57:05 +00:00
static HCL_INLINE void switch_to_process_from_nil ( hcl_t * hcl , hcl_oop_process_t proc )
{
HCL_ASSERT ( hcl , hcl - > processor - > active = = hcl - > nil_process ) ;
wake_process ( hcl , proc ) ;
hcl - > proc_switched = 1 ;
}
2016-10-04 17:56:28 +00:00
static HCL_INLINE hcl_oop_process_t find_next_runnable_process ( hcl_t * hcl )
{
2020-10-15 12:57:05 +00:00
hcl_oop_process_t nrp ;
2018-02-05 10:43:25 +00:00
HCL_ASSERT ( hcl , hcl - > processor - > active - > state = = HCL_SMOOI_TO_OOP ( PROC_STATE_RUNNING ) ) ;
2020-10-15 12:57:05 +00:00
nrp = hcl - > processor - > active - > ps . next ;
if ( ( hcl_oop_t ) nrp = = hcl - > _nil ) nrp = hcl - > processor - > runnable . first ;
return nrp ;
2016-10-04 17:56:28 +00:00
}
static HCL_INLINE void switch_to_next_runnable_process ( hcl_t * hcl )
{
hcl_oop_process_t nrp ;
nrp = find_next_runnable_process ( hcl ) ;
if ( nrp ! = hcl - > processor - > active ) switch_to_process ( hcl , nrp , PROC_STATE_RUNNABLE ) ;
}
2020-10-15 12:57:05 +00:00
static HCL_INLINE void chain_into_processor ( hcl_t * hcl , hcl_oop_process_t proc , int new_state )
2016-10-04 17:56:28 +00:00
{
/* the process is not scheduled at all.
* link it to the processor ' s process list . */
2020-10-15 12:57:05 +00:00
hcl_ooi_t runnable_count ;
hcl_ooi_t suspended_count ;
2016-10-04 17:56:28 +00:00
2020-10-15 12:57:05 +00:00
/*HCL_ASSERT (hcl, (hcl_oop_t)proc->ps.prev == hcl->_nil);
HCL_ASSERT ( hcl , ( hcl_oop_t ) proc - > ps . next = = hcl - > _nil ) ; */
2016-10-04 17:56:28 +00:00
2018-02-05 10:43:25 +00:00
HCL_ASSERT ( hcl , proc - > state = = HCL_SMOOI_TO_OOP ( PROC_STATE_SUSPENDED ) ) ;
2020-10-15 12:57:05 +00:00
HCL_ASSERT ( hcl , new_state = = PROC_STATE_RUNNABLE | | new_state = = PROC_STATE_RUNNING ) ;
2016-10-04 17:56:28 +00:00
2018-02-08 09:21:18 +00:00
# if defined(HCL_DEBUG_VM_PROCESSOR)
HCL_LOG3 ( hcl , HCL_LOG_IC | HCL_LOG_DEBUG ,
" Processor - process[%zd] %hs->%hs in chain_into_processor \n " ,
HCL_OOP_TO_SMOOI ( proc - > id ) ,
proc_state_to_string ( HCL_OOP_TO_SMOOI ( proc - > state ) ) ,
proc_state_to_string ( new_state ) ) ;
# endif
2020-10-15 12:57:05 +00:00
runnable_count = HCL_OOP_TO_SMOOI ( hcl - > processor - > runnable . count ) ;
2016-10-04 17:56:28 +00:00
2020-10-15 12:57:05 +00:00
HCL_ASSERT ( hcl , runnable_count > = 0 ) ;
suspended_count = HCL_OOP_TO_SMOOI ( hcl - > processor - > suspended . count ) ;
HCL_DELETE_FROM_OOP_LIST ( hcl , & hcl - > processor - > suspended , proc , ps ) ;
suspended_count - - ;
hcl - > processor - > suspended . count = HCL_SMOOI_TO_OOP ( suspended_count ) ;
2016-10-04 17:56:28 +00:00
/* append to the runnable list */
2020-10-15 12:57:05 +00:00
HCL_APPEND_TO_OOP_LIST ( hcl , & hcl - > processor - > runnable , hcl_oop_process_t , proc , ps ) ;
2018-02-08 09:21:18 +00:00
proc - > state = HCL_SMOOI_TO_OOP ( new_state ) ;
2016-10-04 17:56:28 +00:00
2020-10-15 12:57:05 +00:00
runnable_count + + ;
hcl - > processor - > runnable . count = HCL_SMOOI_TO_OOP ( runnable_count ) ;
2016-10-04 17:56:28 +00:00
}
2018-02-08 09:21:18 +00:00
static HCL_INLINE void unchain_from_processor ( hcl_t * hcl , hcl_oop_process_t proc , int new_state )
2016-10-04 17:56:28 +00:00
{
2020-10-15 12:57:05 +00:00
hcl_ooi_t runnable_count ;
hcl_ooi_t suspended_count ;
hcl_ooi_t total_count ;
2016-10-04 17:56:28 +00:00
2018-02-05 10:43:25 +00:00
HCL_ASSERT ( hcl , proc - > state = = HCL_SMOOI_TO_OOP ( PROC_STATE_RUNNING ) | |
2020-10-15 12:57:05 +00:00
proc - > state = = HCL_SMOOI_TO_OOP ( PROC_STATE_RUNNABLE ) | |
proc - > state = = HCL_SMOOI_TO_OOP ( PROC_STATE_SUSPENDED ) ) ;
2016-10-04 17:56:28 +00:00
2020-10-15 12:57:05 +00:00
HCL_ASSERT ( hcl , proc - > state ! = HCL_SMOOI_TO_OOP ( new_state ) ) ;
2016-10-04 17:56:28 +00:00
2018-02-08 09:21:18 +00:00
# if defined(HCL_DEBUG_VM_PROCESSOR)
HCL_LOG3 ( hcl , HCL_LOG_IC | HCL_LOG_DEBUG , " Processor - process[%zd] %hs->%hs in unchain_from_processor \n " , HCL_OOP_TO_SMOOI ( proc - > id ) , proc_state_to_string ( HCL_OOP_TO_SMOOI ( proc - > state ) ) , proc_state_to_string ( HCL_OOP_TO_SMOOI ( new_state ) ) ) ;
# endif
2020-10-15 12:57:05 +00:00
if ( proc - > state = = HCL_SMOOI_TO_OOP ( PROC_STATE_SUSPENDED ) )
{
suspended_count = HCL_OOP_TO_SMOOI ( hcl - > processor - > suspended . count ) ;
HCL_ASSERT ( hcl , suspended_count > 0 ) ;
HCL_DELETE_FROM_OOP_LIST ( hcl , & hcl - > processor - > suspended , proc , ps ) ;
suspended_count - - ;
hcl - > processor - > suspended . count = HCL_SMOOI_TO_OOP ( suspended_count ) ;
}
else
{
runnable_count = HCL_OOP_TO_SMOOI ( hcl - > processor - > runnable . count ) ;
HCL_ASSERT ( hcl , runnable_count > 0 ) ;
HCL_DELETE_FROM_OOP_LIST ( hcl , & hcl - > processor - > runnable , proc , ps ) ;
runnable_count - - ;
hcl - > processor - > runnable . count = HCL_SMOOI_TO_OOP ( runnable_count ) ;
if ( runnable_count = = 0 ) hcl - > processor - > active = hcl - > nil_process ;
}
2016-10-04 17:56:28 +00:00
2020-10-15 12:57:05 +00:00
if ( new_state = = PROC_STATE_TERMINATED )
{
/* do not chain it to the suspended process list as it's being terminated */
proc - > ps . prev = ( hcl_oop_process_t ) hcl - > _nil ;
proc - > ps . next = ( hcl_oop_process_t ) hcl - > _nil ;
2018-02-08 09:21:18 +00:00
2020-10-15 12:57:05 +00:00
total_count = HCL_OOP_TO_SMOOI ( hcl - > processor - > total_count ) ;
total_count - - ;
hcl - > processor - > total_count = HCL_SMOOI_TO_OOP ( total_count ) ;
}
else
{
/* append to the suspended process list */
HCL_ASSERT ( hcl , new_state = = PROC_STATE_SUSPENDED ) ;
2018-02-08 09:21:18 +00:00
2020-10-15 12:57:05 +00:00
suspended_count = HCL_OOP_TO_SMOOI ( hcl - > processor - > suspended . count ) ;
HCL_APPEND_TO_OOP_LIST ( hcl , & hcl - > processor - > suspended , hcl_oop_process_t , proc , ps ) ;
suspended_count + + ;
hcl - > processor - > suspended . count = HCL_SMOOI_TO_OOP ( suspended_count ) ;
}
proc - > state = HCL_SMOOI_TO_OOP ( new_state ) ;
2016-10-04 17:56:28 +00:00
}
static HCL_INLINE void chain_into_semaphore ( hcl_t * hcl , hcl_oop_process_t proc , hcl_oop_semaphore_t sem )
{
2020-10-15 12:57:05 +00:00
/* append a process to the process list of a semaphore or a semaphore group */
/* a process chained to a semaphore cannot get chained to
* a semaphore again . a process can get chained to a single semaphore
* or a single semaphore group only */
if ( ( hcl_oop_t ) proc - > sem ! = hcl - > _nil ) return ; /* ignore it if it happens anyway. TODO: is it desirable???? */
2016-10-04 17:56:28 +00:00
2018-02-05 10:43:25 +00:00
HCL_ASSERT ( hcl , ( hcl_oop_t ) proc - > sem = = hcl - > _nil ) ;
2020-10-15 12:57:05 +00:00
HCL_ASSERT ( hcl , ( hcl_oop_t ) proc - > sem_wait . prev = = hcl - > _nil ) ;
HCL_ASSERT ( hcl , ( hcl_oop_t ) proc - > sem_wait . next = = hcl - > _nil ) ;
2016-10-04 17:56:28 +00:00
2020-10-15 12:57:05 +00:00
/* a semaphore or a semaphore group must be given for process chaining */
HCL_ASSERT ( hcl , HCL_IS_SEMAPHORE ( hcl , sem ) | | HCL_IS_SEMAPHORE_GROUP ( hcl , sem ) ) ;
2016-10-04 17:56:28 +00:00
2020-10-15 12:57:05 +00:00
/* i assume the head part of the semaphore has the same layout as
* the semaphore group */
HCL_ASSERT ( hcl , HCL_OFFSETOF ( hcl_semaphore_t , waiting ) = =
HCL_OFFSETOF ( hcl_semaphore_group_t , waiting ) ) ;
HCL_APPEND_TO_OOP_LIST ( hcl , & sem - > waiting , hcl_oop_process_t , proc , sem_wait ) ;
proc - > sem = ( hcl_oop_t ) sem ;
2016-10-04 17:56:28 +00:00
}
static HCL_INLINE void unchain_from_semaphore ( hcl_t * hcl , hcl_oop_process_t proc )
{
hcl_oop_semaphore_t sem ;
2018-02-05 10:43:25 +00:00
HCL_ASSERT ( hcl , ( hcl_oop_t ) proc - > sem ! = hcl - > _nil ) ;
2020-10-15 12:57:05 +00:00
HCL_ASSERT ( hcl , HCL_IS_SEMAPHORE ( hcl , proc - > sem ) | | HCL_IS_SEMAPHORE_GROUP ( hcl , proc - > sem ) ) ;
HCL_ASSERT ( hcl , HCL_OFFSETOF ( hcl_semaphore_t , waiting ) = = HCL_OFFSETOF ( hcl_semaphore_group_t , waiting ) ) ;
/* proc->sem may be one of a semaphore or a semaphore group.
* i assume that ' waiting ' is defined to the same position
* in both Semaphore and SemaphoreGroup . there is no need to
* write different code for each class . */
sem = ( hcl_oop_semaphore_t ) proc - > sem ; /* semgrp = (hcl_oop_semaphore_group_t)proc->sem */
HCL_DELETE_FROM_OOP_LIST ( hcl , & sem - > waiting , proc , sem_wait ) ;
proc - > sem_wait . prev = ( hcl_oop_process_t ) hcl - > _nil ;
proc - > sem_wait . next = ( hcl_oop_process_t ) hcl - > _nil ;
proc - > sem = hcl - > _nil ;
}
static void dump_process_info ( hcl_t * hcl , hcl_bitmask_t log_mask )
{
if ( HCL_OOP_TO_SMOOI ( hcl - > processor - > runnable . count ) > 0 )
{
hcl_oop_process_t p ;
HCL_LOG0 ( hcl , log_mask , " > Runnable: " ) ;
p = hcl - > processor - > runnable . first ;
while ( p )
{
HCL_LOG1 ( hcl , log_mask , " %O " , p - > id ) ;
if ( p = = hcl - > processor - > runnable . last ) break ;
p = p - > ps . next ;
}
HCL_LOG0 ( hcl , log_mask , " \n " ) ;
}
if ( HCL_OOP_TO_SMOOI ( hcl - > processor - > suspended . count ) > 0 )
{
hcl_oop_process_t p ;
HCL_LOG0 ( hcl , log_mask , " > Suspended: " ) ;
p = hcl - > processor - > suspended . first ;
while ( p )
{
HCL_LOG1 ( hcl , log_mask , " %O " , p - > id ) ;
if ( p = = hcl - > processor - > suspended . last ) break ;
p = p - > ps . next ;
}
HCL_LOG0 ( hcl , log_mask , " \n " ) ;
}
if ( hcl - > sem_io_wait_count > 0 )
{
hcl_ooi_t io_handle ;
2016-10-04 17:56:28 +00:00
2020-10-15 12:57:05 +00:00
HCL_LOG0 ( hcl , log_mask , " > IO semaphores: " ) ;
for ( io_handle = 0 ; io_handle < hcl - > sem_io_map_capa ; io_handle + + )
{
hcl_ooi_t index ;
index = hcl - > sem_io_map [ io_handle ] ;
if ( index > = 0 )
{
hcl_oop_semaphore_t sem ;
2016-10-04 17:56:28 +00:00
2020-10-15 12:57:05 +00:00
HCL_LOG1 ( hcl , log_mask , " h=%zd " , io_handle ) ;
2016-10-04 17:56:28 +00:00
2020-10-15 12:57:05 +00:00
/* dump process IDs waiting for input signaling */
HCL_LOG0 ( hcl , log_mask , " (wpi " ) ;
sem = hcl - > sem_io_tuple [ index ] . sem [ HCL_SEMAPHORE_IO_TYPE_INPUT ] ;
if ( sem )
{
hcl_oop_process_t wp ; /* waiting process */
for ( wp = sem - > waiting . first ; ( hcl_oop_t ) wp ! = hcl - > _nil ; wp = wp - > sem_wait . next )
{
HCL_LOG1 ( hcl , log_mask , " :%zd " , HCL_OOP_TO_SMOOI ( wp - > id ) ) ;
}
}
else
{
HCL_LOG0 ( hcl , log_mask , " :none " ) ;
}
/* dump process IDs waitingt for output signaling */
HCL_LOG0 ( hcl , log_mask , " ,wpo " ) ;
sem = hcl - > sem_io_tuple [ index ] . sem [ HCL_SEMAPHORE_IO_TYPE_OUTPUT ] ;
if ( sem )
{
hcl_oop_process_t wp ; /* waiting process */
for ( wp = sem - > waiting . first ; ( hcl_oop_t ) wp ! = hcl - > _nil ; wp = wp - > sem_wait . next )
{
HCL_LOG1 ( hcl , log_mask , " :%zd " , HCL_OOP_TO_SMOOI ( wp - > id ) ) ;
}
}
else
{
HCL_LOG0 ( hcl , log_mask , " :none " ) ;
}
HCL_LOG0 ( hcl , log_mask , " ) " ) ;
}
}
HCL_LOG0 ( hcl , log_mask , " \n " ) ;
}
2016-10-04 17:56:28 +00:00
}
static void terminate_process ( hcl_t * hcl , hcl_oop_process_t proc )
{
if ( proc - > state = = HCL_SMOOI_TO_OOP ( PROC_STATE_RUNNING ) | |
proc - > state = = HCL_SMOOI_TO_OOP ( PROC_STATE_RUNNABLE ) )
{
/* RUNNING/RUNNABLE ---> TERMINATED */
# if defined(HCL_DEBUG_VM_PROCESSOR)
2018-02-08 09:21:18 +00:00
HCL_LOG2 ( hcl , HCL_LOG_IC | HCL_LOG_DEBUG , " Processor - process[%zd] %hs->TERMINATED in terminate_process \n " , HCL_OOP_TO_SMOOI ( proc - > id ) , proc_state_to_string ( HCL_OOP_TO_SMOOI ( proc - > state ) ) ) ;
2016-10-04 17:56:28 +00:00
# endif
if ( proc = = hcl - > processor - > active )
{
hcl_oop_process_t nrp ;
2020-10-15 12:57:05 +00:00
nrp = find_next_runnable_process ( hcl ) ;
2016-10-04 17:56:28 +00:00
unchain_from_processor ( hcl , proc , PROC_STATE_TERMINATED ) ;
proc - > sp = HCL_SMOOI_TO_OOP ( - 1 ) ; /* invalidate the process stack */
proc - > current_context = proc - > initial_context ; /* not needed but just in case */
/* a runnable or running process must not be chanined to the
* process list of a semaphore */
2018-02-05 10:43:25 +00:00
HCL_ASSERT ( hcl , ( hcl_oop_t ) proc - > sem = = hcl - > _nil ) ;
2016-10-04 17:56:28 +00:00
if ( nrp = = proc )
{
/* no runnable process after termination */
2018-02-05 10:43:25 +00:00
HCL_ASSERT ( hcl , hcl - > processor - > active = = hcl - > nil_process ) ;
2020-10-15 12:57:05 +00:00
if ( HCL_LOG_ENABLED ( hcl , HCL_LOG_IC | HCL_LOG_DEBUG ) )
{
HCL_LOG5 ( hcl , HCL_LOG_IC | HCL_LOG_DEBUG ,
" No runnable process after termination of process %zd - total %zd runnable/running %zd suspended %zd - sem_io_wait_count %zu \n " ,
HCL_OOP_TO_SMOOI ( proc - > id ) ,
HCL_OOP_TO_SMOOI ( hcl - > processor - > total_count ) ,
HCL_OOP_TO_SMOOI ( hcl - > processor - > runnable . count ) ,
HCL_OOP_TO_SMOOI ( hcl - > processor - > suspended . count ) ,
hcl - > sem_io_wait_count
) ;
dump_process_info ( hcl , HCL_LOG_IC | HCL_LOG_DEBUG ) ;
}
2016-10-04 17:56:28 +00:00
}
else
{
switch_to_process ( hcl , nrp , PROC_STATE_TERMINATED ) ;
}
}
else
{
unchain_from_processor ( hcl , proc , PROC_STATE_TERMINATED ) ;
proc - > sp = HCL_SMOOI_TO_OOP ( - 1 ) ; /* invalidate the process stack */
}
2018-02-08 09:21:18 +00:00
/* when terminated, clear it from the pid table and set the process id to a negative number */
free_pid ( hcl , proc ) ;
2016-10-04 17:56:28 +00:00
}
else if ( proc - > state = = HCL_SMOOI_TO_OOP ( PROC_STATE_SUSPENDED ) )
{
/* SUSPENDED ---> TERMINATED */
# if defined(HCL_DEBUG_VM_PROCESSOR)
2018-02-08 09:21:18 +00:00
HCL_LOG2 ( hcl , HCL_LOG_IC | HCL_LOG_DEBUG , " Processor - process[%zd] %hs->TERMINATED in terminate_process \n " , HCL_OOP_TO_SMOOI ( proc - > id ) , proc_state_to_string ( HCL_OOP_TO_SMOOI ( proc - > state ) ) ) ;
2016-10-04 17:56:28 +00:00
# endif
2020-10-15 12:57:05 +00:00
/*proc->state = HCL_SMOOI_TO_OOP(PROC_STATE_TERMINATED);*/
unchain_from_processor ( hcl , proc , PROC_STATE_TERMINATED ) ;
2016-10-04 17:56:28 +00:00
proc - > sp = HCL_SMOOI_TO_OOP ( - 1 ) ; /* invalidate the proce stack */
if ( ( hcl_oop_t ) proc - > sem ! = hcl - > _nil )
{
2020-10-15 12:57:05 +00:00
if ( HCL_IS_SEMAPHORE_GROUP ( hcl , proc - > sem ) )
{
if ( HCL_OOP_TO_SMOOI ( ( ( hcl_oop_semaphore_group_t ) proc - > sem ) - > sem_io_count ) > 0 )
{
HCL_ASSERT ( hcl , hcl - > sem_io_wait_count > 0 ) ;
hcl - > sem_io_wait_count - - ;
HCL_DEBUG1 ( hcl , " terminate_process(sg) - lowered sem_io_wait_count to %zu \n " , hcl - > sem_io_wait_count ) ;
}
}
else
{
HCL_ASSERT ( hcl , HCL_IS_SEMAPHORE ( hcl , proc - > sem ) ) ;
if ( ( ( hcl_oop_semaphore_t ) proc - > sem ) - > subtype = = HCL_SMOOI_TO_OOP ( HCL_SEMAPHORE_SUBTYPE_IO ) )
{
HCL_ASSERT ( hcl , hcl - > sem_io_wait_count > 0 ) ;
hcl - > sem_io_wait_count - - ;
HCL_DEBUG3 ( hcl , " terminate_process(s) - lowered sem_io_wait_count to %zu for IO semaphore at index %zd handle %zd \n " ,
hcl - > sem_io_wait_count ,
HCL_OOP_TO_SMOOI ( ( ( hcl_oop_semaphore_t ) proc - > sem ) - > u . io . index ) ,
HCL_OOP_TO_SMOOI ( ( ( hcl_oop_semaphore_t ) proc - > sem ) - > u . io . handle )
) ;
}
}
2016-10-04 17:56:28 +00:00
unchain_from_semaphore ( hcl , proc ) ;
}
2018-02-08 09:21:18 +00:00
/* when terminated, clear it from the pid table and set the process id to a negative number */
free_pid ( hcl , proc ) ;
2016-10-04 17:56:28 +00:00
}
2020-10-15 12:57:05 +00:00
#if 0
2016-10-04 17:56:28 +00:00
else if ( proc - > state = = HCL_SMOOI_TO_OOP ( PROC_STATE_WAITING ) )
{
/* WAITING ---> TERMINATED */
/* TODO: */
}
2020-10-15 12:57:05 +00:00
# endif
2016-10-04 17:56:28 +00:00
}
static void resume_process ( hcl_t * hcl , hcl_oop_process_t proc )
{
if ( proc - > state = = HCL_SMOOI_TO_OOP ( PROC_STATE_SUSPENDED ) )
{
2020-10-15 12:57:05 +00:00
/* SUSPENDED ---> RUNNABLE */
/*HCL_ASSERT (hcl, (hcl_oop_t)proc->ps.prev == hcl->_nil);
HCL_ASSERT ( hcl , ( hcl_oop_t ) proc - > ps . next = = hcl - > _nil ) ; */
2016-10-04 17:56:28 +00:00
# if defined(HCL_DEBUG_VM_PROCESSOR)
2018-02-08 09:21:18 +00:00
HCL_LOG2 ( hcl , HCL_LOG_IC | HCL_LOG_DEBUG , " Processor - process[%zd] %hs->RUNNABLE in resume_process \n " , HCL_OOP_TO_SMOOI ( proc - > id ) , proc_state_to_string ( HCL_OOP_TO_SMOOI ( proc - > state ) ) ) ;
2016-10-04 17:56:28 +00:00
# endif
2020-10-15 12:57:05 +00:00
/* don't switch to this process. just change the state to RUNNABLE.
* process switching should be triggerd by the process scheduler . */
chain_into_processor ( hcl , proc , PROC_STATE_RUNNABLE ) ;
/*HCL_STORE_OOP (hcl, &proc->current_context = proc->initial_context);*/
2016-10-04 17:56:28 +00:00
}
#if 0
else if ( proc - > state = = HCL_SMOOI_TO_OOP ( PROC_STATE_RUNNABLE ) )
{
/* RUNNABLE ---> RUNNING */
/* TODO: should i allow this? */
2018-02-05 10:43:25 +00:00
HCL_ASSERT ( hcl , hcl - > processor - > active ! = proc ) ;
2016-10-04 17:56:28 +00:00
switch_to_process ( hcl , proc , PROC_STATE_RUNNABLE ) ;
}
# endif
}
static void suspend_process ( hcl_t * hcl , hcl_oop_process_t proc )
{
if ( proc - > state = = HCL_SMOOI_TO_OOP ( PROC_STATE_RUNNING ) | |
proc - > state = = HCL_SMOOI_TO_OOP ( PROC_STATE_RUNNABLE ) )
{
/* RUNNING/RUNNABLE ---> SUSPENDED */
# if defined(HCL_DEBUG_VM_PROCESSOR)
2020-10-15 12:57:05 +00:00
HCL_LOG2 ( hcl , HCL_LOG_IC | HCL_LOG_DEBUG , " Processor - process[%zd] %hs->SUSPENDED in suspend_process \n " , HCL_OOP_TO_SMOOI ( proc - > id ) , proc_state_to_string ( HCL_OOP_TO_SMOOI ( proc - > state ) ) ) ;
2016-10-04 17:56:28 +00:00
# endif
if ( proc = = hcl - > processor - > active )
{
2020-10-15 12:57:05 +00:00
/* suspend the active process */
2016-10-04 17:56:28 +00:00
hcl_oop_process_t nrp ;
nrp = find_next_runnable_process ( hcl ) ;
if ( nrp = = proc )
{
/* no runnable process after suspension */
sleep_active_process ( hcl , PROC_STATE_RUNNABLE ) ;
unchain_from_processor ( hcl , proc , PROC_STATE_SUSPENDED ) ;
/* the last running/runnable process has been unchained
* from the processor and set to SUSPENDED . the active
* process must be the nil process */
2018-02-05 10:43:25 +00:00
HCL_ASSERT ( hcl , hcl - > processor - > active = = hcl - > nil_process ) ;
2016-10-04 17:56:28 +00:00
}
else
{
2020-10-15 12:57:05 +00:00
/* unchain_from_processor moves the process to the suspended
* process and sets its state to the given state ( SUSPENDED here ) .
* it doesn ' t change the active process . we switch the active
* process with switch_to_process ( ) . setting the state of the
* old active process to SUSPENDED is redundant because it ' s
* done in unchain_from_processor ( ) . the state of the active
* process is somewhat wrong for a short period of time until
* switch_to_process ( ) has changed the active process . */
unchain_from_processor ( hcl , proc , PROC_STATE_SUSPENDED ) ;
2018-02-05 10:43:25 +00:00
HCL_ASSERT ( hcl , hcl - > processor - > active ! = hcl - > nil_process ) ;
2020-10-15 12:57:05 +00:00
switch_to_process ( hcl , nrp , PROC_STATE_SUSPENDED ) ;
2016-10-04 17:56:28 +00:00
}
}
else
{
unchain_from_processor ( hcl , proc , PROC_STATE_SUSPENDED ) ;
}
}
}
static void yield_process ( hcl_t * hcl , hcl_oop_process_t proc )
{
if ( proc - > state = = HCL_SMOOI_TO_OOP ( PROC_STATE_RUNNING ) )
{
/* RUNNING --> RUNNABLE */
hcl_oop_process_t nrp ;
2018-02-05 10:43:25 +00:00
HCL_ASSERT ( hcl , proc = = hcl - > processor - > active ) ;
2016-10-04 17:56:28 +00:00
nrp = find_next_runnable_process ( hcl ) ;
/* if there are more than 1 runnable processes, the next
* runnable process must be different from proc */
if ( nrp ! = proc )
{
# if defined(HCL_DEBUG_VM_PROCESSOR)
2020-10-15 12:57:05 +00:00
HCL_LOG2 ( hcl , HCL_LOG_IC | HCL_LOG_DEBUG , " Processor - process[%zd] %hs->RUNNABLE in yield_process \n " , HCL_OOP_TO_SMOOI ( proc - > id ) , proc_state_to_string ( HCL_OOP_TO_SMOOI ( proc - > state ) ) ) ;
2016-10-04 17:56:28 +00:00
# endif
switch_to_process ( hcl , nrp , PROC_STATE_RUNNABLE ) ;
}
}
}
2020-10-15 12:57:05 +00:00
2016-10-04 17:56:28 +00:00
static int async_signal_semaphore ( hcl_t * hcl , hcl_oop_semaphore_t sem )
{
2018-02-05 10:43:25 +00:00
#if 0
2016-10-04 17:56:28 +00:00
if ( hcl - > sem_list_count > = SEM_LIST_MAX )
{
2018-02-05 10:43:25 +00:00
hcl_seterrnum ( hcl , HCL_ESLFULL ) ;
2016-10-04 17:56:28 +00:00
return - 1 ;
}
if ( hcl - > sem_list_count > = hcl - > sem_list_capa )
{
hcl_oow_t new_capa ;
hcl_oop_semaphore_t * tmp ;
new_capa = hcl - > sem_list_capa + SEM_LIST_INC ; /* TODO: overflow check.. */
2020-10-15 12:57:05 +00:00
tmp = ( hcl_oop_semaphore_t * ) hcl_reallocmem ( hcl , hcl - > sem_list , HCL_SIZEOF ( hcl_oop_semaphore_t ) * new_capa ) ;
if ( HCL_UNLIKELY ( ! tmp ) ) return - 1 ;
2016-10-04 17:56:28 +00:00
hcl - > sem_list = tmp ;
hcl - > sem_list_capa = new_capa ;
}
hcl - > sem_list [ hcl - > sem_list_count ] = sem ;
hcl - > sem_list_count + + ;
2018-02-05 10:43:25 +00:00
# endif
2016-10-04 17:56:28 +00:00
return 0 ;
}
static hcl_oop_process_t signal_semaphore ( hcl_t * hcl , hcl_oop_semaphore_t sem )
{
hcl_oop_process_t proc ;
hcl_ooi_t count ;
2020-10-15 12:57:05 +00:00
hcl_oop_semaphore_group_t sg ;
sg = sem - > group ;
if ( ( hcl_oop_t ) sg ! = hcl - > _nil )
{
/* the semaphore belongs to a semaphore group */
if ( ( hcl_oop_t ) sg - > waiting . first ! = hcl - > _nil )
{
hcl_ooi_t sp ;
/* there is a process waiting on the process group */
proc = sg - > waiting . first ; /* will wake the first process in the waiting list */
unchain_from_semaphore ( hcl , proc ) ;
resume_process ( hcl , proc ) ;
/* [IMPORTANT] RETURN VALUE of SemaphoreGroup's wait.
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* the waiting process has been suspended after a waiting
* primitive function in Semaphore or SemaphoreGroup .
* the top of the stack of the process must hold the temporary
* return value set by await_semaphore ( ) or await_semaphore_group ( ) .
* change the return value forcibly to the actual signaled
* semaphore */
HCL_ASSERT ( hcl , HCL_OOP_TO_SMOOI ( proc - > sp ) < ( hcl_ooi_t ) ( HCL_OBJ_GET_SIZE ( proc ) - HCL_PROCESS_NAMED_INSTVARS ) ) ;
sp = HCL_OOP_TO_SMOOI ( proc - > sp ) ;
proc - > slot [ sp ] = ( hcl_oop_t ) sem ;
/* i should decrement the counter as long as the group being
* signaled contains an IO semaphore */
if ( HCL_OOP_TO_SMOOI ( sg - > sem_io_count ) > 0 )
{
HCL_ASSERT ( hcl , hcl - > sem_io_wait_count > 0 ) ;
hcl - > sem_io_wait_count - - ;
HCL_DEBUG2 ( hcl , " signal_semaphore(sg) - lowered sem_io_wait_count to %zu for handle %zd \n " , hcl - > sem_io_wait_count , HCL_OOP_TO_SMOOI ( sem - > u . io . handle ) ) ;
}
return proc ;
}
}
2016-10-04 17:56:28 +00:00
2020-10-15 12:57:05 +00:00
/* if the semaphore belongs to a semaphore group and the control reaches
* here , no process is waiting on the semaphore group . however , a process
* may still be waiting on the semaphore . If a process waits on a semaphore
* group and another process wait on a semaphore that belongs to the
* semaphore group , the process waiting on the group always wins .
*
* TODO : implement a fair scheduling policy . or do i simply have to disallow individual wait on a semaphore belonging to a group ?
*
* if it doesn ' t belong to a sempahore group , i ' m free from the starvation issue .
*/
if ( ( hcl_oop_t ) sem - > waiting . first = = hcl - > _nil )
2016-10-04 17:56:28 +00:00
{
/* no process is waiting on this semaphore */
2020-10-15 12:57:05 +00:00
2016-10-04 17:56:28 +00:00
count = HCL_OOP_TO_SMOOI ( sem - > count ) ;
count + + ;
sem - > count = HCL_SMOOI_TO_OOP ( count ) ;
2020-10-15 12:57:05 +00:00
HCL_ASSERT ( hcl , count > = 1 ) ;
if ( count = = 1 & & ( hcl_oop_t ) sg ! = hcl - > _nil )
{
/* move the semaphore from the unsignaled list to the signaled list
* if the semaphore count has changed from 0 to 1 in a group */
HCL_DELETE_FROM_OOP_LIST ( hcl , & sg - > sems [ HCL_SEMAPHORE_GROUP_SEMS_UNSIG ] , sem , grm ) ;
HCL_APPEND_TO_OOP_LIST ( hcl , & sg - > sems [ HCL_SEMAPHORE_GROUP_SEMS_SIG ] , hcl_oop_semaphore_t , sem , grm ) ;
}
2016-10-04 17:56:28 +00:00
/* no process has been resumed */
return ( hcl_oop_process_t ) hcl - > _nil ;
}
else
{
2020-10-15 12:57:05 +00:00
proc = sem - > waiting . first ;
2016-10-04 17:56:28 +00:00
2020-12-31 17:48:47 +00:00
/* [NOTE] no GC must occur as 'proc' isn't protected with hcl_pushvolat(). */
2016-10-04 17:56:28 +00:00
2020-10-15 12:57:05 +00:00
/* detach a process from a semaphore's waiting list and
* make it runnable */
2016-10-04 17:56:28 +00:00
unchain_from_semaphore ( hcl , proc ) ;
2020-10-15 12:57:05 +00:00
resume_process ( hcl , proc ) ;
if ( sem - > subtype = = HCL_SMOOI_TO_OOP ( HCL_SEMAPHORE_SUBTYPE_IO ) )
{
HCL_ASSERT ( hcl , hcl - > sem_io_wait_count > 0 ) ;
hcl - > sem_io_wait_count - - ;
HCL_DEBUG3 ( hcl , " signal_semaphore(s) - lowered sem_io_wait_count to %zu for IO semaphore at index %zd handle %zd \n " ,
hcl - > sem_io_wait_count , HCL_OOP_TO_SMOOI ( sem - > u . io . index ) , HCL_OOP_TO_SMOOI ( sem - > u . io . handle ) ) ;
}
2016-10-04 17:56:28 +00:00
2020-10-15 12:57:05 +00:00
/* return the resumed(runnable) process */
2016-10-04 17:56:28 +00:00
return proc ;
}
}
2020-10-15 12:57:05 +00:00
static HCL_INLINE int can_await_semaphore ( hcl_t * hcl , hcl_oop_semaphore_t sem )
{
/* a sempahore that doesn't belong to a gruop can be waited on */
return ( hcl_oop_t ) sem - > group = = hcl - > _nil ;
}
static HCL_INLINE void await_semaphore ( hcl_t * hcl , hcl_oop_semaphore_t sem )
2016-10-04 17:56:28 +00:00
{
hcl_oop_process_t proc ;
hcl_ooi_t count ;
2020-10-15 12:57:05 +00:00
hcl_oop_semaphore_group_t semgrp ;
semgrp = sem - > group ;
/* the caller of this function must ensure that the semaphore doesn't belong to a group */
HCL_ASSERT ( hcl , ( hcl_oop_t ) semgrp = = hcl - > _nil ) ;
2016-10-04 17:56:28 +00:00
count = HCL_OOP_TO_SMOOI ( sem - > count ) ;
if ( count > 0 )
{
2020-10-15 12:57:05 +00:00
/* it's already signaled */
2016-10-04 17:56:28 +00:00
count - - ;
sem - > count = HCL_SMOOI_TO_OOP ( count ) ;
2020-10-15 12:57:05 +00:00
if ( ( hcl_oop_t ) semgrp ! = hcl - > _nil & & count = = 0 )
{
int sems_idx ;
/* TODO: if i disallow individual wait on a semaphore in a group,
* this membership manipulation is redundant */
HCL_DELETE_FROM_OOP_LIST ( hcl , & semgrp - > sems [ HCL_SEMAPHORE_GROUP_SEMS_SIG ] , sem , grm ) ;
sems_idx = count > 0 ? HCL_SEMAPHORE_GROUP_SEMS_SIG : HCL_SEMAPHORE_GROUP_SEMS_UNSIG ;
HCL_APPEND_TO_OOP_LIST ( hcl , & semgrp - > sems [ sems_idx ] , hcl_oop_semaphore_t , sem , grm ) ;
}
2016-10-04 17:56:28 +00:00
}
else
{
/* not signaled. need to wait */
proc = hcl - > processor - > active ;
/* suspend the active process */
suspend_process ( hcl , proc ) ;
/* link the suspended process to the semaphore's process list */
chain_into_semaphore ( hcl , proc , sem ) ;
2020-10-15 12:57:05 +00:00
HCL_ASSERT ( hcl , sem - > waiting . last = = proc ) ;
if ( sem - > subtype = = HCL_SMOOI_TO_OOP ( HCL_SEMAPHORE_SUBTYPE_IO ) )
{
hcl - > sem_io_wait_count + + ;
HCL_DEBUG3 ( hcl , " await_semaphore - raised sem_io_wait_count to %zu for IO semaphore at index %zd handle %zd \n " ,
hcl - > sem_io_wait_count , HCL_OOP_TO_SMOOI ( sem - > u . io . index ) , HCL_OOP_TO_SMOOI ( sem - > u . io . handle ) ) ;
}
2016-10-04 17:56:28 +00:00
2018-02-05 10:43:25 +00:00
HCL_ASSERT ( hcl , hcl - > processor - > active ! = proc ) ;
2016-10-04 17:56:28 +00:00
}
}
2020-10-15 12:57:05 +00:00
static HCL_INLINE hcl_oop_t await_semaphore_group ( hcl_t * hcl , hcl_oop_semaphore_group_t semgrp )
{
/* wait for one of semaphores in the group to be signaled */
hcl_oop_process_t proc ;
hcl_oop_semaphore_t sem ;
HCL_ASSERT ( hcl , HCL_IS_SEMAPHORE_GROUP ( hcl , semgrp ) ) ;
if ( HCL_OOP_TO_SMOOI ( semgrp - > sem_count ) < = 0 )
{
/* cannot wait on a semaphore group that has no member semaphores.
* return failure if waiting on such a semapohre group is attempted */
HCL_ASSERT ( hcl , ( hcl_oop_t ) semgrp - > sems [ HCL_SEMAPHORE_GROUP_SEMS_SIG ] . first = = hcl - > _nil ) ;
HCL_ASSERT ( hcl , ( hcl_oop_t ) semgrp - > sems [ HCL_SEMAPHORE_GROUP_SEMS_SIG ] . last = = hcl - > _nil ) ;
return HCL_ERROR_TO_OOP ( HCL_EINVAL ) ; /* TODO: better error code? */
}
sem = semgrp - > sems [ HCL_SEMAPHORE_GROUP_SEMS_SIG ] . first ;
if ( ( hcl_oop_t ) sem ! = hcl - > _nil )
{
hcl_ooi_t count ;
int sems_idx ;
/* there is a semaphore signaled in the group */
count = HCL_OOP_TO_SMOOI ( sem - > count ) ;
HCL_ASSERT ( hcl , count > 0 ) ;
count - - ;
sem - > count = HCL_SMOOI_TO_OOP ( count ) ;
HCL_DELETE_FROM_OOP_LIST ( hcl , & semgrp - > sems [ HCL_SEMAPHORE_GROUP_SEMS_SIG ] , sem , grm ) ;
sems_idx = count > 0 ? HCL_SEMAPHORE_GROUP_SEMS_SIG : HCL_SEMAPHORE_GROUP_SEMS_UNSIG ;
HCL_APPEND_TO_OOP_LIST ( hcl , & semgrp - > sems [ sems_idx ] , hcl_oop_semaphore_t , sem , grm ) ;
return ( hcl_oop_t ) sem ;
}
/* no semaphores have been signaled. suspend the current process
* until at least one of them is signaled */
proc = hcl - > processor - > active ;
/* suspend the active process */
suspend_process ( hcl , proc ) ;
/* link the suspended process to the semaphore group's process list */
chain_into_semaphore ( hcl , proc , ( hcl_oop_semaphore_t ) semgrp ) ;
HCL_ASSERT ( hcl , semgrp - > waiting . last = = proc ) ;
if ( HCL_OOP_TO_SMOOI ( semgrp - > sem_io_count ) > 0 )
{
/* there might be more than 1 IO semaphores in the group
* but i increment hcl - > sem_io_wait_count by 1 only */
hcl - > sem_io_wait_count + + ;
HCL_DEBUG1 ( hcl , " await_semaphore_group - raised sem_io_wait_count to %zu \n " , hcl - > sem_io_wait_count ) ;
}
/* the current process will get suspended after the caller (mostly a
* a primitive function handler ) is over as it ' s added to a suspened
* process list above */
HCL_ASSERT ( hcl , hcl - > processor - > active ! = proc ) ;
return hcl - > _nil ;
}
2016-10-04 17:56:28 +00:00
static void sift_up_sem_heap ( hcl_t * hcl , hcl_ooi_t index )
{
if ( index > 0 )
{
hcl_ooi_t parent ;
hcl_oop_semaphore_t sem , parsem ;
parent = SEM_HEAP_PARENT ( index ) ;
sem = hcl - > sem_heap [ index ] ;
parsem = hcl - > sem_heap [ parent ] ;
if ( SEM_HEAP_EARLIER_THAN ( hcl , sem , parsem ) )
{
do
{
/* move down the parent to the current position */
2020-10-15 12:57:05 +00:00
parsem - > u . timed . index = HCL_SMOOI_TO_OOP ( index ) ;
2016-10-04 17:56:28 +00:00
hcl - > sem_heap [ index ] = parsem ;
/* traverse up */
index = parent ;
if ( index < = 0 ) break ;
parent = SEM_HEAP_PARENT ( parent ) ;
parsem = hcl - > sem_heap [ parent ] ;
}
while ( SEM_HEAP_EARLIER_THAN ( hcl , sem , parsem ) ) ;
2020-10-15 12:57:05 +00:00
sem - > u . timed . index = HCL_SMOOI_TO_OOP ( index ) ;
2016-10-04 17:56:28 +00:00
hcl - > sem_heap [ index ] = sem ;
}
}
}
static void sift_down_sem_heap ( hcl_t * hcl , hcl_ooi_t index )
{
hcl_ooi_t base = hcl - > sem_heap_count / 2 ;
if ( index < base ) /* at least 1 child is under the 'index' position */
{
hcl_ooi_t left , right , child ;
hcl_oop_semaphore_t sem , chisem ;
sem = hcl - > sem_heap [ index ] ;
do
{
left = SEM_HEAP_LEFT ( index ) ;
right = SEM_HEAP_RIGHT ( index ) ;
2020-10-15 12:57:05 +00:00
if ( right < hcl - > sem_heap_count & & SEM_HEAP_EARLIER_THAN ( hcl , hcl - > sem_heap [ right ] , hcl - > sem_heap [ left ] ) )
2016-10-04 17:56:28 +00:00
{
child = right ;
}
else
{
child = left ;
}
chisem = hcl - > sem_heap [ child ] ;
if ( SEM_HEAP_EARLIER_THAN ( hcl , sem , chisem ) ) break ;
2020-10-15 12:57:05 +00:00
chisem - > u . timed . index = HCL_SMOOI_TO_OOP ( index ) ;
hcl - > sem_heap [ index ] = chisem ;
2016-10-04 17:56:28 +00:00
index = child ;
}
while ( index < base ) ;
2020-10-15 12:57:05 +00:00
sem - > u . timed . index = HCL_SMOOI_TO_OOP ( index ) ;
hcl - > sem_heap [ index ] = sem ;
}
}
static int add_to_sem_heap ( hcl_t * hcl , hcl_oop_semaphore_t sem )
{
hcl_ooi_t index ;
HCL_ASSERT ( hcl , sem - > subtype = = hcl - > _nil ) ;
if ( hcl - > sem_heap_count > = SEM_HEAP_MAX )
{
hcl_seterrbfmt ( hcl , HCL_ESEMFLOOD , " too many semaphores in the semaphore heap " ) ;
return - 1 ;
}
if ( hcl - > sem_heap_count > = hcl - > sem_heap_capa )
{
hcl_oow_t new_capa ;
hcl_oop_semaphore_t * tmp ;
/* no overflow check when calculating the new capacity
* owing to SEM_HEAP_MAX check above */
new_capa = hcl - > sem_heap_capa + SEM_HEAP_INC ;
tmp = ( hcl_oop_semaphore_t * ) hcl_reallocmem ( hcl , hcl - > sem_heap , HCL_SIZEOF ( hcl_oop_semaphore_t ) * new_capa ) ;
if ( HCL_UNLIKELY ( ! tmp ) ) return - 1 ;
hcl - > sem_heap = tmp ;
hcl - > sem_heap_capa = new_capa ;
}
HCL_ASSERT ( hcl , hcl - > sem_heap_count < = HCL_SMOOI_MAX ) ;
index = hcl - > sem_heap_count ;
hcl - > sem_heap [ index ] = sem ;
sem - > u . timed . index = HCL_SMOOI_TO_OOP ( index ) ;
sem - > subtype = HCL_SMOOI_TO_OOP ( HCL_SEMAPHORE_SUBTYPE_TIMED ) ;
hcl - > sem_heap_count + + ;
sift_up_sem_heap ( hcl , index ) ;
return 0 ;
}
static void delete_from_sem_heap ( hcl_t * hcl , hcl_ooi_t index )
{
hcl_oop_semaphore_t sem , lastsem ;
HCL_ASSERT ( hcl , index > = 0 & & index < hcl - > sem_heap_count ) ;
sem = hcl - > sem_heap [ index ] ;
sem - > subtype = hcl - > _nil ;
sem - > u . timed . index = hcl - > _nil ;
sem - > u . timed . ftime_sec = hcl - > _nil ;
sem - > u . timed . ftime_nsec = hcl - > _nil ;
hcl - > sem_heap_count - - ;
if ( /*hcl->sem_heap_count > 0 &&*/ index ! = hcl - > sem_heap_count )
{
/* move the last item to the deletion position */
lastsem = hcl - > sem_heap [ hcl - > sem_heap_count ] ;
lastsem - > u . timed . index = HCL_SMOOI_TO_OOP ( index ) ;
hcl - > sem_heap [ index ] = lastsem ;
if ( SEM_HEAP_EARLIER_THAN ( hcl , lastsem , sem ) )
sift_up_sem_heap ( hcl , index ) ;
else
sift_down_sem_heap ( hcl , index ) ;
}
}
#if 0
/* unused */
static void update_sem_heap ( hcl_t * hcl , hcl_ooi_t index , hcl_oop_semaphore_t newsem )
{
hcl_oop_semaphore_t sem ;
sem = hcl - > sem_heap [ index ] ;
sem - > timed . index = hcl - > _nil ;
newsem - > timed . index = HCL_SMOOI_TO_OOP ( index ) ;
hcl - > sem_heap [ index ] = newsem ;
if ( SEM_HEAP_EARLIER_THAN ( hcl , newsem , sem ) )
sift_up_sem_heap ( hcl , index ) ;
else
sift_down_sem_heap ( hcl , index ) ;
}
# endif
static int add_sem_to_sem_io_tuple ( hcl_t * hcl , hcl_oop_semaphore_t sem , hcl_ooi_t io_handle , hcl_semaphore_io_type_t io_type )
{
hcl_ooi_t index ;
hcl_ooi_t new_mask ;
int n , tuple_added = 0 ;
HCL_ASSERT ( hcl , sem - > subtype = = ( hcl_oop_t ) hcl - > _nil ) ;
HCL_ASSERT ( hcl , sem - > u . io . index = = ( hcl_oop_t ) hcl - > _nil ) ;
/*HCL_ASSERT (hcl, sem->io.handle == (hcl_oop_t)hcl->_nil);
HCL_ASSERT ( hcl , sem - > io . type = = ( hcl_oop_t ) hcl - > _nil ) ; */
if ( io_handle < 0 )
{
hcl_seterrbfmt ( hcl , HCL_EINVAL , " handle %zd out of supported range " , io_handle ) ;
return - 1 ;
}
if ( io_handle > = hcl - > sem_io_map_capa )
{
hcl_oow_t new_capa , i ;
hcl_ooi_t * tmp ;
/* TODO: specify the maximum io_handle supported and check it here instead of just relying on memory allocation success/failure? */
new_capa = HCL_ALIGN_POW2 ( io_handle + 1 , SEM_IO_MAP_ALIGN ) ;
tmp = hcl_reallocmem ( hcl , hcl - > sem_io_map , HCL_SIZEOF ( * tmp ) * new_capa ) ;
if ( ! tmp )
{
const hcl_ooch_t * oldmsg = hcl_backuperrmsg ( hcl ) ;
hcl_seterrbfmt ( hcl , hcl - > errnum , " handle %zd out of supported range - %js " , oldmsg ) ;
return - 1 ;
}
for ( i = hcl - > sem_io_map_capa ; i < new_capa ; i + + ) tmp [ i ] = - 1 ;
hcl - > sem_io_map = tmp ;
hcl - > sem_io_map_capa = new_capa ;
}
index = hcl - > sem_io_map [ io_handle ] ;
if ( index < = - 1 )
{
/* this handle is not in any tuples. add it to a new tuple */
if ( hcl - > sem_io_tuple_count > = SEM_IO_TUPLE_MAX )
{
hcl_seterrbfmt ( hcl , HCL_ESEMFLOOD , " too many IO semaphore tuples " ) ;
return - 1 ;
}
if ( hcl - > sem_io_tuple_count > = hcl - > sem_io_tuple_capa )
{
hcl_oow_t new_capa ;
hcl_sem_tuple_t * tmp ;
/* no overflow check when calculating the new capacity
* owing to SEM_IO_TUPLE_MAX check above */
new_capa = hcl - > sem_io_tuple_capa + SEM_IO_TUPLE_INC ;
tmp = hcl_reallocmem ( hcl , hcl - > sem_io_tuple , HCL_SIZEOF ( hcl_sem_tuple_t ) * new_capa ) ;
if ( ! tmp ) return - 1 ;
hcl - > sem_io_tuple = tmp ;
hcl - > sem_io_tuple_capa = new_capa ;
}
/* this condition must be true assuming SEM_IO_TUPLE_MAX <= HCL_SMOOI_MAX */
HCL_ASSERT ( hcl , hcl - > sem_io_tuple_count < = HCL_SMOOI_MAX ) ;
index = hcl - > sem_io_tuple_count ;
tuple_added = 1 ;
/* safe to initialize before vm_muxadd() because
* hcl - > sem_io_tuple_count has not been incremented .
* still no impact even if it fails . */
hcl - > sem_io_tuple [ index ] . sem [ HCL_SEMAPHORE_IO_TYPE_INPUT ] = HCL_NULL ;
hcl - > sem_io_tuple [ index ] . sem [ HCL_SEMAPHORE_IO_TYPE_OUTPUT ] = HCL_NULL ;
hcl - > sem_io_tuple [ index ] . handle = io_handle ;
hcl - > sem_io_tuple [ index ] . mask = 0 ;
new_mask = ( ( hcl_ooi_t ) 1 < < io_type ) ;
2020-12-31 17:48:47 +00:00
hcl_pushvolat ( hcl , ( hcl_oop_t * ) & sem ) ;
2020-10-15 12:57:05 +00:00
n = hcl - > vmprim . vm_muxadd ( hcl , io_handle , new_mask ) ;
2020-12-31 17:48:47 +00:00
hcl_popvolat ( hcl ) ;
2020-10-15 12:57:05 +00:00
}
else
{
if ( hcl - > sem_io_tuple [ index ] . sem [ io_type ] )
{
hcl_seterrbfmt ( hcl , HCL_EINVAL , " handle %zd already linked with an IO semaphore for %hs " , io_handle , io_type_str [ io_type ] ) ;
return - 1 ;
}
new_mask = hcl - > sem_io_tuple [ index ] . mask ; /* existing mask */
new_mask | = ( ( hcl_ooi_t ) 1 < < io_type ) ;
2020-12-31 17:48:47 +00:00
hcl_pushvolat ( hcl , ( hcl_oop_t * ) & sem ) ;
2020-10-15 12:57:05 +00:00
n = hcl - > vmprim . vm_muxmod ( hcl , io_handle , new_mask ) ;
2020-12-31 17:48:47 +00:00
hcl_popvolat ( hcl ) ;
2020-10-15 12:57:05 +00:00
}
if ( n < = - 1 )
{
HCL_LOG3 ( hcl , HCL_LOG_WARN , " Failed to add IO semaphore at index %zd for %hs on handle %zd \n " , index , io_type_str [ io_type ] , io_handle ) ;
return - 1 ;
}
HCL_LOG3 ( hcl , HCL_LOG_DEBUG , " Added IO semaphore at index %zd for %hs on handle %zd \n " , index , io_type_str [ io_type ] , io_handle ) ;
sem - > subtype = HCL_SMOOI_TO_OOP ( HCL_SEMAPHORE_SUBTYPE_IO ) ;
sem - > u . io . index = HCL_SMOOI_TO_OOP ( index ) ;
sem - > u . io . handle = HCL_SMOOI_TO_OOP ( io_handle ) ;
sem - > u . io . type = HCL_SMOOI_TO_OOP ( ( hcl_ooi_t ) io_type ) ;
hcl - > sem_io_tuple [ index ] . handle = io_handle ;
hcl - > sem_io_tuple [ index ] . mask = new_mask ;
hcl - > sem_io_tuple [ index ] . sem [ io_type ] = sem ;
hcl - > sem_io_count + + ;
if ( tuple_added )
{
hcl - > sem_io_tuple_count + + ;
hcl - > sem_io_map [ io_handle ] = index ;
}
/* update the number of IO semaphores in a group if necessary */
if ( ( hcl_oop_t ) sem - > group ! = hcl - > _nil )
{
hcl_ooi_t count ;
count = HCL_OOP_TO_SMOOI ( sem - > group - > sem_io_count ) ;
count + + ;
sem - > group - > sem_io_count = HCL_SMOOI_TO_OOP ( count ) ;
2016-10-04 17:56:28 +00:00
}
2020-10-15 12:57:05 +00:00
return 0 ;
2016-10-04 17:56:28 +00:00
}
2020-10-15 12:57:05 +00:00
static int delete_sem_from_sem_io_tuple ( hcl_t * hcl , hcl_oop_semaphore_t sem , int force )
2016-10-04 17:56:28 +00:00
{
hcl_ooi_t index ;
2020-10-15 12:57:05 +00:00
hcl_ooi_t new_mask , io_handle , io_type ;
int x ;
2016-10-04 17:56:28 +00:00
2020-10-15 12:57:05 +00:00
HCL_ASSERT ( hcl , sem - > subtype = = HCL_SMOOI_TO_OOP ( HCL_SEMAPHORE_SUBTYPE_IO ) ) ;
HCL_ASSERT ( hcl , HCL_OOP_IS_SMOOI ( sem - > u . io . type ) ) ;
HCL_ASSERT ( hcl , HCL_OOP_IS_SMOOI ( sem - > u . io . index ) ) ;
HCL_ASSERT ( hcl , HCL_OOP_IS_SMOOI ( sem - > u . io . handle ) ) ;
index = HCL_OOP_TO_SMOOI ( sem - > u . io . index ) ;
HCL_ASSERT ( hcl , index > = 0 & & index < hcl - > sem_io_tuple_count ) ;
io_handle = HCL_OOP_TO_SMOOI ( sem - > u . io . handle ) ;
if ( io_handle < 0 | | io_handle > = hcl - > sem_io_map_capa )
2016-10-04 17:56:28 +00:00
{
2020-10-15 12:57:05 +00:00
hcl_seterrbfmt ( hcl , HCL_EINVAL , " handle %zd out of supported range " , io_handle ) ;
2016-10-04 17:56:28 +00:00
return - 1 ;
}
2020-10-15 12:57:05 +00:00
HCL_ASSERT ( hcl , hcl - > sem_io_map [ io_handle ] = = HCL_OOP_TO_SMOOI ( sem - > u . io . index ) ) ;
2016-10-04 17:56:28 +00:00
2020-10-15 12:57:05 +00:00
io_type = HCL_OOP_TO_SMOOI ( sem - > u . io . type ) ;
new_mask = hcl - > sem_io_tuple [ index ] . mask ;
new_mask & = ~ ( ( hcl_ooi_t ) 1 < < io_type ) ; /* this is the new mask after deletion */
2020-12-31 17:48:47 +00:00
hcl_pushvolat ( hcl , ( hcl_oop_t * ) & sem ) ;
2020-10-15 12:57:05 +00:00
x = new_mask ? hcl - > vmprim . vm_muxmod ( hcl , io_handle , new_mask ) :
hcl - > vmprim . vm_muxdel ( hcl , io_handle ) ;
2020-12-31 17:48:47 +00:00
hcl_popvolat ( hcl ) ;
2020-10-15 12:57:05 +00:00
if ( x < = - 1 )
2016-10-04 17:56:28 +00:00
{
2020-10-15 12:57:05 +00:00
HCL_LOG3 ( hcl , HCL_LOG_WARN , " Failed to delete IO semaphore at index %zd handle %zd for %hs \n " , index , io_handle , io_type_str [ io_type ] ) ;
if ( ! force ) return - 1 ;
/* [NOTE]
* this means there could be some issue handling the file handles .
* the file handle might have been closed before reaching here .
* assuming the callback works correctly , it ' s not likely that the
* underlying operating system returns failure for no reason .
* i should inspect the overall vm implementation */
HCL_LOG1 ( hcl , HCL_LOG_ERROR , " Forcibly unmapping the IO semaphored handle %zd as if it's deleted \n " , io_handle ) ;
}
else
{
HCL_LOG3 ( hcl , HCL_LOG_DEBUG , " Deleted IO semaphore at index %zd handle %zd for %hs \n " , index , io_handle , io_type_str [ io_type ] ) ;
}
2016-10-04 17:56:28 +00:00
2020-10-15 12:57:05 +00:00
sem - > subtype = hcl - > _nil ;
sem - > u . io . index = hcl - > _nil ;
sem - > u . io . handle = hcl - > _nil ;
sem - > u . io . type = hcl - > _nil ;
hcl - > sem_io_count - - ;
2016-10-04 17:56:28 +00:00
2020-10-15 12:57:05 +00:00
if ( ( hcl_oop_t ) sem - > group ! = hcl - > _nil )
{
hcl_ooi_t count ;
count = HCL_OOP_TO_SMOOI ( sem - > group - > sem_io_count ) ;
HCL_ASSERT ( hcl , count > 0 ) ;
count - - ;
sem - > group - > sem_io_count = HCL_SMOOI_TO_OOP ( count ) ;
2016-10-04 17:56:28 +00:00
}
2020-10-15 12:57:05 +00:00
if ( new_mask )
{
hcl - > sem_io_tuple [ index ] . mask = new_mask ;
hcl - > sem_io_tuple [ index ] . sem [ io_type ] = HCL_NULL ;
}
else
{
hcl - > sem_io_tuple_count - - ;
2016-10-04 17:56:28 +00:00
2020-10-15 12:57:05 +00:00
if ( /*hcl->sem_io_tuple_count > 0 &&*/ index ! = hcl - > sem_io_tuple_count )
{
/* migrate the last item to the deleted slot to compact the gap */
hcl - > sem_io_tuple [ index ] = hcl - > sem_io_tuple [ hcl - > sem_io_tuple_count ] ;
if ( hcl - > sem_io_tuple [ index ] . sem [ HCL_SEMAPHORE_IO_TYPE_INPUT ] )
hcl - > sem_io_tuple [ index ] . sem [ HCL_SEMAPHORE_IO_TYPE_INPUT ] - > u . io . index = HCL_SMOOI_TO_OOP ( index ) ;
if ( hcl - > sem_io_tuple [ index ] . sem [ HCL_SEMAPHORE_IO_TYPE_OUTPUT ] )
hcl - > sem_io_tuple [ index ] . sem [ HCL_SEMAPHORE_IO_TYPE_OUTPUT ] - > u . io . index = HCL_SMOOI_TO_OOP ( index ) ;
hcl - > sem_io_map [ hcl - > sem_io_tuple [ index ] . handle ] = index ;
HCL_LOG2 ( hcl , HCL_LOG_DEBUG , " Migrated IO semaphore tuple from index %zd to %zd \n " , hcl - > sem_io_tuple_count , index ) ;
}
hcl - > sem_io_map [ io_handle ] = - 1 ;
}
2016-10-04 17:56:28 +00:00
return 0 ;
}
2020-10-15 12:57:05 +00:00
static void _signal_io_semaphore ( hcl_t * hcl , hcl_oop_semaphore_t sem )
2016-10-04 17:56:28 +00:00
{
2020-10-15 12:57:05 +00:00
hcl_oop_process_t proc ;
2016-10-04 17:56:28 +00:00
2020-10-15 12:57:05 +00:00
proc = signal_semaphore ( hcl , sem ) ;
2016-10-04 17:56:28 +00:00
2020-10-15 12:57:05 +00:00
if ( hcl - > processor - > active = = hcl - > nil_process & & ( hcl_oop_t ) proc ! = hcl - > _nil )
2016-10-04 17:56:28 +00:00
{
2020-10-15 12:57:05 +00:00
/* this is the only runnable process.
* switch the process to the running state .
* it uses wake_process ( ) instead of
* switch_to_process ( ) as there is no running
* process at this moment */
HCL_ASSERT ( hcl , proc - > state = = HCL_SMOOI_TO_OOP ( PROC_STATE_RUNNABLE ) ) ;
HCL_ASSERT ( hcl , proc = = hcl - > processor - > runnable . first ) ;
#if 0
wake_process ( hcl , proc ) ; /* switch to running */
hcl - > proc_switched = 1 ;
# else
switch_to_process_from_nil ( hcl , proc ) ;
# endif
2016-10-04 17:56:28 +00:00
}
}
2020-10-15 12:57:05 +00:00
static void signal_io_semaphore ( hcl_t * hcl , hcl_ooi_t io_handle , hcl_ooi_t mask )
2016-10-04 17:56:28 +00:00
{
2020-10-15 12:57:05 +00:00
if ( io_handle > = 0 & & io_handle < hcl - > sem_io_map_capa & & hcl - > sem_io_map [ io_handle ] > = 0 )
{
hcl_oop_semaphore_t insem , outsem ;
hcl_ooi_t sem_io_index ;
2016-10-04 17:56:28 +00:00
2020-10-15 12:57:05 +00:00
sem_io_index = hcl - > sem_io_map [ io_handle ] ;
insem = hcl - > sem_io_tuple [ sem_io_index ] . sem [ HCL_SEMAPHORE_IO_TYPE_INPUT ] ;
outsem = hcl - > sem_io_tuple [ sem_io_index ] . sem [ HCL_SEMAPHORE_IO_TYPE_OUTPUT ] ;
2016-10-04 17:56:28 +00:00
2020-10-15 12:57:05 +00:00
if ( outsem )
{
if ( ( mask & ( HCL_SEMAPHORE_IO_MASK_OUTPUT | HCL_SEMAPHORE_IO_MASK_ERROR ) ) | |
( ! insem & & ( mask & HCL_SEMAPHORE_IO_MASK_HANGUP ) ) )
{
_signal_io_semaphore ( hcl , outsem ) ;
}
}
2016-10-04 17:56:28 +00:00
2020-10-15 12:57:05 +00:00
if ( insem )
{
if ( mask & ( HCL_SEMAPHORE_IO_MASK_INPUT | HCL_SEMAPHORE_IO_MASK_HANGUP | HCL_SEMAPHORE_IO_MASK_ERROR ) )
{
_signal_io_semaphore ( hcl , insem ) ;
}
}
}
2016-10-04 17:56:28 +00:00
else
2020-10-15 12:57:05 +00:00
{
/* you may come across this warning message if the multiplexer returned
* an IO event */
HCL_LOG2 ( hcl , HCL_LOG_WARN , " Warning - semaphore signaling requested on an unmapped handle %zd with mask %#zx \n " , io_handle , mask ) ;
}
}
void hcl_releaseiohandle ( hcl_t * hcl , hcl_ooi_t io_handle )
{
/* TODO: optimize io semapore unmapping. since i'm to close the handle,
* i don ' t need to call delete_sem_from_sem_io_tuple ( ) seperately for input
* and output . */
if ( io_handle < hcl - > sem_io_map_capa )
{
hcl_ooi_t index ;
hcl_oop_semaphore_t sem ;
index = hcl - > sem_io_map [ io_handle ] ;
if ( index > = 0 )
{
HCL_ASSERT ( hcl , hcl - > sem_io_tuple [ index ] . handle = = io_handle ) ;
sem = hcl - > sem_io_tuple [ index ] . sem [ HCL_SEMAPHORE_IO_TYPE_INPUT ] ;
if ( sem )
{
HCL_ASSERT ( hcl , sem - > subtype = = HCL_SMOOI_TO_OOP ( HCL_SEMAPHORE_SUBTYPE_IO ) ) ;
delete_sem_from_sem_io_tuple ( hcl , sem , 0 ) ;
}
}
}
if ( io_handle < hcl - > sem_io_map_capa )
{
hcl_ooi_t index ;
hcl_oop_semaphore_t sem ;
index = hcl - > sem_io_map [ io_handle ] ;
if ( index > = 0 )
{
HCL_ASSERT ( hcl , hcl - > sem_io_tuple [ index ] . handle = = io_handle ) ;
sem = hcl - > sem_io_tuple [ index ] . sem [ HCL_SEMAPHORE_IO_TYPE_OUTPUT ] ;
if ( sem )
{
HCL_ASSERT ( hcl , sem - > subtype = = HCL_SMOOI_TO_OOP ( HCL_SEMAPHORE_SUBTYPE_IO ) ) ;
delete_sem_from_sem_io_tuple ( hcl , sem , 0 ) ;
}
}
}
2016-10-04 17:56:28 +00:00
}
2020-10-15 12:57:05 +00:00
2016-10-06 17:49:47 +00:00
/* ------------------------------------------------------------------------- */
2016-10-04 17:56:28 +00:00
2020-10-10 17:36:33 +00:00
static int __activate_block ( hcl_t * hcl , hcl_oop_block_t rcv_blk , hcl_ooi_t nargs , hcl_oop_context_t * pnewctx )
2016-10-04 17:56:28 +00:00
{
/* prepare a new block context for activation.
* the receiver must be a block context which becomes the base
* for a new block context . */
hcl_oop_context_t blkctx ;
hcl_ooi_t local_ntmprs , i ;
/* TODO: find a better way to support a reentrant block context. */
/* | sum |
* sum : = [ : n | ( n < 2 ) ifTrue : [ 1 ] ifFalse : [ n + ( sum value : ( n - 1 ) ) ] ] .
* ( sum value : 10 ) .
*
* For the code above , sum is a block context and it is sent value : inside
* itself . Let me simply clone a block context to allow reentrancy like this
* while the block context is active
*/
/* the receiver must be a block context */
2020-10-09 07:14:32 +00:00
HCL_ASSERT ( hcl , HCL_IS_BLOCK ( hcl , rcv_blk ) ) ;
2016-10-04 17:56:28 +00:00
2020-10-09 07:14:32 +00:00
if ( HCL_OOP_TO_SMOOI ( rcv_blk - > nargs ) ! = nargs )
2016-10-04 17:56:28 +00:00
{
2016-10-06 17:49:47 +00:00
HCL_LOG3 ( hcl , HCL_LOG_IC | HCL_LOG_ERROR ,
2020-10-09 07:14:32 +00:00
" Error - wrong number of arguments to a block %O - expecting %zd, got %zd \n " ,
rcv_blk , HCL_OOP_TO_SMOOI ( rcv_blk - > nargs ) , nargs ) ;
2018-02-05 10:43:25 +00:00
hcl_seterrnum ( hcl , HCL_ECALLARG ) ;
2016-10-06 17:49:47 +00:00
return - 1 ;
2016-10-04 17:56:28 +00:00
}
2020-10-09 07:14:32 +00:00
local_ntmprs = HCL_OOP_TO_SMOOI ( rcv_blk - > ntmprs ) ;
2018-02-05 10:43:25 +00:00
HCL_ASSERT ( hcl , local_ntmprs > = nargs ) ;
2016-10-04 17:56:28 +00:00
2020-10-09 07:14:32 +00:00
/* create a new block context to clone rcv_blk */
2020-12-31 17:48:47 +00:00
hcl_pushvolat ( hcl , ( hcl_oop_t * ) & rcv_blk ) ;
2020-10-15 12:57:05 +00:00
blkctx = make_context ( hcl , local_ntmprs ) ;
2020-12-31 17:48:47 +00:00
hcl_popvolat ( hcl ) ;
2020-10-13 14:44:00 +00:00
if ( HCL_UNLIKELY ( ! blkctx ) ) return - 1 ;
2016-10-04 17:56:28 +00:00
#if 0
/* shallow-copy the named part including home, origin, etc. */
for ( i = 0 ; i < HCL_CONTEXT_NAMED_INSTVARS ; i + + )
{
2020-10-09 07:14:32 +00:00
( ( hcl_oop_oop_t ) blkctx ) - > slot [ i ] = ( ( hcl_oop_oop_t ) rcv_blk ) - > slot [ i ] ;
2016-10-04 17:56:28 +00:00
}
# else
2020-10-09 07:14:32 +00:00
blkctx - > ip = rcv_blk - > ip ;
blkctx - > ntmprs = rcv_blk - > ntmprs ;
blkctx - > nargs = rcv_blk - > nargs ;
blkctx - > receiver_or_base = ( hcl_oop_t ) rcv_blk ;
blkctx - > home = rcv_blk - > home ;
/* blkctx->origin = rcv_blk->origin; */
blkctx - > origin = rcv_blk - > home - > origin ;
2016-10-04 17:56:28 +00:00
# endif
/* TODO: check the stack size of a block context to see if it's large enough to hold arguments */
/* copy the arguments to the stack */
for ( i = 0 ; i < nargs ; i + + )
{
2016-10-06 18:17:52 +00:00
blkctx - > slot [ i ] = HCL_STACK_GETARG ( hcl , nargs , i ) ;
2016-10-04 17:56:28 +00:00
}
HCL_STACK_POPS ( hcl , nargs + 1 ) ; /* pop arguments and receiver */
blkctx - > sender = hcl - > active_context ;
2020-10-15 12:57:05 +00:00
HCL_ASSERT ( hcl , ( hcl_oop_t ) blkctx - > home ! = hcl - > _nil ) ; /* if not intial context, the home must not be null */
2016-10-04 17:56:28 +00:00
2020-10-10 17:36:33 +00:00
* pnewctx = blkctx ;
2016-10-06 17:49:47 +00:00
return 0 ;
2016-10-04 17:56:28 +00:00
}
2020-10-09 07:14:32 +00:00
static HCL_INLINE int activate_block ( hcl_t * hcl , hcl_ooi_t nargs )
2016-10-04 17:56:28 +00:00
{
int x ;
2020-10-09 07:14:32 +00:00
hcl_oop_block_t rcv ;
2020-10-10 17:36:33 +00:00
hcl_oop_context_t newctx ;
2016-10-04 17:56:28 +00:00
2020-10-09 07:14:32 +00:00
rcv = ( hcl_oop_block_t ) HCL_STACK_GETRCV ( hcl , nargs ) ;
HCL_ASSERT ( hcl , HCL_IS_BLOCK ( hcl , rcv ) ) ;
2016-10-04 17:56:28 +00:00
2020-10-10 17:36:33 +00:00
x = __activate_block ( hcl , rcv , nargs , & newctx ) ;
2020-10-04 18:21:05 +00:00
if ( HCL_UNLIKELY ( x < = - 1 ) ) return - 1 ;
2020-10-10 17:36:33 +00:00
SWITCH_ACTIVE_CONTEXT ( hcl , newctx ) ;
2020-10-04 18:21:05 +00:00
return 0 ;
}
/* ------------------------------------------------------------------------- */
2020-10-10 17:36:33 +00:00
static int __activate_function ( hcl_t * hcl , hcl_oop_function_t rcv_func , hcl_ooi_t nargs , hcl_oop_context_t * pnewctx )
2020-10-04 18:21:05 +00:00
{
/* prepare a new block context for activation.
* the receiver must be a block context which becomes the base
* for a new block context . */
2020-10-10 17:36:33 +00:00
hcl_oop_context_t functx ;
2020-10-04 18:21:05 +00:00
hcl_ooi_t local_ntmprs , i ;
/*
2021-01-26 10:10:18 +00:00
( defun sum ( x )
( if ( < x 2 ) 1
else ( + x ( sum ( - x 1 ) ) ) ) )
( printf " >>>> %d \n " ( sum 10 ) )
2020-10-04 18:21:05 +00:00
*/
2020-10-05 09:37:26 +00:00
/* the receiver must be a function */
2020-10-04 18:21:05 +00:00
HCL_ASSERT ( hcl , HCL_IS_FUNCTION ( hcl , rcv_func ) ) ;
if ( HCL_OOP_TO_SMOOI ( rcv_func - > nargs ) ! = nargs )
{
HCL_LOG3 ( hcl , HCL_LOG_IC | HCL_LOG_ERROR ,
" Error - wrong number of arguments to a function %O - expecting %zd, got %zd \n " ,
rcv_func , HCL_OOP_TO_SMOOI ( rcv_func - > nargs ) , nargs ) ;
hcl_seterrnum ( hcl , HCL_ECALLARG ) ;
return - 1 ;
}
local_ntmprs = HCL_OOP_TO_SMOOI ( rcv_func - > ntmprs ) ;
HCL_ASSERT ( hcl , local_ntmprs > = nargs ) ;
/* create a new block context to clone rcv_func */
2020-12-31 17:48:47 +00:00
hcl_pushvolat ( hcl , ( hcl_oop_t * ) & rcv_func ) ;
2020-10-15 12:57:05 +00:00
functx = make_context ( hcl , local_ntmprs ) ;
2020-12-31 17:48:47 +00:00
hcl_popvolat ( hcl ) ;
2020-10-13 14:44:00 +00:00
if ( HCL_UNLIKELY ( ! functx ) ) return - 1 ;
2020-10-04 18:21:05 +00:00
2020-10-10 17:36:33 +00:00
functx - > ip = HCL_SMOOI_TO_OOP ( 0 ) ;
functx - > ntmprs = rcv_func - > ntmprs ;
functx - > nargs = rcv_func - > nargs ;
functx - > receiver_or_base = ( hcl_oop_t ) rcv_func ;
functx - > home = rcv_func - > home ;
functx - > origin = functx ; /* the origin of the context over a function should be itself */
2020-10-04 18:21:05 +00:00
/* TODO: check the stack size of a block context to see if it's large enough to hold arguments */
/* copy the arguments to the stack */
for ( i = 0 ; i < nargs ; i + + )
{
2020-10-10 17:36:33 +00:00
functx - > slot [ i ] = HCL_STACK_GETARG ( hcl , nargs , i ) ;
2020-10-04 18:21:05 +00:00
}
HCL_STACK_POPS ( hcl , nargs + 1 ) ; /* pop arguments and receiver */
2020-10-10 17:36:33 +00:00
HCL_ASSERT ( hcl , ( hcl_oop_t ) functx - > home ! = hcl - > _nil ) ;
functx - > sender = hcl - > active_context ;
2020-10-04 18:21:05 +00:00
2020-10-10 17:36:33 +00:00
* pnewctx = functx ;
2020-10-04 18:21:05 +00:00
return 0 ;
}
static HCL_INLINE int activate_function ( hcl_t * hcl , hcl_ooi_t nargs )
{
int x ;
2020-10-04 19:34:53 +00:00
hcl_oop_function_t rcv ;
2020-10-10 17:36:33 +00:00
hcl_oop_context_t newctx ;
2020-10-04 18:21:05 +00:00
2020-10-04 19:34:53 +00:00
rcv = ( hcl_oop_function_t ) HCL_STACK_GETRCV ( hcl , nargs ) ;
2020-10-04 18:21:05 +00:00
HCL_ASSERT ( hcl , HCL_IS_FUNCTION ( hcl , rcv ) ) ;
2020-10-10 17:36:33 +00:00
x = __activate_function ( hcl , rcv , nargs , & newctx ) ;
2020-10-04 18:21:05 +00:00
if ( HCL_UNLIKELY ( x < = - 1 ) ) return - 1 ;
2016-10-04 17:56:28 +00:00
2020-10-10 17:36:33 +00:00
SWITCH_ACTIVE_CONTEXT ( hcl , newctx ) ;
2016-10-06 17:49:47 +00:00
return 0 ;
2016-10-04 17:56:28 +00:00
}
2016-10-06 17:49:47 +00:00
/* ------------------------------------------------------------------------- */
static HCL_INLINE int call_primitive ( hcl_t * hcl , hcl_ooi_t nargs )
{
hcl_oop_word_t rcv ;
rcv = ( hcl_oop_word_t ) HCL_STACK_GETRCV ( hcl , nargs ) ;
2018-02-28 05:04:42 +00:00
HCL_ASSERT ( hcl , HCL_IS_PRIM ( hcl , rcv ) ) ;
HCL_ASSERT ( hcl , HCL_OBJ_GET_SIZE ( rcv ) = = 4 ) ;
2016-10-06 17:49:47 +00:00
if ( nargs < rcv - > slot [ 1 ] & & nargs > rcv - > slot [ 2 ] )
{
/* TODO: include a primitive name... */
HCL_LOG3 ( hcl , HCL_LOG_IC | HCL_LOG_ERROR ,
" Error - wrong number of arguments to a primitive - expecting %zd-%zd, got %zd \n " ,
rcv - > slot [ 1 ] , rcv - > slot [ 2 ] , nargs ) ;
2018-02-05 10:43:25 +00:00
hcl_seterrnum ( hcl , HCL_ECALLARG ) ;
2016-10-06 17:49:47 +00:00
return - 1 ;
}
2018-02-28 05:04:42 +00:00
return ( ( hcl_pfimpl_t ) rcv - > slot [ 0 ] ) ( hcl , ( hcl_mod_t * ) rcv - > slot [ 3 ] , nargs ) ;
2016-10-06 17:49:47 +00:00
}
2016-10-04 17:56:28 +00:00
2018-08-02 17:09:32 +00:00
2019-04-17 05:51:36 +00:00
#if 0
/* EXPERIMENTAL CODE INTEGRATING EXTERNAL COMMANDS */
2018-08-02 17:09:32 +00:00
# include <unistd.h>
# include <sys/wait.h>
# include <sys/stat.h>
# include <limits.h>
# include <string.h>
# include <stdlib.h>
# include <errno.h>
2018-08-07 16:05:41 +00:00
# include <stdio.h>
2018-08-02 17:09:32 +00:00
extern char * * environ ;
# define _PATH_DEFPATH " / usr / bin: / bin"
static int is_regular_executable_file_by_me ( const char * path )
{
2018-08-06 10:41:38 +00:00
struct stat st ;
if ( stat ( path , & st ) = = - 1 ) return 0 ;
return S_ISREG ( st . st_mode ) & & access ( path , X_OK ) = = 0 ; //? use eaccess instead??
2018-08-02 17:09:32 +00:00
}
static char * find_exec ( hcl_t * hcl , const char * name )
{
size_t lp , ln ;
char buf [ PATH_MAX ] ;
const char * bp , * path , * p ;
bp = buf ;
/* Get the path we're searching. */
if ( ! ( path = getenv ( " PATH " ) ) ) path = _PATH_DEFPATH ;
ln = strlen ( name ) ;
do
{
/* Find the end of this path element. */
for ( p = path ; * path ! = 0 & & * path ! = ' : ' ; path + + ) ;
/*
* It ' s a SHELL path - - double , leading and trailing colons
* mean the current directory .
*/
if ( p = = path )
{
p = " . " ;
lp = 1 ;
}
else
{
lp = path - p ;
}
/*
* If the path is too long complain . This is a possible
* security issue ; given a way to make the path too long
* the user may execute the wrong program .
*/
if ( lp + ln + 2 > sizeof ( buf ) ) continue ;
memcpy ( buf , p , lp ) ;
buf [ lp ] = ' / ' ;
memcpy ( buf + lp + 1 , name , ln ) ;
buf [ lp + ln + 1 ] = ' \0 ' ;
if ( is_regular_executable_file_by_me ( bp ) ) return strdup ( bp ) ;
}
while ( * path + + = = ' : ' ) ; /* Otherwise, *path was NUL */
done :
hcl_seterrbfmt ( hcl , HCL_ENOENT , " callable %hs not found " , name ) ;
return HCL_NULL ;
}
static HCL_INLINE int exec_syscmd ( hcl_t * hcl , hcl_ooi_t nargs )
{
hcl_oop_word_t rcv ;
2018-08-06 10:41:38 +00:00
hcl_bch_t * cmd = HCL_NULL ;
hcl_bch_t * xcmd = HCL_NULL ;
2018-08-02 17:09:32 +00:00
rcv = ( hcl_oop_word_t ) HCL_STACK_GETRCV ( hcl , nargs ) ;
/*HCL_ASSERT (hcl, HCL_IS_STRING(hcl, rcv) || HCL_IS_SYMBOL(hcl, rcv));*/
HCL_ASSERT ( hcl , HCL_OBJ_IS_CHAR_POINTER ( rcv ) ) ;
if ( HCL_OBJ_GET_SIZE ( rcv ) = = 0 | | hcl_count_oocstr ( HCL_OBJ_GET_CHAR_SLOT ( rcv ) ) ! = HCL_OBJ_GET_SIZE ( rcv ) )
{
/* '\0' is contained in the middle */
hcl_seterrbfmt ( hcl , HCL_EINVAL , " invalid callable %O " , rcv ) ;
2018-08-06 10:41:38 +00:00
goto oops ;
2018-08-02 17:09:32 +00:00
}
cmd = hcl_dupootobcstr ( hcl , HCL_OBJ_GET_CHAR_SLOT ( rcv ) , HCL_NULL ) ;
2018-08-06 10:41:38 +00:00
if ( ! cmd ) goto oops ;
2018-08-02 17:09:32 +00:00
if ( hcl_find_bchar_in_bcstr ( cmd , ' / ' ) )
{
if ( ! is_regular_executable_file_by_me ( cmd ) )
{
hcl_seterrbfmt ( hcl , HCL_ECALL , " cannot execute %O " , rcv ) ;
2018-08-06 10:41:38 +00:00
goto oops ;
2018-08-02 17:09:32 +00:00
}
xcmd = cmd ;
}
else
{
xcmd = find_exec ( hcl , cmd ) ;
2018-08-06 10:41:38 +00:00
if ( ! xcmd ) goto oops ;
2018-08-02 17:09:32 +00:00
}
{ /* TODO: make it a callback ... */
pid_t pid ;
int status ;
pid = fork ( ) ;
2018-08-06 10:41:38 +00:00
if ( pid = = - 1 ) goto oops ;
2018-08-02 17:09:32 +00:00
/* TODO: set a new process group / session leader??? */
if ( pid = = 0 )
{
2018-08-06 10:41:38 +00:00
hcl_bch_t * * argv ;
hcl_ooi_t i ;
2018-08-02 17:09:32 +00:00
2018-08-06 10:41:38 +00:00
/* TODO: close file descriptors??? */
argv = ( hcl_bch_t * * ) hcl_allocmem ( hcl , ( nargs + 2 ) * HCL_SIZEOF ( * argv ) ) ;
if ( argv )
{
argv [ 0 ] = cmd ;
2018-08-04 00:59:35 +00:00
HCL_DEBUG1 ( hcl , " NARG %d \n " , ( int ) nargs ) ;
2018-08-06 10:41:38 +00:00
for ( i = 0 ; i < nargs ; )
{
hcl_oop_t ta = HCL_STACK_GETARG ( hcl , nargs , i ) ;
2018-08-02 17:09:32 +00:00
/* TODO: check if an argument is a string or a symbol */
2018-08-07 11:04:38 +00:00
if ( HCL_OOP_IS_SMOOI ( ta ) )
{
/* TODO: rewrite this part */
hcl_bch_t tmp [ 64 ] ;
snprintf ( tmp , sizeof ( tmp ) , " %ld " , ( long int ) HCL_OOP_TO_SMOOI ( ta ) ) ;
argv [ + + i ] = hcl_dupbchars ( hcl , tmp , strlen ( tmp ) ) ;
}
else
{
argv [ + + i ] = hcl_dupootobchars ( hcl , HCL_OBJ_GET_CHAR_SLOT ( ta ) , HCL_OBJ_GET_SIZE ( ta ) , HCL_NULL ) ;
}
2020-10-15 12:57:05 +00:00
/*HCL_DEBUG2 (hcl, "ARG %d -> %hs\n", (int)i - 1, argv[i]);*/
2018-08-02 17:09:32 +00:00
}
2018-08-06 10:41:38 +00:00
argv [ nargs + 1 ] = HCL_NULL ;
execvp ( xcmd , argv ) ;
}
if ( cmd ) hcl_freemem ( hcl , cmd ) ;
if ( xcmd & & xcmd ! = cmd ) hcl_freemem ( hcl , xcmd ) ;
_exit ( 255 ) ;
2018-08-02 17:09:32 +00:00
}
2018-08-06 10:41:38 +00:00
waitpid ( pid , & status , 0 ) ; /* TOOD: enhance this waiting */
2018-08-02 17:09:32 +00:00
HCL_STACK_SETRET ( hcl , nargs , HCL_SMOOI_TO_OOP ( WEXITSTATUS ( status ) ) ) ;
}
hcl_freemem ( hcl , cmd ) ;
if ( xcmd ! = cmd ) hcl_freemem ( hcl , xcmd ) ;
return 0 ;
2018-08-06 10:41:38 +00:00
oops :
if ( cmd ) hcl_freemem ( hcl , cmd ) ;
if ( xcmd & & xcmd ! = cmd ) hcl_freemem ( hcl , xcmd ) ;
return - 1 ;
2018-08-02 17:09:32 +00:00
}
2019-04-17 05:51:36 +00:00
# endif
2016-10-06 17:49:47 +00:00
/* ------------------------------------------------------------------------- */
2016-10-04 17:56:28 +00:00
static hcl_oop_process_t start_initial_process ( hcl_t * hcl , hcl_oop_context_t ctx )
{
hcl_oop_process_t proc ;
/* there must be no active process when this function is called */
2020-10-15 12:57:05 +00:00
HCL_ASSERT ( hcl , hcl - > processor - > runnable . count = = HCL_SMOOI_TO_OOP ( 0 ) ) ;
2018-02-05 10:43:25 +00:00
HCL_ASSERT ( hcl , hcl - > processor - > active = = hcl - > nil_process ) ;
2016-10-04 17:56:28 +00:00
2020-10-04 18:21:05 +00:00
proc = make_process ( hcl , ctx ) ;
if ( HCL_UNLIKELY ( ! proc ) ) return HCL_NULL ;
2016-10-04 17:56:28 +00:00
2018-02-08 09:21:18 +00:00
/* skip RUNNABLE and go to RUNNING */
2020-10-15 12:57:05 +00:00
chain_into_processor ( hcl , proc , PROC_STATE_RUNNING ) ;
2016-10-04 17:56:28 +00:00
hcl - > processor - > active = proc ;
/* do something that resume_process() would do with less overhead */
2018-02-05 10:43:25 +00:00
HCL_ASSERT ( hcl , ( hcl_oop_t ) proc - > current_context ! = hcl - > _nil ) ;
HCL_ASSERT ( hcl , proc - > current_context = = proc - > initial_context ) ;
2016-10-04 17:56:28 +00:00
SWITCH_ACTIVE_CONTEXT ( hcl , proc - > current_context ) ;
return proc ;
}
2018-02-08 10:33:59 +00:00
static int start_initial_process_and_context ( hcl_t * hcl , hcl_ooi_t initial_ip )
2016-10-04 17:56:28 +00:00
{
hcl_oop_context_t ctx ;
hcl_oop_process_t proc ;
2020-10-04 19:34:53 +00:00
/* create the initial context over the initial function */
2020-10-15 12:57:05 +00:00
ctx = make_context ( hcl , 0 ) ; /* no temporary variables */
2020-10-13 14:44:00 +00:00
if ( HCL_UNLIKELY ( ! ctx ) ) return - 1 ;
2016-10-04 17:56:28 +00:00
2018-02-08 10:33:59 +00:00
hcl - > ip = initial_ip ;
2016-10-04 17:56:28 +00:00
hcl - > sp = - 1 ;
2020-10-04 18:21:05 +00:00
ctx - > ip = HCL_SMOOI_TO_OOP ( initial_ip ) ;
ctx - > nargs = HCL_SMOOI_TO_OOP ( 0 ) ;
2016-10-04 17:56:28 +00:00
ctx - > ntmprs = HCL_SMOOI_TO_OOP ( 0 ) ;
2020-10-10 17:36:33 +00:00
ctx - > origin = ctx ; /* the origin of the initial context is itself as this is created over the initial function */
2020-10-04 18:21:05 +00:00
ctx - > home = hcl - > initial_function - > home ; /* this should be nil */
2020-10-04 19:34:53 +00:00
ctx - > sender = ( hcl_oop_context_t ) hcl - > _nil ;
ctx - > receiver_or_base = hcl - > initial_function ;
HCL_ASSERT ( hcl , ( hcl_oop_t ) ctx - > home = = hcl - > _nil ) ;
2016-10-04 17:56:28 +00:00
/* [NOTE]
2020-10-04 19:34:53 +00:00
* the sender field of the initial context is nil .
2016-10-04 17:56:28 +00:00
* especially , the fact that the sender field is nil is used by
* the main execution loop for breaking out of the loop */
2018-02-05 10:43:25 +00:00
HCL_ASSERT ( hcl , hcl - > active_context = = HCL_NULL ) ;
2016-10-04 17:56:28 +00:00
/* hcl_gc() uses hcl->processor when hcl->active_context
* is not NULL . at this poinst , hcl - > processor should point to
* an instance of ProcessScheduler . */
2018-02-05 10:43:25 +00:00
HCL_ASSERT ( hcl , ( hcl_oop_t ) hcl - > processor ! = hcl - > _nil ) ;
2020-10-15 12:57:05 +00:00
HCL_ASSERT ( hcl , hcl - > processor - > runnable . count = = HCL_SMOOI_TO_OOP ( 0 ) ) ;
2016-10-04 17:56:28 +00:00
/* start_initial_process() calls the SWITCH_ACTIVE_CONTEXT() macro.
* the macro assumes a non - null value in hcl - > active_context .
* let ' s force set active_context to ctx directly . */
hcl - > active_context = ctx ;
2020-12-31 17:48:47 +00:00
hcl_pushvolat ( hcl , ( hcl_oop_t * ) & ctx ) ;
2020-10-04 18:21:05 +00:00
proc = start_initial_process ( hcl , ctx ) ;
2020-12-31 17:48:47 +00:00
hcl_popvolat ( hcl ) ;
2020-10-04 18:21:05 +00:00
if ( HCL_UNLIKELY ( ! proc ) ) return - 1 ;
2016-10-04 17:56:28 +00:00
2020-10-13 14:44:00 +00:00
/* the stack must contain nothing as it should emulate the expresssion - (the-initial-function).
* for a normal function call , the function object and arguments are pushed by the caller .
* __activate_function ( ) creates a new context and pops the function object and arguments off the stack .
* at this point , it should be as if the pop - off has been completed .
* because this is the very beginning , nothing should exist in the stack */
HCL_ASSERT ( hcl , hcl - > sp = = - 1 ) ;
2020-10-13 17:20:01 +00:00
HCL_ASSERT ( hcl , hcl - > sp = = HCL_OOP_TO_SMOOI ( proc - > sp ) ) ;
2016-10-04 17:56:28 +00:00
2020-10-04 18:21:05 +00:00
HCL_ASSERT ( hcl , proc = = hcl - > processor - > active ) ;
hcl - > initial_context = proc - > initial_context ;
2020-10-04 19:34:53 +00:00
HCL_ASSERT ( hcl , hcl - > initial_context = = hcl - > active_context ) ;
2020-10-04 19:07:21 +00:00
2020-10-04 19:34:53 +00:00
return 0 ;
2016-10-04 17:56:28 +00:00
}
2020-10-10 17:36:33 +00:00
/* ------------------------------------------------------------------------- */
2020-10-15 12:57:05 +00:00
static HCL_INLINE int switch_process_if_needed ( hcl_t * hcl )
{
if ( hcl - > sem_heap_count > 0 )
{
/* handle timed semaphores */
hcl_ntime_t ft , now ;
vm_gettime ( hcl , & now ) ;
do
{
HCL_ASSERT ( hcl , hcl - > sem_heap [ 0 ] - > subtype = = HCL_SMOOI_TO_OOP ( HCL_SEMAPHORE_SUBTYPE_TIMED ) ) ;
HCL_ASSERT ( hcl , HCL_OOP_IS_SMOOI ( hcl - > sem_heap [ 0 ] - > u . timed . ftime_sec ) ) ;
HCL_ASSERT ( hcl , HCL_OOP_IS_SMOOI ( hcl - > sem_heap [ 0 ] - > u . timed . ftime_nsec ) ) ;
HCL_INIT_NTIME ( & ft ,
HCL_OOP_TO_SMOOI ( hcl - > sem_heap [ 0 ] - > u . timed . ftime_sec ) ,
HCL_OOP_TO_SMOOI ( hcl - > sem_heap [ 0 ] - > u . timed . ftime_nsec )
) ;
if ( HCL_CMP_NTIME ( & ft , ( hcl_ntime_t * ) & now ) < = 0 )
{
hcl_oop_process_t proc ;
signal_timed :
/* waited long enough. signal the semaphore */
proc = signal_semaphore ( hcl , hcl - > sem_heap [ 0 ] ) ;
/* [NOTE] no hcl_pushvolat() on proc. no GC must occur
* in the following line until it ' s used for
* wake_process ( ) below . */
delete_from_sem_heap ( hcl , 0 ) ; /* hcl->sem_heap_count is decremented in delete_from_sem_heap() */
/* if no process is waiting on the semaphore,
* signal_semaphore ( ) returns hcl - > _nil . */
if ( hcl - > processor - > active = = hcl - > nil_process & & ( hcl_oop_t ) proc ! = hcl - > _nil )
{
/* this is the only runnable process.
* switch the process to the running state .
* it uses wake_process ( ) instead of
* switch_to_process ( ) as there is no running
* process at this moment */
# if defined(HCL_DEBUG_VM_PROCESSOR) && (HCL_DEBUG_VM_PROCESSOR >= 2)
HCL_LOG2 ( hcl , HCL_LOG_IC | HCL_LOG_DEBUG , " Processor - switching to a process[%zd] while no process is active - total runnables %zd \n " , HCL_OOP_TO_SMOOI ( proc - > id ) , HCL_OOP_TO_SMOOI ( hcl - > processor - > runnable . count ) ) ;
# endif
HCL_ASSERT ( hcl , proc - > state = = HCL_SMOOI_TO_OOP ( PROC_STATE_RUNNABLE ) ) ;
HCL_ASSERT ( hcl , proc = = hcl - > processor - > runnable . last ) ; /* resume_process() appends to the runnable list */
#if 0
wake_process ( hcl , proc ) ; /* switch to running */
hcl - > proc_switched = 1 ;
# else
switch_to_process_from_nil ( hcl , proc ) ;
# endif
}
}
else if ( hcl - > processor - > active = = hcl - > nil_process )
{
/* no running process. before firing time. */
HCL_SUB_NTIME ( & ft , & ft , ( hcl_ntime_t * ) & now ) ;
if ( hcl - > sem_io_wait_count > 0 )
{
/* no running process but io semaphore being waited on */
vm_muxwait ( hcl , & ft ) ;
/* exit early if a process has been woken up.
* the break in the else part further down will get hit
* eventually even if the following line doesn ' t exist .
* having the following line causes to skip firing the
* timed semaphore that would expire between now and the
* moment the next inspection occurs . */
if ( hcl - > processor - > active ! = hcl - > nil_process ) goto switch_to_next ;
}
else
{
int halting ;
# if defined(ENABLE_GCFIN)
/* no running process, no io semaphore */
if ( ( hcl_oop_t ) hcl - > sem_gcfin ! = hcl - > _nil & & hcl - > sem_gcfin_sigreq ) goto signal_sem_gcfin ;
# endif
halting = vm_sleep ( hcl , & ft ) ;
if ( halting )
{
vm_gettime ( hcl , & now ) ;
goto signal_timed ;
}
}
vm_gettime ( hcl , & now ) ;
}
else
{
/* there is a running process. go on */
break ;
}
}
while ( hcl - > sem_heap_count > 0 & & ! hcl - > abort_req ) ;
}
if ( hcl - > sem_io_wait_count > 0 )
{
if ( hcl - > processor - > active = = hcl - > nil_process )
{
hcl_ntime_t ft ;
HCL_ASSERT ( hcl , hcl - > processor - > runnable . count = = HCL_SMOOI_TO_OOP ( 0 ) ) ;
# if defined(ENABLE_GCFIN)
/* no runnable process while there is an io semaphore being waited for */
if ( ( hcl_oop_t ) hcl - > sem_gcfin ! = hcl - > _nil & & hcl - > sem_gcfin_sigreq ) goto signal_sem_gcfin ;
# endif
if ( hcl - > processor - > suspended . count = = HCL_SMOOI_TO_OOP ( 0 ) )
{
/* no suspended process. the program is buggy or is probably being
* terminated forcibly .
* the default signal handler may lead to this situation . */
hcl - > abort_req = 1 ;
}
else
{
do
{
HCL_INIT_NTIME ( & ft , 3 , 0 ) ; /* TODO: use a configured time */
vm_muxwait ( hcl , & ft ) ;
}
while ( hcl - > processor - > active = = hcl - > nil_process & & ! hcl - > abort_req ) ;
}
}
else
{
/* well, there is a process waiting on one or more semaphores while
* there are other normal processes to run . check IO activities
* before proceeding to handle normal process scheduling */
/* [NOTE] the check with the multiplexer may happen too frequently
* because this is called everytime process switching is requested .
* the actual callback implementation should try to avoid invoking
* actual system calls too frequently for less overhead . */
vm_muxwait ( hcl , HCL_NULL ) ;
}
}
# if defined(ENABLE_GCFIN)
if ( ( hcl_oop_t ) hcl - > sem_gcfin ! = hcl - > _nil )
{
hcl_oop_process_t proc ;
if ( hcl - > sem_gcfin_sigreq )
{
signal_sem_gcfin :
HCL_LOG0 ( hcl , HCL_LOG_IC | HCL_LOG_DEBUG , " Signaled GCFIN semaphore \n " ) ;
proc = signal_semaphore ( hcl , hcl - > sem_gcfin ) ;
if ( hcl - > processor - > active = = hcl - > nil_process & & ( hcl_oop_t ) proc ! = hcl - > _nil )
{
HCL_ASSERT ( hcl , proc - > state = = HCL_SMOOI_TO_OOP ( PROC_STATE_RUNNABLE ) ) ;
HCL_ASSERT ( hcl , proc = = hcl - > processor - > runnable . first ) ;
switch_to_process_from_nil ( hcl , proc ) ;
}
hcl - > sem_gcfin_sigreq = 0 ;
}
else
{
/* the gcfin semaphore signalling is not requested and there are
* no runnable processes nor no waiting semaphores . if there is
* process waiting on the gcfin semaphore , i will just schedule
* it to run by calling signal_semaphore ( ) on hcl - > sem_gcfin .
*/
/* TODO: check if this is the best implementation practice */
if ( hcl - > processor - > active = = hcl - > nil_process )
{
/* there is no active process. in most cases, the only process left
* should be the gc finalizer process started in the System > > startup .
* if there are other suspended processes at this point , the processes
* are not likely to run again .
*
* imagine the following single line program that creates a process
* but never start it .
*
* method ( # class ) main { | p | p : = [ ] newProcess . }
*
* the gc finalizer process and the process assigned to p exist .
* when the code reaches here , the ' p ' process still is alive
* despite no active process nor no process waiting on timers
* and semaphores . so when the entire program terminates , there
* might still be some suspended processes that are not possible
* to schedule .
*/
HCL_LOG4 ( hcl , HCL_LOG_IC | HCL_LOG_DEBUG ,
" Signaled GCFIN semaphore without gcfin signal request - total %zd runnable/running %zd suspended %zd - sem_io_wait_count %zu \n " ,
HCL_OOP_TO_SMOOI ( hcl - > processor - > total_count ) ,
HCL_OOP_TO_SMOOI ( hcl - > processor - > runnable . count ) ,
HCL_OOP_TO_SMOOI ( hcl - > processor - > suspended . count ) ,
hcl - > sem_io_wait_count ) ;
proc = signal_semaphore ( hcl , hcl - > sem_gcfin ) ;
if ( ( hcl_oop_t ) proc ! = hcl - > _nil )
{
HCL_ASSERT ( hcl , proc - > state = = HCL_SMOOI_TO_OOP ( PROC_STATE_RUNNABLE ) ) ;
HCL_ASSERT ( hcl , proc = = hcl - > processor - > runnable . first ) ;
hcl - > _system - > cvar [ 2 ] = hcl - > _true ; /* set gcfin_should_exit in System to true. if the postion of the class variable changes, the index must get changed, too. */
switch_to_process_from_nil ( hcl , proc ) ; /* sechedule the gc finalizer process */
}
}
}
}
# endif
#if 0
while ( hcl - > sem_list_count > 0 )
{
/* handle async signals */
- - hcl - > sem_list_count ;
signal_semaphore ( hcl , hcl - > sem_list [ hcl - > sem_list_count ] ) ;
if ( hcl - > processor - > active = = hcl - > nil_process )
{ suspended process
}
}
/*
if ( semaphore heap has pending request )
{
signal them . . .
} */
# endif
if ( hcl - > processor - > active = = hcl - > nil_process )
{
/* no more waiting semaphore and no more process */
HCL_ASSERT ( hcl , hcl - > processor - > runnable . count = HCL_SMOOI_TO_OOP ( 0 ) ) ;
HCL_LOG0 ( hcl , HCL_LOG_IC | HCL_LOG_DEBUG , " No more runnable process \n " ) ;
2020-12-31 19:03:37 +00:00
2020-10-15 12:57:05 +00:00
if ( HCL_OOP_TO_SMOOI ( hcl - > processor - > suspended . count ) > 0 )
{
/* there exist suspended processes while no processes are runnable.
* most likely , the running program contains process / semaphore related bugs */
HCL_LOG1 ( hcl , HCL_LOG_IC | HCL_LOG_WARN ,
" %zd suspended process(es) found - check your program \n " ,
HCL_OOP_TO_SMOOI ( hcl - > processor - > suspended . count ) ) ;
}
return 0 ;
}
switch_to_next :
/* TODO: implement different process switching scheme - time-slice or clock based??? */
# if defined(HCL_EXTERNAL_PROCESS_SWITCH)
if ( hcl - > switch_proc )
{
# endif
if ( ! hcl - > proc_switched )
{
switch_to_next_runnable_process ( hcl ) ;
hcl - > proc_switched = 0 ;
}
# if defined(HCL_EXTERNAL_PROCESS_SWITCH)
hcl - > switch_proc = 0 ;
}
else hcl - > proc_switched = 0 ;
# endif
return 1 ;
}
2021-02-01 13:20:46 +00:00
2020-10-15 12:57:05 +00:00
/* ------------------------------------------------------------------------- */
2020-10-10 17:36:33 +00:00
static HCL_INLINE int do_return ( hcl_t * hcl , hcl_oop_t return_value )
{
2020-10-13 14:44:00 +00:00
/* if (hcl->active_context == hcl->processor->active->initial_context) // read the interactive mode note below... */
2020-12-31 19:03:37 +00:00
if ( ( hcl_oop_t ) hcl - > active_context - > home = = hcl - > _nil )
2020-10-10 17:36:33 +00:00
{
2020-10-13 14:44:00 +00:00
/* returning from the intial context.
* ( return - from - home 999 ) */
HCL_ASSERT ( hcl , ( hcl_oop_t ) hcl - > active_context - > sender = = hcl - > _nil ) ;
hcl - > active_context - > ip = HCL_SMOOI_TO_OOP ( - 1 ) ; /* mark the active context dead */
2020-10-10 17:36:33 +00:00
2020-10-13 14:44:00 +00:00
if ( hcl - > sp > = 0 )
{
2020-10-13 17:20:01 +00:00
/* return-from-home has been called from where it shouldn't be. for instance,
2020-10-13 14:44:00 +00:00
* ( printf " xxx %d \n " ( return - from - home 999 ) )
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* ( if ( > 19 ( return - from - home 20 ) ) 30 ) */
HCL_LOG0 ( hcl , HCL_LOG_IC | HCL_LOG_WARN , " Warning - stack not empty on return-from-home \n " ) ; /* TODO: include line number and file name */
}
2020-10-10 17:36:33 +00:00
2020-10-13 14:44:00 +00:00
terminate_process ( hcl , hcl - > processor - > active ) ;
}
/*else if (hcl->active_context->home == hcl->processor->active->initial_context) // read the interactive mode note below...*/
2020-12-31 19:03:37 +00:00
else if ( ( hcl_oop_t ) hcl - > active_context - > home - > home = = hcl - > _nil )
2020-10-10 17:36:33 +00:00
{
2020-10-13 14:44:00 +00:00
/* non-local return out of the initial context
* ( defun y ( x ) ( return - from - home ( * x x ) ) )
* ( y 999 ) */
/* [NOTE]
* in the interactive mode , a new initial context / function / process is created
* for each expression ( as implemented bin / main . c )
* hcl - > active_context may be the intial context of the previous expression .
* ( defun y ( x ) ( return - from - home ( * x x ) ) ) < - - initial context
* ( y 999 ) < - another initial context
* when y is called from the second initial context , the home context to return
* from the the first initial context . comparing hcl - > active_context - > home againt
* hcl - > initial_context doesn ' t return true in this case .
*/
HCL_ASSERT ( hcl , ( hcl_oop_t ) hcl - > active_context - > home - > sender = = hcl - > _nil ) ;
hcl - > active_context - > home - > ip = HCL_SMOOI_TO_OOP ( - 1 ) ; /* mark that this context has returned */
if ( hcl - > sp > = 0 )
{
/* return-from-home has been called from where it shouldn't be
* ( defun y ( x ) ( return - from - home ( * x x ) ) )
* ( printf " xxx %d \n " ( y 999 ) ) */
HCL_LOG0 ( hcl , HCL_LOG_IC | HCL_LOG_WARN , " Warning - stack not empty on non-local return-from-home \n " ) ; /* TODO: include line number and file name */
}
2020-10-10 17:36:33 +00:00
terminate_process ( hcl , hcl - > processor - > active ) ;
}
else
{
2020-10-13 14:44:00 +00:00
/*
( defun f ( x )
( defun y ( x ) ( return - from - home ( * x x ) ) )
( y x )
( printf " this line must not be printed \n " ) ;
)
( printf " %d \n " ( f 90 ) ) ; this should print 8100.
( y 10 ) ; this ends up with the " unable to return from dead context " error .
*/
HCL_ASSERT ( hcl , hcl - > active_context ! = hcl - > processor - > active - > initial_context ) ;
2020-12-31 19:03:37 +00:00
HCL_ASSERT ( hcl , ( hcl_oop_t ) hcl - > active_context - > home - > sender ! = hcl - > _nil ) ;
2020-10-13 14:44:00 +00:00
if ( hcl - > active_context - > home - > ip = = HCL_SMOOI_TO_OOP ( - 1 ) )
{
HCL_LOG0 ( hcl , HCL_LOG_IC | HCL_LOG_ERROR , " Error - cannot return from dead context \n " ) ;
hcl_seterrbfmt ( hcl , HCL_EINTERN , " unable to return from dead context " ) ; /* TODO: can i make this error catchable at the hcl level? */
return - 1 ;
}
2020-10-10 17:36:33 +00:00
2020-10-13 14:44:00 +00:00
hcl - > active_context - > home - > ip = HCL_SMOOI_TO_OOP ( - 1 ) ; /* mark that this context has returned */
hcl - > ip = - 1 ; /* mark that the active context has returned. saved into hcl->active_context->ip in SWITCH_ACTIVE_CONTEXT() */
2020-10-10 17:36:33 +00:00
SWITCH_ACTIVE_CONTEXT ( hcl , hcl - > active_context - > home - > sender ) ;
/* push the return value to the stack of the new active context */
HCL_STACK_PUSH ( hcl , return_value ) ;
2020-10-13 14:44:00 +00:00
2020-10-15 12:57:05 +00:00
#if 0
/* stack dump */
HCL_DEBUG1 ( hcl , " ****** non local returning %O \n " , return_value ) ;
{
int i ;
for ( i = hcl - > sp ; i > = 0 ; i - - )
{
HCL_DEBUG2 ( hcl , " STACK[%d] => %O \n " , i , HCL_STACK_GET ( hcl , i ) ) ;
}
}
# endif
2020-10-10 17:36:33 +00:00
}
return 0 ;
}
2020-10-13 14:44:00 +00:00
static HCL_INLINE void do_return_from_block ( hcl_t * hcl )
{
/*if (hcl->active_context == hcl->processor->active->initial_context)*/
if ( hcl - > active_context - > home = = hcl - > _nil )
{
/* the active context to return from is an initial context of
* the active process . let ' s terminate the process .
* the initial context has been forged over the initial function
* in start_initial_process_and_context ( ) */
HCL_ASSERT ( hcl , ( hcl_oop_t ) hcl - > active_context - > sender = = hcl - > _nil ) ;
hcl - > active_context - > ip = HCL_SMOOI_TO_OOP ( - 1 ) ; /* mark context dead */
terminate_process ( hcl , hcl - > processor - > active ) ;
}
else
{
/* it is a normal block return as the active block context
* is not the initial context of a process */
hcl - > ip = - 1 ; /* mark context dead. saved into hcl->active_context->ip in SWITCH_ACTIVE_CONTEXT */
SWITCH_ACTIVE_CONTEXT ( hcl , ( hcl_oop_context_t ) hcl - > active_context - > sender ) ;
}
}
2016-10-04 17:56:28 +00:00
/* ------------------------------------------------------------------------- */
2020-12-31 17:48:47 +00:00
static void xma_dumper ( void * ctx , const char * fmt , . . . )
{
va_list ap ;
va_start ( ap , fmt ) ;
hcl_logbfmtv ( ( hcl_t * ) ctx , HCL_LOG_IC | HCL_LOG_INFO , fmt , ap ) ;
va_end ( ap ) ;
}
2021-01-31 18:46:13 +00:00
static void supplement_errmsg ( hcl_t * hcl , hcl_ooi_t ip )
{
if ( hcl - > active_function - > dbgi ! = hcl - > _nil )
{
2021-02-01 03:32:09 +00:00
hcl_dbgi_t * dbgi ;
2021-01-31 18:46:13 +00:00
static hcl_ooch_t dash [ ] = { ' - ' , ' \0 ' } ;
const hcl_ooch_t * orgmsg = hcl_backuperrmsg ( hcl ) ;
hcl_errnum_t orgnum = hcl_geterrnum ( hcl ) ;
HCL_ASSERT ( hcl , HCL_IS_BYTEARRAY ( hcl , hcl - > active_function - > dbgi ) ) ;
2021-02-01 03:32:09 +00:00
dbgi = ( hcl_dbgi_t * ) HCL_OBJ_GET_BYTE_SLOT ( hcl - > active_function - > dbgi ) ;
2021-01-31 18:46:13 +00:00
hcl_seterrbfmt ( hcl , orgnum , " %js (%js:%zu) " , orgmsg ,
2021-02-01 03:32:09 +00:00
( dbgi [ ip ] . fname ? dbgi [ ip ] . fname : dash ) , dbgi [ ip ] . sline ) ;
2021-01-31 18:46:13 +00:00
}
}
2016-10-04 17:56:28 +00:00
static int execute ( hcl_t * hcl )
{
hcl_oob_t bcode ;
hcl_oow_t b1 , b2 ;
hcl_oop_t return_value ;
2021-01-31 18:46:13 +00:00
hcl_ooi_t fetched_instruction_pointer ;
2016-10-04 17:56:28 +00:00
# if defined(HCL_PROFILE_VM)
hcl_uintmax_t inst_counter = 0 ;
# endif
2018-02-05 10:43:25 +00:00
HCL_ASSERT ( hcl , hcl - > active_context ! = HCL_NULL ) ;
2016-10-04 17:56:28 +00:00
2018-03-10 17:53:44 +00:00
hcl - > abort_req = 0 ;
if ( vm_startup ( hcl ) < = - 1 ) return - 1 ;
2016-10-04 17:56:28 +00:00
hcl - > proc_switched = 0 ;
2020-12-31 17:48:47 +00:00
hcl - > gci . lazy_sweep = 1 ; /* TODO: make it configurable?? */
HCL_INIT_NTIME ( & hcl - > gci . stat . alloc , 0 , 0 ) ;
HCL_INIT_NTIME ( & hcl - > gci . stat . mark , 0 , 0 ) ;
HCL_INIT_NTIME ( & hcl - > gci . stat . sweep , 0 , 0 ) ;
2016-10-04 17:56:28 +00:00
while ( 1 )
{
2020-10-15 12:57:05 +00:00
/* stop requested or no more runnable process */
2021-01-24 15:53:35 +00:00
if ( hcl - > abort_req | | ( ! hcl - > no_proc_switch & & switch_process_if_needed ( hcl ) = = 0 ) )
{
/* TODO: if aborting, ensure to terminate all ongoing processes */
break ;
}
2016-10-04 17:56:28 +00:00
2020-10-08 09:25:54 +00:00
if ( HCL_UNLIKELY ( hcl - > ip > = HCL_FUNCTION_GET_CODE_SIZE ( hcl - > active_function ) ) )
2016-10-13 07:41:10 +00:00
{
2020-10-13 14:44:00 +00:00
HCL_DEBUG2 ( hcl , " Stopping execution as IP reached the end of bytecode(%zu) - SP %zd \n " , hcl - > code . bc . len , hcl - > sp ) ;
2018-02-08 14:40:56 +00:00
return_value = hcl - > _nil ;
goto handle_return ;
2016-10-13 07:41:10 +00:00
}
2016-10-06 17:49:47 +00:00
fetched_instruction_pointer = hcl - > ip ;
2016-10-04 17:56:28 +00:00
FETCH_BYTE_CODE_TO ( hcl , bcode ) ;
/*while (bcode == HCL_CODE_NOOP) FETCH_BYTE_CODE_TO (hcl, bcode);*/
2018-03-11 11:16:28 +00:00
if ( hcl - > vm_checkbc_cb_count ) vm_checkbc ( hcl , bcode ) ;
2020-10-15 12:57:05 +00:00
2018-03-11 03:05:42 +00:00
if ( HCL_UNLIKELY ( hcl - > abort_req ) )
{
2018-03-11 11:16:28 +00:00
/* i place this abortion check after vm_checkbc()
2018-03-11 03:05:42 +00:00
* to honor hcl_abort ( ) if called in the callback , */
HCL_DEBUG0 ( hcl , " Stopping execution for abortion request \n " ) ;
return_value = hcl - > _nil ;
goto handle_return ;
}
2018-03-10 17:53:44 +00:00
# if defined(HCL_PROFILE_VM)
2016-10-04 17:56:28 +00:00
inst_counter + + ;
2018-03-10 17:53:44 +00:00
# endif
2016-10-04 17:56:28 +00:00
switch ( bcode )
{
/* ------------------------------------------------- */
#if 0
2020-09-22 09:19:53 +00:00
case HCL_CODE_PUSH_INSTVAR_X :
2016-10-04 17:56:28 +00:00
FETCH_PARAM_CODE_TO ( hcl , b1 ) ;
goto push_instvar ;
2020-09-22 09:19:53 +00:00
case HCL_CODE_PUSH_INSTVAR_0 :
case HCL_CODE_PUSH_INSTVAR_1 :
case HCL_CODE_PUSH_INSTVAR_2 :
case HCL_CODE_PUSH_INSTVAR_3 :
case HCL_CODE_PUSH_INSTVAR_4 :
case HCL_CODE_PUSH_INSTVAR_5 :
case HCL_CODE_PUSH_INSTVAR_6 :
case HCL_CODE_PUSH_INSTVAR_7 :
2016-10-04 17:56:28 +00:00
b1 = bcode & 0x7 ; /* low 3 bits */
push_instvar :
LOG_INST_1 ( hcl , " push_instvar %zu " , b1 ) ;
2020-10-04 18:21:05 +00:00
HCL_ASSERT ( hcl , HCL_OBJ_GET_FLAGS_TYPE ( hcl - > active_context - > origin - > receiver_or_base ) = = HCL_OBJ_TYPE_OOP ) ;
HCL_STACK_PUSH ( hcl , ( ( hcl_oop_oop_t ) hcl - > active_context - > origin - > receiver_or_base ) - > slot [ b1 ] ) ;
2016-10-04 17:56:28 +00:00
break ;
/* ------------------------------------------------- */
2020-09-22 09:19:53 +00:00
case HCL_CODE_STORE_INTO_INSTVAR_X :
2016-10-04 17:56:28 +00:00
FETCH_PARAM_CODE_TO ( hcl , b1 ) ;
goto store_instvar ;
2020-09-22 09:19:53 +00:00
case HCL_CODE_STORE_INTO_INSTVAR_0 :
case HCL_CODE_STORE_INTO_INSTVAR_1 :
case HCL_CODE_STORE_INTO_INSTVAR_2 :
case HCL_CODE_STORE_INTO_INSTVAR_3 :
case HCL_CODE_STORE_INTO_INSTVAR_4 :
case HCL_CODE_STORE_INTO_INSTVAR_5 :
case HCL_CODE_STORE_INTO_INSTVAR_6 :
case HCL_CODE_STORE_INTO_INSTVAR_7 :
2016-10-04 17:56:28 +00:00
b1 = bcode & 0x7 ; /* low 3 bits */
store_instvar :
LOG_INST_1 ( hcl , " store_into_instvar %zu " , b1 ) ;
2020-10-04 18:21:05 +00:00
HCL_ASSERT ( hcl , HCL_OBJ_GET_FLAGS_TYPE ( hcl - > active_context - > receiver_or_base ) = = HCL_OBJ_TYPE_OOP ) ;
( ( hcl_oop_oop_t ) hcl - > active_context - > origin - > receiver_or_base ) - > slot [ b1 ] = HCL_STACK_GETTOP ( hcl ) ;
2016-10-04 17:56:28 +00:00
break ;
/* ------------------------------------------------- */
2020-09-22 09:19:53 +00:00
case HCL_CODE_POP_INTO_INSTVAR_X :
2016-10-04 17:56:28 +00:00
FETCH_PARAM_CODE_TO ( hcl , b1 ) ;
goto pop_into_instvar ;
2020-09-22 09:19:53 +00:00
case HCL_CODE_POP_INTO_INSTVAR_0 :
case HCL_CODE_POP_INTO_INSTVAR_1 :
case HCL_CODE_POP_INTO_INSTVAR_2 :
case HCL_CODE_POP_INTO_INSTVAR_3 :
case HCL_CODE_POP_INTO_INSTVAR_4 :
case HCL_CODE_POP_INTO_INSTVAR_5 :
case HCL_CODE_POP_INTO_INSTVAR_6 :
case HCL_CODE_POP_INTO_INSTVAR_7 :
2016-10-04 17:56:28 +00:00
b1 = bcode & 0x7 ; /* low 3 bits */
pop_into_instvar :
LOG_INST_1 ( hcl , " pop_into_instvar %zu " , b1 ) ;
2020-10-04 18:21:05 +00:00
HCL_ASSERT ( hcl , HCL_OBJ_GET_FLAGS_TYPE ( hcl - > active_context - > receiver_or_base ) = = HCL_OBJ_TYPE_OOP ) ;
( ( hcl_oop_oop_t ) hcl - > active_context - > origin - > receiver_or_base ) - > slot [ b1 ] = HCL_STACK_GETTOP ( hcl ) ;
2016-10-04 17:56:28 +00:00
HCL_STACK_POP ( hcl ) ;
break ;
# endif
/* ------------------------------------------------- */
case HCL_CODE_PUSH_TEMPVAR_X :
case HCL_CODE_STORE_INTO_TEMPVAR_X :
2020-09-22 09:19:53 +00:00
case HCL_CODE_POP_INTO_TEMPVAR_X :
2016-10-04 17:56:28 +00:00
FETCH_PARAM_CODE_TO ( hcl , b1 ) ;
goto handle_tempvar ;
case HCL_CODE_PUSH_TEMPVAR_0 :
case HCL_CODE_PUSH_TEMPVAR_1 :
case HCL_CODE_PUSH_TEMPVAR_2 :
case HCL_CODE_PUSH_TEMPVAR_3 :
case HCL_CODE_PUSH_TEMPVAR_4 :
case HCL_CODE_PUSH_TEMPVAR_5 :
case HCL_CODE_PUSH_TEMPVAR_6 :
case HCL_CODE_PUSH_TEMPVAR_7 :
case HCL_CODE_STORE_INTO_TEMPVAR_0 :
case HCL_CODE_STORE_INTO_TEMPVAR_1 :
case HCL_CODE_STORE_INTO_TEMPVAR_2 :
case HCL_CODE_STORE_INTO_TEMPVAR_3 :
case HCL_CODE_STORE_INTO_TEMPVAR_4 :
case HCL_CODE_STORE_INTO_TEMPVAR_5 :
case HCL_CODE_STORE_INTO_TEMPVAR_6 :
case HCL_CODE_STORE_INTO_TEMPVAR_7 :
2020-09-22 09:19:53 +00:00
case HCL_CODE_POP_INTO_TEMPVAR_0 :
case HCL_CODE_POP_INTO_TEMPVAR_1 :
case HCL_CODE_POP_INTO_TEMPVAR_2 :
case HCL_CODE_POP_INTO_TEMPVAR_3 :
case HCL_CODE_POP_INTO_TEMPVAR_4 :
case HCL_CODE_POP_INTO_TEMPVAR_5 :
case HCL_CODE_POP_INTO_TEMPVAR_6 :
case HCL_CODE_POP_INTO_TEMPVAR_7 :
2016-10-04 17:56:28 +00:00
{
hcl_oop_context_t ctx ;
hcl_ooi_t bx ;
b1 = bcode & 0x7 ; /* low 3 bits */
handle_tempvar :
/* when CTXTEMPVAR inststructions are used, the above
* instructions are used only for temporary access
* outside a block . i can assume that the temporary
* variable index is pointing to one of temporaries
* in the relevant method context */
ctx = hcl - > active_context - > origin ;
bx = b1 ;
2018-02-05 10:43:25 +00:00
HCL_ASSERT ( hcl , HCL_IS_CONTEXT ( hcl , ctx ) ) ;
2016-10-04 17:56:28 +00:00
if ( ( bcode > > 4 ) & 1 )
{
/* push - bit 4 on */
LOG_INST_1 ( hcl , " push_tempvar %zu " , b1 ) ;
HCL_STACK_PUSH ( hcl , ctx - > slot [ bx ] ) ;
}
else
{
/* store or pop - bit 5 off */
ctx - > slot [ bx ] = HCL_STACK_GETTOP ( hcl ) ;
if ( ( bcode > > 3 ) & 1 )
{
/* pop - bit 3 on */
LOG_INST_1 ( hcl , " pop_into_tempvar %zu " , b1 ) ;
HCL_STACK_POP ( hcl ) ;
}
else
{
LOG_INST_1 ( hcl , " store_into_tempvar %zu " , b1 ) ;
}
}
break ;
}
/* ------------------------------------------------- */
case HCL_CODE_PUSH_LITERAL_X2 :
FETCH_PARAM_CODE_TO ( hcl , b1 ) ;
FETCH_PARAM_CODE_TO ( hcl , b2 ) ;
2021-01-29 12:39:31 +00:00
# if (HCL_CODE_LONG_PARAM_SIZE == 2)
2016-10-04 17:56:28 +00:00
b1 = ( b1 < < 16 ) | b2 ;
# else
b1 = ( b1 < < 8 ) | b2 ;
# endif
goto push_literal ;
case HCL_CODE_PUSH_LITERAL_X :
FETCH_PARAM_CODE_TO ( hcl , b1 ) ;
goto push_literal ;
case HCL_CODE_PUSH_LITERAL_0 :
case HCL_CODE_PUSH_LITERAL_1 :
case HCL_CODE_PUSH_LITERAL_2 :
case HCL_CODE_PUSH_LITERAL_3 :
case HCL_CODE_PUSH_LITERAL_4 :
case HCL_CODE_PUSH_LITERAL_5 :
case HCL_CODE_PUSH_LITERAL_6 :
case HCL_CODE_PUSH_LITERAL_7 :
b1 = bcode & 0x7 ; /* low 3 bits */
push_literal :
LOG_INST_1 ( hcl , " push_literal @%zu " , b1 ) ;
2020-10-06 09:40:39 +00:00
/*HCL_STACK_PUSH (hcl, hcl->code.lit.arr->slot[b1]);*/
HCL_STACK_PUSH ( hcl , hcl - > active_function - > literal_frame [ b1 ] ) ;
2016-10-04 17:56:28 +00:00
break ;
/* ------------------------------------------------- */
case HCL_CODE_PUSH_OBJECT_X :
case HCL_CODE_STORE_INTO_OBJECT_X :
2020-09-22 09:19:53 +00:00
case HCL_CODE_POP_INTO_OBJECT_X :
2016-10-04 17:56:28 +00:00
FETCH_PARAM_CODE_TO ( hcl , b1 ) ;
goto handle_object ;
case HCL_CODE_PUSH_OBJECT_0 :
case HCL_CODE_PUSH_OBJECT_1 :
case HCL_CODE_PUSH_OBJECT_2 :
case HCL_CODE_PUSH_OBJECT_3 :
case HCL_CODE_STORE_INTO_OBJECT_0 :
case HCL_CODE_STORE_INTO_OBJECT_1 :
case HCL_CODE_STORE_INTO_OBJECT_2 :
case HCL_CODE_STORE_INTO_OBJECT_3 :
2020-09-22 09:19:53 +00:00
case HCL_CODE_POP_INTO_OBJECT_0 :
case HCL_CODE_POP_INTO_OBJECT_1 :
case HCL_CODE_POP_INTO_OBJECT_2 :
case HCL_CODE_POP_INTO_OBJECT_3 :
2016-10-04 17:56:28 +00:00
{
hcl_oop_cons_t ass ;
b1 = bcode & 0x3 ; /* low 2 bits */
handle_object :
2020-10-04 19:07:21 +00:00
/*ass = hcl->code.lit.arr->slot[b1];*/
2020-10-04 18:21:05 +00:00
ass = ( hcl_oop_cons_t ) hcl - > active_function - > literal_frame [ b1 ] ;
2018-02-05 10:43:25 +00:00
HCL_ASSERT ( hcl , HCL_IS_CONS ( hcl , ass ) ) ;
2016-10-04 17:56:28 +00:00
if ( ( bcode > > 3 ) & 1 )
{
/* store or pop */
ass - > cdr = HCL_STACK_GETTOP ( hcl ) ;
if ( ( bcode > > 2 ) & 1 )
{
/* pop */
LOG_INST_1 ( hcl , " pop_into_object @%zu " , b1 ) ;
HCL_STACK_POP ( hcl ) ;
}
else
{
LOG_INST_1 ( hcl , " store_into_object @%zu " , b1 ) ;
}
}
else
{
/* push */
LOG_INST_1 ( hcl , " push_object @%zu " , b1 ) ;
HCL_STACK_PUSH ( hcl , ass - > cdr ) ;
}
break ;
}
/* -------------------------------------------------------- */
case HCL_CODE_JUMP_FORWARD_X :
FETCH_PARAM_CODE_TO ( hcl , b1 ) ;
LOG_INST_1 ( hcl , " jump_forward %zu " , b1 ) ;
hcl - > ip + = b1 ;
break ;
case HCL_CODE_JUMP_FORWARD_0 :
case HCL_CODE_JUMP_FORWARD_1 :
case HCL_CODE_JUMP_FORWARD_2 :
case HCL_CODE_JUMP_FORWARD_3 :
LOG_INST_1 ( hcl , " jump_forward %zu " , ( hcl_oow_t ) ( bcode & 0x3 ) ) ;
hcl - > ip + = ( bcode & 0x3 ) ; /* low 2 bits */
break ;
case HCL_CODE_JUMP_BACKWARD_X :
FETCH_PARAM_CODE_TO ( hcl , b1 ) ;
LOG_INST_1 ( hcl , " jump_backward %zu " , b1 ) ;
2016-10-11 10:29:37 +00:00
hcl - > ip - = b1 ;
2016-10-04 17:56:28 +00:00
break ;
case HCL_CODE_JUMP_BACKWARD_0 :
case HCL_CODE_JUMP_BACKWARD_1 :
case HCL_CODE_JUMP_BACKWARD_2 :
case HCL_CODE_JUMP_BACKWARD_3 :
LOG_INST_1 ( hcl , " jump_backward %zu " , ( hcl_oow_t ) ( bcode & 0x3 ) ) ;
hcl - > ip - = ( bcode & 0x3 ) ; /* low 2 bits */
break ;
2016-10-12 07:30:54 +00:00
case HCL_CODE_JUMP_FORWARD_IF_TRUE :
FETCH_PARAM_CODE_TO ( hcl , b1 ) ;
LOG_INST_1 ( hcl , " jump_forward_if_true %zu " , b1 ) ;
2016-10-15 08:49:27 +00:00
/*if (HCL_STACK_GETTOP(hcl) == hcl->_true) hcl->ip += b1; TODO: _true or not _false?*/
if ( HCL_STACK_GETTOP ( hcl ) ! = hcl - > _false ) hcl - > ip + = b1 ;
2016-10-12 07:30:54 +00:00
break ;
case HCL_CODE_JUMP2_FORWARD_IF_TRUE :
FETCH_PARAM_CODE_TO ( hcl , b1 ) ;
LOG_INST_1 ( hcl , " jump2_forward_if_true %zu " , b1 ) ;
2016-10-15 08:49:27 +00:00
/*if (HCL_STACK_GETTOP(hcl) == hcl->_true) hcl->ip += MAX_CODE_JUMP + b1;*/
if ( HCL_STACK_GETTOP ( hcl ) ! = hcl - > _false ) hcl - > ip + = MAX_CODE_JUMP + b1 ;
2016-10-12 07:30:54 +00:00
break ;
case HCL_CODE_JUMP_FORWARD_IF_FALSE :
2016-10-11 10:29:37 +00:00
FETCH_PARAM_CODE_TO ( hcl , b1 ) ;
LOG_INST_1 ( hcl , " jump_forward_if_false %zu " , b1 ) ;
if ( HCL_STACK_GETTOP ( hcl ) = = hcl - > _false ) hcl - > ip + = b1 ;
break ;
2016-10-12 07:30:54 +00:00
case HCL_CODE_JUMP2_FORWARD_IF_FALSE :
FETCH_PARAM_CODE_TO ( hcl , b1 ) ;
LOG_INST_1 ( hcl , " jump2_forward_if_false %zu " , b1 ) ;
if ( HCL_STACK_GETTOP ( hcl ) = = hcl - > _false ) hcl - > ip + = MAX_CODE_JUMP + b1 ;
2016-10-11 10:29:37 +00:00
break ;
2016-10-04 17:56:28 +00:00
case HCL_CODE_JUMP2_FORWARD :
FETCH_PARAM_CODE_TO ( hcl , b1 ) ;
LOG_INST_1 ( hcl , " jump2_forward %zu " , b1 ) ;
hcl - > ip + = MAX_CODE_JUMP + b1 ;
break ;
2021-01-24 15:45:28 +00:00
case HCL_CODE_JUMP_BACKWARD_IF_TRUE :
FETCH_PARAM_CODE_TO ( hcl , b1 ) ;
LOG_INST_1 ( hcl , " jump_backward_if_true %zu " , b1 ) ;
if ( HCL_STACK_GETTOP ( hcl ) ! = hcl - > _false ) hcl - > ip - = b1 ;
break ;
case HCL_CODE_JUMP2_BACKWARD_IF_TRUE :
FETCH_PARAM_CODE_TO ( hcl , b1 ) ;
LOG_INST_1 ( hcl , " jump2_backward_if_true %zu " , b1 ) ;
if ( HCL_STACK_GETTOP ( hcl ) ! = hcl - > _false ) hcl - > ip - = MAX_CODE_JUMP + b1 ;
break ;
case HCL_CODE_JUMP_BACKWARD_IF_FALSE :
FETCH_PARAM_CODE_TO ( hcl , b1 ) ;
LOG_INST_1 ( hcl , " jump_backward_if_false %zu " , b1 ) ;
if ( HCL_STACK_GETTOP ( hcl ) = = hcl - > _false ) hcl - > ip - = b1 ;
break ;
case HCL_CODE_JUMP2_BACKWARD_IF_FALSE :
FETCH_PARAM_CODE_TO ( hcl , b1 ) ;
LOG_INST_1 ( hcl , " jump2_backward_if_false %zu " , b1 ) ;
if ( HCL_STACK_GETTOP ( hcl ) = = hcl - > _false ) hcl - > ip - = MAX_CODE_JUMP + b1 ;
break ;
2016-10-04 17:56:28 +00:00
case HCL_CODE_JUMP2_BACKWARD :
FETCH_PARAM_CODE_TO ( hcl , b1 ) ;
LOG_INST_1 ( hcl , " jump2_backward %zu " , b1 ) ;
hcl - > ip - = MAX_CODE_JUMP + b1 ;
break ;
/* -------------------------------------------------------- */
case HCL_CODE_CALL_X :
FETCH_PARAM_CODE_TO ( hcl , b1 ) ;
goto handle_call ;
case HCL_CODE_CALL_0 :
case HCL_CODE_CALL_1 :
case HCL_CODE_CALL_2 :
case HCL_CODE_CALL_3 :
2016-10-06 17:49:47 +00:00
{
hcl_oop_t rcv ;
2016-10-04 17:56:28 +00:00
b1 = bcode & 0x3 ; /* low 2 bits */
2016-10-06 18:17:52 +00:00
handle_call :
2016-10-04 17:56:28 +00:00
LOG_INST_1 ( hcl , " call %zu " , b1 ) ;
2016-10-06 17:49:47 +00:00
2018-02-05 15:59:32 +00:00
rcv = HCL_STACK_GETRCV ( hcl , b1 ) ;
2016-10-06 18:17:52 +00:00
if ( HCL_OOP_IS_POINTER ( rcv ) )
2016-10-06 17:49:47 +00:00
{
2016-10-06 18:17:52 +00:00
switch ( HCL_OBJ_GET_FLAGS_BRAND ( rcv ) )
{
2020-10-04 18:21:05 +00:00
case HCL_BRAND_FUNCTION :
2021-02-01 13:20:46 +00:00
if ( activate_function ( hcl , b1 ) < = - 1 ) goto call_failed ;
2020-10-04 18:21:05 +00:00
break ;
2020-10-09 07:14:32 +00:00
case HCL_BRAND_BLOCK :
2021-02-01 13:20:46 +00:00
if ( activate_block ( hcl , b1 ) < = - 1 ) goto call_failed ;
2020-10-09 07:14:32 +00:00
break ;
2016-10-06 18:17:52 +00:00
case HCL_BRAND_PRIM :
2021-02-01 13:20:46 +00:00
if ( call_primitive ( hcl , b1 ) < = - 1 ) goto call_failed ;
2016-10-06 18:17:52 +00:00
break ;
2018-08-06 10:41:38 +00:00
2016-10-06 18:17:52 +00:00
default :
goto cannot_call ;
}
2016-10-06 17:49:47 +00:00
}
else
{
2016-10-06 18:17:52 +00:00
cannot_call :
2016-10-06 17:49:47 +00:00
/* run time error */
2018-02-05 10:43:25 +00:00
hcl_seterrbfmt ( hcl , HCL_ECALL , " cannot call %O " , rcv ) ;
2021-02-01 13:20:46 +00:00
call_failed :
2021-01-31 18:46:13 +00:00
supplement_errmsg ( hcl , fetched_instruction_pointer ) ;
2018-02-12 10:50:44 +00:00
goto oops ;
2016-10-06 17:49:47 +00:00
}
2016-10-04 17:56:28 +00:00
break ;
2016-10-06 17:49:47 +00:00
}
2016-10-04 17:56:28 +00:00
/* -------------------------------------------------------- */
case HCL_CODE_PUSH_CTXTEMPVAR_X :
case HCL_CODE_STORE_INTO_CTXTEMPVAR_X :
2020-09-22 09:19:53 +00:00
case HCL_CODE_POP_INTO_CTXTEMPVAR_X :
2016-10-04 17:56:28 +00:00
FETCH_PARAM_CODE_TO ( hcl , b1 ) ;
FETCH_PARAM_CODE_TO ( hcl , b2 ) ;
goto handle_ctxtempvar ;
case HCL_CODE_PUSH_CTXTEMPVAR_0 :
case HCL_CODE_PUSH_CTXTEMPVAR_1 :
case HCL_CODE_PUSH_CTXTEMPVAR_2 :
case HCL_CODE_PUSH_CTXTEMPVAR_3 :
case HCL_CODE_STORE_INTO_CTXTEMPVAR_0 :
case HCL_CODE_STORE_INTO_CTXTEMPVAR_1 :
case HCL_CODE_STORE_INTO_CTXTEMPVAR_2 :
case HCL_CODE_STORE_INTO_CTXTEMPVAR_3 :
2020-09-22 09:19:53 +00:00
case HCL_CODE_POP_INTO_CTXTEMPVAR_0 :
case HCL_CODE_POP_INTO_CTXTEMPVAR_1 :
case HCL_CODE_POP_INTO_CTXTEMPVAR_2 :
case HCL_CODE_POP_INTO_CTXTEMPVAR_3 :
2016-10-04 17:56:28 +00:00
{
hcl_ooi_t i ;
hcl_oop_context_t ctx ;
b1 = bcode & 0x3 ; /* low 2 bits */
FETCH_BYTE_CODE_TO ( hcl , b2 ) ;
handle_ctxtempvar :
ctx = hcl - > active_context ;
2018-02-05 10:43:25 +00:00
HCL_ASSERT ( hcl , ( hcl_oop_t ) ctx ! = hcl - > _nil ) ;
2016-10-04 17:56:28 +00:00
for ( i = 0 ; i < b1 ; i + + )
{
ctx = ( hcl_oop_context_t ) ctx - > home ;
2020-10-04 18:21:05 +00:00
/* the initial context has nil in the home field.
* the loop must not reach beyond the initial context */
2020-10-04 19:34:53 +00:00
HCL_ASSERT ( hcl , ( hcl_oop_t ) ctx ! = hcl - > _nil ) ;
2016-10-04 17:56:28 +00:00
}
if ( ( bcode > > 3 ) & 1 )
{
/* store or pop */
ctx - > slot [ b2 ] = HCL_STACK_GETTOP ( hcl ) ;
if ( ( bcode > > 2 ) & 1 )
{
/* pop */
HCL_STACK_POP ( hcl ) ;
LOG_INST_2 ( hcl , " pop_into_ctxtempvar %zu %zu " , b1 , b2 ) ;
}
else
{
LOG_INST_2 ( hcl , " store_into_ctxtempvar %zu %zu " , b1 , b2 ) ;
}
}
else
{
/* push */
HCL_STACK_PUSH ( hcl , ctx - > slot [ b2 ] ) ;
LOG_INST_2 ( hcl , " push_ctxtempvar %zu %zu " , b1 , b2 ) ;
}
break ;
}
/* -------------------------------------------------------- */
2020-09-22 09:19:53 +00:00
case HCL_CODE_PUSH_OBJVAR_X :
case HCL_CODE_STORE_INTO_OBJVAR_X :
case HCL_CODE_POP_INTO_OBJVAR_X :
2016-10-04 17:56:28 +00:00
FETCH_PARAM_CODE_TO ( hcl , b1 ) ;
FETCH_PARAM_CODE_TO ( hcl , b2 ) ;
goto handle_objvar ;
2020-09-22 09:19:53 +00:00
case HCL_CODE_PUSH_OBJVAR_0 :
case HCL_CODE_PUSH_OBJVAR_1 :
case HCL_CODE_PUSH_OBJVAR_2 :
case HCL_CODE_PUSH_OBJVAR_3 :
case HCL_CODE_STORE_INTO_OBJVAR_0 :
case HCL_CODE_STORE_INTO_OBJVAR_1 :
case HCL_CODE_STORE_INTO_OBJVAR_2 :
case HCL_CODE_STORE_INTO_OBJVAR_3 :
case HCL_CODE_POP_INTO_OBJVAR_0 :
case HCL_CODE_POP_INTO_OBJVAR_1 :
case HCL_CODE_POP_INTO_OBJVAR_2 :
case HCL_CODE_POP_INTO_OBJVAR_3 :
2016-10-04 17:56:28 +00:00
{
hcl_oop_oop_t t ;
/* b1 -> variable index to the object indicated by b2.
* b2 - > object index stored in the literal frame . */
b1 = bcode & 0x3 ; /* low 2 bits */
FETCH_BYTE_CODE_TO ( hcl , b2 ) ;
handle_objvar :
2020-10-04 19:07:21 +00:00
/*t = hcl->code.lit.arr->slot[b2];*/
2020-10-04 18:21:05 +00:00
t = ( hcl_oop_oop_t ) hcl - > active_function - > literal_frame [ b2 ] ;
2018-02-05 10:43:25 +00:00
HCL_ASSERT ( hcl , HCL_OBJ_GET_FLAGS_TYPE ( t ) = = HCL_OBJ_TYPE_OOP ) ;
HCL_ASSERT ( hcl , b1 < HCL_OBJ_GET_SIZE ( t ) ) ;
2016-10-04 17:56:28 +00:00
if ( ( bcode > > 3 ) & 1 )
{
/* store or pop */
t - > slot [ b1 ] = HCL_STACK_GETTOP ( hcl ) ;
if ( ( bcode > > 2 ) & 1 )
{
/* pop */
HCL_STACK_POP ( hcl ) ;
LOG_INST_2 ( hcl , " pop_into_objvar %zu %zu " , b1 , b2 ) ;
}
else
{
LOG_INST_2 ( hcl , " store_into_objvar %zu %zu " , b1 , b2 ) ;
}
}
else
{
/* push */
LOG_INST_2 ( hcl , " push_objvar %zu %zu " , b1 , b2 ) ;
HCL_STACK_PUSH ( hcl , t - > slot [ b1 ] ) ;
}
break ;
}
/* -------------------------------------------------------- */
#if 0
2020-09-22 09:19:53 +00:00
case HCL_CODE_SEND_MESSAGE_X :
case HCL_CODE_SEND_MESSAGE_TO_SUPER_X :
2016-10-04 17:56:28 +00:00
/* b1 -> number of arguments
* b2 - > selector index stored in the literal frame */
FETCH_PARAM_CODE_TO ( hcl , b1 ) ;
FETCH_PARAM_CODE_TO ( hcl , b2 ) ;
goto handle_send_message ;
2020-09-22 09:19:53 +00:00
case HCL_CODE_SEND_MESSAGE_0 :
case HCL_CODE_SEND_MESSAGE_1 :
case HCL_CODE_SEND_MESSAGE_2 :
case HCL_CODE_SEND_MESSAGE_3 :
case HCL_CODE_SEND_MESSAGE_TO_SUPER_0 :
case HCL_CODE_SEND_MESSAGE_TO_SUPER_1 :
case HCL_CODE_SEND_MESSAGE_TO_SUPER_2 :
case HCL_CODE_SEND_MESSAGE_TO_SUPER_3 :
2016-10-04 17:56:28 +00:00
{
hcl_oop_char_t selector ;
b1 = bcode & 0x3 ; /* low 2 bits */
FETCH_BYTE_CODE_TO ( hcl , b2 ) ;
handle_send_message :
/* get the selector from the literal frame */
selector = ( hcl_oop_char_t ) hcl - > active_method - > slot [ b2 ] ;
LOG_INST_3 ( hcl , " send_message%hs %zu @%zu " , ( ( ( bcode > > 2 ) & 1 ) ? " _to_super " : " " ) , b1 , b2 ) ;
if ( send_message ( hcl , selector , ( ( bcode > > 2 ) & 1 ) , b1 ) < = - 1 ) goto oops ;
break ; /* CMD_SEND_MESSAGE */
}
# endif
/* -------------------------------------------------------- */
2020-10-04 18:21:05 +00:00
case HCL_CODE_PUSH_RECEIVER : /* push self or super */
2016-10-04 17:56:28 +00:00
LOG_INST_0 ( hcl , " push_receiver " ) ;
2020-10-04 18:21:05 +00:00
HCL_STACK_PUSH ( hcl , hcl - > active_context - > origin - > receiver_or_base ) ;
2016-10-04 17:56:28 +00:00
break ;
case HCL_CODE_PUSH_NIL :
LOG_INST_0 ( hcl , " push_nil " ) ;
HCL_STACK_PUSH ( hcl , hcl - > _nil ) ;
break ;
case HCL_CODE_PUSH_TRUE :
LOG_INST_0 ( hcl , " push_true " ) ;
HCL_STACK_PUSH ( hcl , hcl - > _true ) ;
break ;
case HCL_CODE_PUSH_FALSE :
LOG_INST_0 ( hcl , " push_false " ) ;
HCL_STACK_PUSH ( hcl , hcl - > _false ) ;
break ;
2020-09-22 09:19:53 +00:00
case HCL_CODE_PUSH_CONTEXT :
2016-10-04 17:56:28 +00:00
LOG_INST_0 ( hcl , " push_context " ) ;
HCL_STACK_PUSH ( hcl , ( hcl_oop_t ) hcl - > active_context ) ;
break ;
2020-09-22 09:19:53 +00:00
case HCL_CODE_PUSH_PROCESS :
2016-10-04 17:56:28 +00:00
LOG_INST_0 ( hcl , " push_process " ) ;
HCL_STACK_PUSH ( hcl , ( hcl_oop_t ) hcl - > processor - > active ) ;
break ;
case HCL_CODE_PUSH_NEGONE :
LOG_INST_0 ( hcl , " push_negone " ) ;
HCL_STACK_PUSH ( hcl , HCL_SMOOI_TO_OOP ( - 1 ) ) ;
break ;
case HCL_CODE_PUSH_ZERO :
LOG_INST_0 ( hcl , " push_zero " ) ;
HCL_STACK_PUSH ( hcl , HCL_SMOOI_TO_OOP ( 0 ) ) ;
break ;
case HCL_CODE_PUSH_ONE :
LOG_INST_0 ( hcl , " push_one " ) ;
HCL_STACK_PUSH ( hcl , HCL_SMOOI_TO_OOP ( 1 ) ) ;
break ;
case HCL_CODE_PUSH_TWO :
LOG_INST_0 ( hcl , " push_two " ) ;
HCL_STACK_PUSH ( hcl , HCL_SMOOI_TO_OOP ( 2 ) ) ;
break ;
case HCL_CODE_PUSH_INTLIT :
FETCH_PARAM_CODE_TO ( hcl , b1 ) ;
LOG_INST_1 ( hcl , " push_intlit %zu " , b1 ) ;
HCL_STACK_PUSH ( hcl , HCL_SMOOI_TO_OOP ( b1 ) ) ;
break ;
case HCL_CODE_PUSH_NEGINTLIT :
{
hcl_ooi_t num ;
FETCH_PARAM_CODE_TO ( hcl , b1 ) ;
num = b1 ;
LOG_INST_1 ( hcl , " push_negintlit %zu " , b1 ) ;
HCL_STACK_PUSH ( hcl , HCL_SMOOI_TO_OOP ( - num ) ) ;
break ;
}
case HCL_CODE_PUSH_CHARLIT :
FETCH_PARAM_CODE_TO ( hcl , b1 ) ;
LOG_INST_1 ( hcl , " push_charlit %zu " , b1 ) ;
HCL_STACK_PUSH ( hcl , HCL_CHAR_TO_OOP ( b1 ) ) ;
break ;
/* -------------------------------------------------------- */
2018-02-06 13:52:58 +00:00
case HCL_CODE_MAKE_ARRAY :
{
hcl_oop_t t ;
FETCH_PARAM_CODE_TO ( hcl , b1 ) ;
LOG_INST_1 ( hcl , " make_array %zu " , b1 ) ;
/* create an empty array */
2021-01-03 13:51:23 +00:00
t = hcl_makearray ( hcl , b1 , 0 ) ;
2021-01-31 18:46:13 +00:00
if ( HCL_UNLIKELY ( ! t ) )
{
supplement_errmsg ( hcl , fetched_instruction_pointer ) ;
goto oops ;
}
2018-02-06 13:52:58 +00:00
HCL_STACK_PUSH ( hcl , t ) ; /* push the array created */
break ;
}
case HCL_CODE_POP_INTO_ARRAY :
{
hcl_oop_t t1 , t2 ;
FETCH_PARAM_CODE_TO ( hcl , b1 ) ;
LOG_INST_1 ( hcl , " pop_into_array %zu " , b1 ) ;
t1 = HCL_STACK_GETTOP ( hcl ) ; /* value to store */
HCL_STACK_POP ( hcl ) ;
t2 = HCL_STACK_GETTOP ( hcl ) ; /* array */
2021-01-24 15:45:28 +00:00
if ( HCL_UNLIKELY ( b1 > = HCL_OBJ_GET_SIZE ( t2 ) ) )
{
hcl_seterrbfmt ( hcl , HCL_ECALL , " index %zu out of upper bound %zd " , b1 , ( hcl_oow_t ) HCL_OBJ_GET_SIZE ( t2 ) ) ;
goto oops ;
}
2018-02-06 13:52:58 +00:00
( ( hcl_oop_oop_t ) t2 ) - > slot [ b1 ] = t1 ;
break ;
}
2018-02-07 13:55:22 +00:00
case HCL_CODE_MAKE_BYTEARRAY :
{
hcl_oop_t t ;
FETCH_PARAM_CODE_TO ( hcl , b1 ) ;
LOG_INST_1 ( hcl , " make_bytearray %zu " , b1 ) ;
/* create an empty array */
2021-01-03 13:51:23 +00:00
t = hcl_makebytearray ( hcl , HCL_NULL , b1 ) ;
2021-01-31 18:46:13 +00:00
if ( HCL_UNLIKELY ( ! t ) )
{
supplement_errmsg ( hcl , fetched_instruction_pointer ) ;
goto oops ;
}
2018-02-07 13:55:22 +00:00
HCL_STACK_PUSH ( hcl , t ) ; /* push the byte array created */
break ;
}
case HCL_CODE_POP_INTO_BYTEARRAY :
{
hcl_oop_t t1 , t2 ;
hcl_ooi_t bv ;
FETCH_PARAM_CODE_TO ( hcl , b1 ) ;
LOG_INST_1 ( hcl , " pop_into_bytearray %zu " , b1 ) ;
t1 = HCL_STACK_GETTOP ( hcl ) ; /* value to store */
if ( ! HCL_OOP_IS_SMOOI ( t1 ) | | ( bv = HCL_OOP_TO_SMOOI ( t1 ) ) < 0 | | bv > 255 )
{
hcl_seterrbfmt ( hcl , HCL_ERANGE , " not a byte or out of byte range - %O " , t1 ) ;
2018-02-12 10:50:44 +00:00
goto oops ;
2018-02-07 13:55:22 +00:00
}
HCL_STACK_POP ( hcl ) ;
t2 = HCL_STACK_GETTOP ( hcl ) ; /* array */
( ( hcl_oop_byte_t ) t2 ) - > slot [ b1 ] = bv ;
break ;
}
2018-02-07 10:55:20 +00:00
case HCL_CODE_MAKE_DIC :
2018-02-06 13:52:58 +00:00
{
hcl_oop_t t ;
FETCH_PARAM_CODE_TO ( hcl , b1 ) ;
2018-02-07 10:55:20 +00:00
LOG_INST_1 ( hcl , " make_dic %zu " , b1 ) ;
2021-01-03 13:51:23 +00:00
t = ( hcl_oop_t ) hcl_makedic ( hcl , b1 + 10 ) ;
2021-01-31 18:46:13 +00:00
if ( HCL_UNLIKELY ( ! t ) )
{
supplement_errmsg ( hcl , fetched_instruction_pointer ) ;
goto oops ;
}
2018-02-06 13:52:58 +00:00
HCL_STACK_PUSH ( hcl , t ) ;
break ;
}
2018-02-07 10:55:20 +00:00
case HCL_CODE_POP_INTO_DIC :
2018-02-06 13:52:58 +00:00
{
hcl_oop_t t1 , t2 , t3 ;
2018-02-07 10:55:20 +00:00
LOG_INST_0 ( hcl , " pop_into_dic " ) ;
2018-02-06 13:52:58 +00:00
t1 = HCL_STACK_GETTOP ( hcl ) ; /* value */
HCL_STACK_POP ( hcl ) ;
t2 = HCL_STACK_GETTOP ( hcl ) ; /* key */
HCL_STACK_POP ( hcl ) ;
t3 = HCL_STACK_GETTOP ( hcl ) ; /* dictionary */
2021-01-03 13:51:23 +00:00
if ( ! hcl_putatdic ( hcl , ( hcl_oop_dic_t ) t3 , t2 , t1 ) ) goto oops ;
break ;
}
2021-01-24 15:45:28 +00:00
case HCL_CODE_MAKE_CONS :
2021-01-03 13:51:23 +00:00
{
hcl_oop_t t ;
2021-01-24 15:45:28 +00:00
LOG_INST_0 ( hcl , " make_cons " ) ;
2021-01-03 13:51:23 +00:00
2021-01-24 15:45:28 +00:00
t = hcl_makecons ( hcl , hcl - > _nil , hcl - > _nil ) ;
2021-01-31 18:46:13 +00:00
if ( HCL_UNLIKELY ( ! t ) )
{
supplement_errmsg ( hcl , fetched_instruction_pointer ) ;
goto oops ;
}
2021-01-03 13:51:23 +00:00
2021-01-24 15:45:28 +00:00
HCL_STACK_PUSH ( hcl , t ) ; /* push the head cons cell */
HCL_STACK_PUSH ( hcl , hcl - > _nil ) ; /* sentinnel */
2021-01-03 13:51:23 +00:00
break ;
}
2021-01-24 15:45:28 +00:00
case HCL_CODE_POP_INTO_CONS :
2021-01-03 13:51:23 +00:00
{
2021-01-24 15:45:28 +00:00
hcl_oop_t t1 , t2 , t3 ;
LOG_INST_0 ( hcl , " pop_into_cons " ) ;
t1 = HCL_STACK_GETTOP ( hcl ) ; /* value to store */
HCL_STACK_POP ( hcl ) ;
t3 = HCL_STACK_GETTOP ( hcl ) ; /* sentinnel */
HCL_STACK_POP ( hcl ) ;
t2 = HCL_STACK_GETTOP ( hcl ) ; /* head cons */
if ( HCL_UNLIKELY ( ! HCL_IS_CONS ( hcl , t2 ) ) )
{
hcl_seterrbfmt ( hcl , HCL_EINTERN , " internal error - invalid vm state detected in pop_into_cons " ) ;
goto oops ;
}
if ( t3 = = hcl - > _nil )
{
( ( hcl_oop_oop_t ) t2 ) - > slot [ 0 ] = t1 ;
HCL_STACK_PUSH ( hcl , t2 ) ; /* push self again */
}
else
{
hcl_oop_t t ;
hcl_pushvolat ( hcl , & t3 ) ;
t = hcl_makecons ( hcl , t1 , hcl - > _nil ) ;
hcl_popvolat ( hcl ) ;
if ( HCL_UNLIKELY ( ! t ) ) goto oops ;
( ( hcl_oop_oop_t ) t3 ) - > slot [ 1 ] = t ;
HCL_STACK_PUSH ( hcl , t ) ;
}
break ;
}
case HCL_CODE_POP_INTO_CONS_END :
{
hcl_oop_t t1 , t2 , t3 ;
LOG_INST_0 ( hcl , " pop_into_cons_end " ) ;
t1 = HCL_STACK_GETTOP ( hcl ) ; /* value to store */
HCL_STACK_POP ( hcl ) ;
t3 = HCL_STACK_GETTOP ( hcl ) ; /* sentinnel */
HCL_STACK_POP ( hcl ) ;
t2 = HCL_STACK_GETTOP ( hcl ) ; /* head cons */
if ( HCL_UNLIKELY ( ! HCL_IS_CONS ( hcl , t2 ) ) )
{
hcl_seterrbfmt ( hcl , HCL_EINTERN , " internal error - invalid vm state detected in pop_into_cons " ) ;
goto oops ;
}
if ( t3 = = hcl - > _nil )
{
( ( hcl_oop_oop_t ) t2 ) - > slot [ 0 ] = t1 ;
}
else
{
hcl_oop_t t ;
hcl_pushvolat ( hcl , & t3 ) ;
t = hcl_makecons ( hcl , t1 , hcl - > _nil ) ;
hcl_popvolat ( hcl ) ;
if ( HCL_UNLIKELY ( ! t ) ) goto oops ;
( ( hcl_oop_oop_t ) t3 ) - > slot [ 1 ] = t ;
}
break ;
}
case HCL_CODE_POP_INTO_CONS_CDR :
{
hcl_oop_t t1 , t2 , t3 ;
LOG_INST_0 ( hcl , " pop_into_cons_end " ) ;
2021-01-03 13:51:23 +00:00
t1 = HCL_STACK_GETTOP ( hcl ) ; /* value to store */
HCL_STACK_POP ( hcl ) ;
2021-01-24 15:45:28 +00:00
t3 = HCL_STACK_GETTOP ( hcl ) ; /* sentinnel */
HCL_STACK_POP ( hcl ) ;
t2 = HCL_STACK_GETTOP ( hcl ) ; /* head cons */
if ( HCL_UNLIKELY ( ! HCL_IS_CONS ( hcl , t2 ) ) )
{
hcl_seterrbfmt ( hcl , HCL_EINTERN , " internal error - invalid vm state detected in pop_into_cons " ) ;
goto oops ;
}
if ( t3 = = hcl - > _nil )
{
( ( hcl_oop_oop_t ) t2 ) - > slot [ 1 ] = t1 ;
}
else
{
( ( hcl_oop_oop_t ) t3 ) - > slot [ 1 ] = t1 ;
}
/* no push back of the sentinnel */
2018-02-06 13:52:58 +00:00
break ;
}
/* -------------------------------------------------------- */
2020-09-22 09:19:53 +00:00
case HCL_CODE_DUP_STACKTOP :
2016-10-04 17:56:28 +00:00
{
hcl_oop_t t ;
LOG_INST_0 ( hcl , " dup_stacktop " ) ;
2018-02-05 10:43:25 +00:00
HCL_ASSERT ( hcl , ! HCL_STACK_ISEMPTY ( hcl ) ) ;
2016-10-04 17:56:28 +00:00
t = HCL_STACK_GETTOP ( hcl ) ;
HCL_STACK_PUSH ( hcl , t ) ;
break ;
}
case HCL_CODE_POP_STACKTOP :
LOG_INST_0 ( hcl , " pop_stacktop " ) ;
2018-02-05 10:43:25 +00:00
HCL_ASSERT ( hcl , ! HCL_STACK_ISEMPTY ( hcl ) ) ;
2018-02-22 07:41:03 +00:00
/* at the top level, the value is just popped off the stack
2020-10-08 09:25:54 +00:00
* after evaluation of an expression . so it ' s likely the
2018-02-22 07:41:03 +00:00
* return value of the last expression unless explicit
* returning is performed */
hcl - > last_retv = HCL_STACK_GETTOP ( hcl ) ;
2016-10-04 17:56:28 +00:00
HCL_STACK_POP ( hcl ) ;
break ;
2020-09-22 09:19:53 +00:00
case HCL_CODE_RETURN_STACKTOP :
2016-10-04 17:56:28 +00:00
LOG_INST_0 ( hcl , " return_stacktop " ) ;
return_value = HCL_STACK_GETTOP ( hcl ) ;
HCL_STACK_POP ( hcl ) ;
goto handle_return ;
2020-09-22 09:19:53 +00:00
case HCL_CODE_RETURN_RECEIVER :
2016-10-04 17:56:28 +00:00
LOG_INST_0 ( hcl , " return_receiver " ) ;
2020-10-04 18:21:05 +00:00
return_value = hcl - > active_context - > origin - > receiver_or_base ;
2016-10-04 17:56:28 +00:00
handle_return :
2020-10-08 09:25:54 +00:00
hcl - > last_retv = return_value ;
2020-10-10 17:36:33 +00:00
if ( do_return ( hcl , return_value ) < = - 1 ) goto oops ;
2016-10-04 17:56:28 +00:00
break ;
case HCL_CODE_RETURN_FROM_BLOCK :
LOG_INST_0 ( hcl , " return_from_block " ) ;
2018-02-15 15:36:15 +00:00
HCL_ASSERT ( hcl , HCL_IS_CONTEXT ( hcl , hcl - > active_context ) ) ;
2018-02-22 07:41:03 +00:00
hcl - > last_retv = HCL_STACK_GETTOP ( hcl ) ;
2020-10-10 17:36:33 +00:00
2020-10-13 14:44:00 +00:00
do_return_from_block ( hcl ) ;
2016-10-04 17:56:28 +00:00
break ;
2020-10-04 18:21:05 +00:00
case HCL_CODE_MAKE_FUNCTION :
2016-10-04 17:56:28 +00:00
{
2020-10-04 18:21:05 +00:00
hcl_oop_function_t func ;
hcl_oow_t b3 , b4 , i , j ;
hcl_oow_t joff ;
2016-10-04 17:56:28 +00:00
/* b1 - number of block arguments
2020-10-04 18:21:05 +00:00
* b2 - number of block temporaries
* b3 - literal frame base
* b4 - literal frame size */
2016-10-04 17:56:28 +00:00
FETCH_PARAM_CODE_TO ( hcl , b1 ) ;
FETCH_PARAM_CODE_TO ( hcl , b2 ) ;
2020-10-04 18:21:05 +00:00
FETCH_PARAM_CODE_TO ( hcl , b3 ) ;
FETCH_PARAM_CODE_TO ( hcl , b4 ) ;
2016-10-04 17:56:28 +00:00
2020-10-04 18:21:05 +00:00
LOG_INST_4 ( hcl , " make_function %zu %zu %zu %zu " , b1 , b2 , b3 , b4 ) ;
2016-10-04 17:56:28 +00:00
2018-02-05 10:43:25 +00:00
HCL_ASSERT ( hcl , b1 > = 0 ) ;
HCL_ASSERT ( hcl , b2 > = b1 ) ;
2020-10-04 18:21:05 +00:00
/* the MAKE_FUNCTION instruction is followed by the long JUMP_FORWARD_X instruction.
* i can decode the instruction and get the size of instructions
* of the block context */
HCL_ASSERT ( hcl , hcl - > active_code [ hcl - > ip ] = = HCL_CODE_JUMP_FORWARD_X ) ;
joff = hcl - > active_code [ hcl - > ip + 1 ] ;
2021-01-29 12:39:31 +00:00
# if (HCL_CODE_LONG_PARAM_SIZE == 2)
2020-10-04 18:21:05 +00:00
joff = ( joff < < 8 ) | hcl - > active_code [ hcl - > ip + 2 ] ;
# endif
2016-10-04 17:56:28 +00:00
2020-10-04 18:21:05 +00:00
/* copy the byte codes from the active context to the new context */
2021-01-29 12:39:31 +00:00
# if (HCL_CODE_LONG_PARAM_SIZE == 2)
func = make_function ( hcl , b4 , & hcl - > active_code [ hcl - > ip + 3 ] , joff , HCL_NULL ) ;
2020-10-04 18:21:05 +00:00
# else
2021-01-29 12:39:31 +00:00
func = make_function ( hcl , b4 , & hcl - > active_code [ hcl - > ip + 2 ] , joff , HCL_NULL ) ;
2020-10-04 18:21:05 +00:00
# endif
if ( HCL_UNLIKELY ( ! func ) ) goto oops ;
2020-09-19 11:55:58 +00:00
2020-10-05 14:49:54 +00:00
fill_function_data ( hcl , func , b1 , b2 , hcl - > active_context , & hcl - > active_function - > literal_frame [ b3 ] , b4 ) ;
2020-09-19 11:55:58 +00:00
2020-10-04 18:21:05 +00:00
/* push the new function to the stack of the active context */
HCL_STACK_PUSH ( hcl , ( hcl_oop_t ) func ) ;
break ;
}
2020-09-19 11:55:58 +00:00
2020-10-04 18:21:05 +00:00
case HCL_CODE_MAKE_BLOCK :
{
2020-10-09 07:14:32 +00:00
hcl_oop_block_t blkobj ;
/* b1 - number of block arguments
* b2 - number of block temporaries */
FETCH_PARAM_CODE_TO ( hcl , b1 ) ;
FETCH_PARAM_CODE_TO ( hcl , b2 ) ;
LOG_INST_2 ( hcl , " make_block %zu %zu " , b1 , b2 ) ;
HCL_ASSERT ( hcl , b1 > = 0 ) ;
HCL_ASSERT ( hcl , b2 > = b1 ) ;
blkobj = make_block ( hcl ) ;
if ( HCL_UNLIKELY ( ! blkobj ) ) goto oops ;
/* the long forward jump instruction has the format of
* 11000100 KKKKKKKK or 11000100 KKKKKKKK KKKKKKKK
2021-01-29 12:39:31 +00:00
* depending on HCL_CODE_LONG_PARAM_SIZE . change ' ip ' to point to
2020-10-09 07:14:32 +00:00
* the instruction after the jump . */
2021-01-29 12:39:31 +00:00
fill_block_data ( hcl , blkobj , b1 , b2 , hcl - > ip + HCL_CODE_LONG_PARAM_SIZE + 1 , hcl - > active_context ) ;
2020-10-09 07:14:32 +00:00
/* push the new block context to the stack of the active context */
HCL_STACK_PUSH ( hcl , ( hcl_oop_t ) blkobj ) ;
2016-10-04 17:56:28 +00:00
break ;
}
case HCL_CODE_NOOP :
/* do nothing */
LOG_INST_0 ( hcl , " noop " ) ;
break ;
default :
HCL_LOG1 ( hcl , HCL_LOG_IC | HCL_LOG_FATAL , " Fatal error - unknown byte code 0x%zx \n " , bcode ) ;
2018-02-05 10:43:25 +00:00
hcl_seterrnum ( hcl , HCL_EINTERN ) ;
2016-10-04 17:56:28 +00:00
goto oops ;
}
}
done :
2020-12-31 17:48:47 +00:00
hcl - > gci . lazy_sweep = 1 ;
2016-10-04 17:56:28 +00:00
vm_cleanup ( hcl ) ;
# if defined(HCL_PROFILE_VM)
2018-02-22 07:41:03 +00:00
HCL_LOG1 ( hcl , HCL_LOG_IC | HCL_LOG_INFO , " TOTAL INST COUTNER = %zu \n " , inst_counter ) ;
2016-10-04 17:56:28 +00:00
# endif
return 0 ;
oops :
2020-12-31 17:48:47 +00:00
hcl - > gci . lazy_sweep = 1 ;
2016-10-04 17:56:28 +00:00
/* TODO: anything to do here? */
2018-02-12 10:50:44 +00:00
if ( hcl - > processor - > active ! = hcl - > nil_process )
{
2018-02-22 07:41:03 +00:00
HCL_LOG1 ( hcl , HCL_LOG_IC | HCL_LOG_INFO , " TERMINATING ACTIVE PROCESS %zd for execution error \n " , HCL_OOP_TO_SMOOI ( hcl - > processor - > active - > id ) ) ;
2018-02-12 10:50:44 +00:00
terminate_process ( hcl , hcl - > processor - > active ) ;
}
2016-10-04 17:56:28 +00:00
return - 1 ;
}
2020-10-08 09:25:54 +00:00
hcl_oop_t hcl_execute ( hcl_t * hcl )
2016-10-04 17:56:28 +00:00
{
2020-10-08 09:25:54 +00:00
hcl_oop_function_t func ;
2018-04-26 04:39:20 +00:00
int n ;
hcl_bitmask_t log_default_type_mask ;
2018-02-08 15:04:07 +00:00
2018-03-11 11:16:28 +00:00
HCL_ASSERT ( hcl , hcl - > code . bc . len < HCL_SMOOI_MAX ) ; /* asserted by the compiler */
2018-02-08 15:04:07 +00:00
log_default_type_mask = hcl - > log . default_type_mask ;
hcl - > log . default_type_mask | = HCL_LOG_VM ;
2016-10-04 17:56:28 +00:00
2018-02-05 10:43:25 +00:00
HCL_ASSERT ( hcl , hcl - > initial_context = = HCL_NULL ) ;
HCL_ASSERT ( hcl , hcl - > active_context = = HCL_NULL ) ;
2016-10-04 17:56:28 +00:00
2020-10-08 09:25:54 +00:00
/* the code generated doesn't cater for its use as an initial funtion.
* mutate the generated code so that the intiail function can break
* out of the execution loop in execute ( ) smoothly */
2020-10-10 17:36:33 +00:00
2020-10-13 14:44:00 +00:00
if ( hcl - > code . bc . len > 0 )
{
HCL_ASSERT ( hcl , hcl - > code . bc . ptr [ hcl - > code . bc . len - 1 ] = = HCL_CODE_POP_STACKTOP ) ;
# if 1
/* append RETURN_FROM_BLOCK
if ( hcl_emitbyteinstruction ( hcl , HCL_CODE_RETURN_FROM_BLOCK ) < = - 1 ) return - 1 ; */
/* substitute RETURN_FROM_BLOCK for POP_STACKTOP) */
hcl - > code . bc . ptr [ hcl - > code . bc . len - 1 ] = HCL_CODE_RETURN_FROM_BLOCK ;
# else
/* substitute RETURN_STACKTOP for POP_STACKTOP) */
hcl - > code . bc . ptr [ hcl - > code . bc . len - 1 ] = HCL_CODE_RETURN_STACKTOP ;
# endif
}
2020-10-08 09:25:54 +00:00
2021-01-26 10:10:18 +00:00
/* create a virtual function object that hold the bytes codes generated */
2021-02-01 03:32:09 +00:00
func = make_function ( hcl , hcl - > code . lit . len , hcl - > code . bc . ptr , hcl - > code . bc . len , hcl - > code . dbgi ) ;
2020-10-08 09:25:54 +00:00
if ( HCL_UNLIKELY ( ! func ) ) return HCL_NULL ;
/* pass nil for the home context of the initial function */
fill_function_data ( hcl , func , 0 , 0 , ( hcl_oop_context_t ) hcl - > _nil , hcl - > code . lit . arr - > slot , hcl - > code . lit . len ) ;
2020-10-13 14:44:00 +00:00
hcl - > initial_function = func ; /* the initial function is ready */
2020-10-08 09:25:54 +00:00
2020-10-15 12:57:05 +00:00
#if 0
/* unless the system is buggy, hcl->proc_map_used should be 0.
* the standard library terminates all processes before halting .
*
* [ EXPERIMENTAL ]
* if you like the process allocation to start from 0 , uncomment
* the following ' if ' block */
if ( hcl - > proc_map_capa > 0 & & hcl - > proc_map_used = = 0 )
{
/* rechain the process map. it must be compatible with prepare_to_alloc_pid().
* by placing the low indiced slot at the beginning of the free list ,
* the special processes ( main_proc , gcfin_proc , ossig_proc ) are allocated
* with low process IDs . */
hcl_ooi_t i , j ;
hcl - > proc_map_free_first = 0 ;
for ( i = 0 , j = 1 ; j < hcl - > proc_map_capa ; i + + , j + + )
{
hcl - > proc_map [ i ] = HCL_SMOOI_TO_OOP ( j ) ;
}
hcl - > proc_map [ i ] = HCL_SMOOI_TO_OOP ( - 1 ) ;
hcl - > proc_map_free_last = i ;
}
# endif
2020-10-13 14:44:00 +00:00
n = start_initial_process_and_context ( hcl , 0 ) ; /* set up the initial context over the initial function */
2020-10-04 18:21:05 +00:00
if ( n > = 0 )
{
2020-10-13 14:44:00 +00:00
hcl - > last_retv = hcl - > _nil ;
2020-10-04 18:21:05 +00:00
n = execute ( hcl ) ;
HCL_INFO1 ( hcl , " RETURNED VALUE - %O \n " , hcl - > last_retv ) ;
}
2018-02-22 07:41:03 +00:00
2016-10-04 17:56:28 +00:00
hcl - > initial_context = HCL_NULL ;
hcl - > active_context = HCL_NULL ;
2020-12-31 19:03:37 +00:00
HCL_ASSERT ( hcl , hcl - > processor - > total_count = = HCL_SMOOI_TO_OOP ( 0 ) ) ;
HCL_ASSERT ( hcl , hcl - > processor - > active = = hcl - > nil_process ) ;
LOAD_ACTIVE_SP ( hcl ) ; /* sync hcl->nil_process->sp with hcl->sp */
HCL_ASSERT ( hcl , hcl - > sp = = - 1 ) ;
2018-02-08 15:04:07 +00:00
2020-12-31 17:48:47 +00:00
# if defined(HCL_PROFILE_VM)
HCL_LOG2 ( hcl , HCL_LOG_IC | HCL_LOG_INFO , " GC - gci.bsz: %zu, gci.stack.max: %zu \n " , hcl - > gci . bsz , hcl - > gci . stack . max ) ;
if ( hcl - > heap - > xma ) hcl_xma_dump ( hcl - > heap - > xma , xma_dumper , hcl ) ;
HCL_LOG2 ( hcl , HCL_LOG_IC | HCL_LOG_INFO , " GC - gci.stat.alloc: %ld.%09u \n " , ( unsigned long int ) hcl - > gci . stat . alloc . sec , ( unsigned int ) hcl - > gci . stat . alloc . nsec ) ;
HCL_LOG2 ( hcl , HCL_LOG_IC | HCL_LOG_INFO , " GC - gci.stat.mark: %ld.%09u \n " , ( unsigned long int ) hcl - > gci . stat . mark . sec , ( unsigned int ) hcl - > gci . stat . mark . nsec ) ;
HCL_LOG2 ( hcl , HCL_LOG_IC | HCL_LOG_INFO , " GC - gci.stat.sweep: %ld.%09u \n " , ( unsigned long int ) hcl - > gci . stat . sweep . sec , ( unsigned int ) hcl - > gci . stat . sweep . nsec ) ;
# endif
2018-02-08 15:04:07 +00:00
hcl - > log . default_type_mask = log_default_type_mask ;
2018-02-22 12:57:31 +00:00
return ( n < = - 1 ) ? HCL_NULL : hcl - > last_retv ;
2016-10-04 17:56:28 +00:00
}
2016-09-28 14:40:37 +00:00
2018-03-10 17:53:44 +00:00
void hcl_abort ( hcl_t * hcl )
{
hcl - > abort_req = 1 ;
}
2021-02-01 13:20:46 +00:00
/* ------------------------------------------------------------------------- */
hcl_pfrc_t hcl_pf_process_fork ( hcl_t * hcl , hcl_mod_t * mod , hcl_ooi_t nargs )
{
hcl_oop_t blk ;
hcl_oop_context_t newctx ;
hcl_oop_process_t newprc ;
blk = ( hcl_oop_t ) HCL_STACK_GETARG ( hcl , nargs , 0 ) ;
if ( ! HCL_IS_BLOCK ( hcl , blk ) )
{
hcl_seterrbfmt ( hcl , HCL_EINVAL , " parameter not block - %O " , blk ) ;
return HCL_PF_FAILURE ;
}
/* TODO: fill arguments. check argument count... */
newctx = make_context ( hcl , 0 ) ;
if ( HCL_UNLIKELY ( ! newctx ) ) return HCL_PF_FAILURE ;
newprc = make_process ( hcl , newctx ) ;
if ( HCL_UNLIKELY ( ! newprc ) ) return HCL_PF_FAILURE ;
chain_into_processor ( hcl , newprc , PROC_STATE_RUNNABLE ) ;
HCL_STACK_SETRET ( hcl , nargs , ( hcl_oop_t ) newprc ) ;
return HCL_PF_SUCCESS ;
}
hcl_pfrc_t hcl_pf_process_resume ( hcl_t * hcl , hcl_mod_t * mod , hcl_ooi_t nargs )
{
hcl_oop_process_t prc ;
prc = ( hcl_oop_process_t ) HCL_STACK_GETARG ( hcl , nargs , 0 ) ;
if ( ! HCL_IS_PROCESS ( hcl , prc ) )
{
hcl_seterrbfmt ( hcl , HCL_EINVAL , " parameter not process - %O " , prc ) ;
return HCL_PF_FAILURE ;
}
resume_process ( hcl , prc ) ;
return HCL_PF_SUCCESS ;
}
hcl_pfrc_t hcl_pf_process_yield ( hcl_t * hcl , hcl_mod_t * mod , hcl_ooi_t nargs )
{
yield_process ( hcl , hcl - > processor - > active ) ;
return HCL_PF_SUCCESS ;
}
hcl_pfrc_t hcl_pf_process_suspend ( hcl_t * hcl , hcl_mod_t * mod , hcl_ooi_t nargs )
{
hcl_oop_process_t prc ;
if ( nargs > = 1 )
{
prc = ( hcl_oop_process_t ) HCL_STACK_GETARG ( hcl , nargs , 0 ) ;
if ( ! HCL_IS_PROCESS ( hcl , prc ) )
{
hcl_seterrbfmt ( hcl , HCL_EINVAL , " parameter not process - %O " , prc ) ;
return HCL_PF_FAILURE ;
}
}
else
{
prc = hcl - > processor - > active ;
}
suspend_process ( hcl , prc ) ;
return HCL_PF_SUCCESS ;
}
hcl_pfrc_t hcl_pf_process_sleep ( hcl_t * hcl , hcl_mod_t * mod , hcl_ooi_t nargs )
{
/* TODO: sleep the current process */
return HCL_PF_SUCCESS ;
}