2022-12-05 08:03:17 +00:00
# include "ipc_util.h"
# include <sys/ipc.h>
# include <sys/shm.h>
# include <sys/stat.h>
# include <sys/types.h>
# include <fcntl.h>
# include <string.h>
# include "log_util.h"
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// linux_event
unsigned long linux_event : : to_abs_time_us = 0 ;
linux_event : : linux_event ( const char * desc ) : waiting_ ( false ) , sem_ ( nullptr ) , desc_ ( desc ? desc : " " ) , first_ ( true ) , multi_proc_ ( false )
{
log_cls : : log ( LOG_LEVEL_ALL , " +linux_event(%p) unamed for '%s' constructing ... \n " , this , desc_ . c_str ( ) ) ;
err_ = sem_init ( & local_sem_ , 0 , 0 ) ;
if ( err_ = = - 1 )
{
err_ = errno ;
log_cls : : log ( LOG_LEVEL_FATAL , " %p: sem_init = %s \n " , this , strerror ( err_ ) ) ;
}
else
{
sem_ = & local_sem_ ;
}
}
linux_event : : linux_event ( const char * name , const char * desc ) : waiting_ ( false ) , sem_ ( nullptr ) , desc_ ( desc ? desc : " " ) , first_ ( true ) , multi_proc_ ( true )
{
log_cls : : log ( LOG_LEVEL_ALL , " +linux_event(%p) of named '%s' for '%s' constructing ... \n " , this , name , desc_ . c_str ( ) ) ;
sem_ = sem_open ( name , O_CREAT | O_EXCL , 0777 , 0 ) ;
if ( sem_ = = ( sem_t * ) SEM_FAILED )
{
sem_ = nullptr ;
err_ = errno ;
log_cls : : log ( LOG_LEVEL_FATAL , " %p: sem_open(O_CREAT | O_EXCL) = %s \n " , this , strerror ( err_ ) ) ;
if ( err_ = EEXIST )
{
sem_ = sem_open ( name , 0666 ) ;
if ( sem_ = = ( sem_t * ) SEM_FAILED )
{
err_ = errno ;
sem_ = nullptr ;
log_cls : : log ( LOG_LEVEL_FATAL , " %p: sem_open = %s \n " , this , strerror ( err_ ) ) ;
}
else
{
err_ = 0 ;
first_ = false ;
}
}
}
else
{
name_ = name ;
log_cls : : log ( LOG_LEVEL_DEBUG , " %p: created named sem OK. \n " , this ) ;
err_ = sem_init ( sem_ , 1 , 0 ) ; // this is used to initialize the event count, whether named or unamed
if ( err_ = = - 1 )
{
err_ = errno ;
log_cls : : log ( LOG_LEVEL_FATAL , " %p: sem_init = %s \n " , this , strerror ( err_ ) ) ;
sem_close ( sem_ ) ;
sem_ = nullptr ;
sem_unlink ( name ) ;
}
}
}
linux_event : : linux_event ( sem_t * mem_sem , bool first , const char * desc ) : waiting_ ( false ) , sem_ ( mem_sem ) , desc_ ( desc ? desc : " " ) , first_ ( first ) , multi_proc_ ( true )
{
log_cls : : log ( LOG_LEVEL_ALL , " +linux_event(%p) at mem(%p) for '%s' constructing ... \n " , this , mem_sem , desc_ . c_str ( ) ) ;
if ( first )
{
err_ = sem_init ( sem_ , 1 , 0 ) ;
if ( err_ = = - 1 )
{
err_ = errno ;
log_cls : : log ( LOG_LEVEL_FATAL , " %p: sem_init = %s \n " , this , strerror ( err_ ) ) ;
}
}
}
linux_event : : ~ linux_event ( )
{
if ( sem_ )
{
char ptr [ 40 ] = { 0 } ;
std : : string tips ( " " ) ;
sprintf ( ptr , " ~%p: " , this ) ;
tips = ptr ;
if ( sem_ = = & local_sem_ | | ( first_ & & name_ . empty ( ) ) )
{
err_ = log_cls : : log_when_err ( sem_destroy ( sem_ ) , ( tips + " sem_destroy " ) . c_str ( ) ) ;
}
else
{
err_ = log_cls : : log_when_err ( sem_close ( sem_ ) , ( tips + " sem_close " ) . c_str ( ) ) ;
// else // why not else ? we should ensure delete the kernel object when unused.
if ( ! name_ . empty ( ) ) // i am the named object owner !
{
err_ = log_cls : : log_when_err ( sem_unlink ( name_ . c_str ( ) ) , ( tips + " sem_unlink " ) . c_str ( ) , LOG_LEVEL_FATAL ) ; // This will cause previously opened objects to never receive events, even if you reopen it.
}
}
}
log_cls : : log ( LOG_LEVEL_ALL , " -linux_event(%p) destroyed. \n " , this ) ;
}
int32_t linux_event : : clear_named_event ( const char * name )
{
sem_t * sem = sem_open ( name , O_CREAT | O_EXCL , 0777 , 0 ) ;
int32_t err = 0 ;
if ( sem = = ( sem_t * ) SEM_FAILED )
{
if ( errno = = EEXIST )
{
err = sem_unlink ( name ) ;
if ( err = = - 1 )
err = errno ;
}
else
{
return 0 ;
}
}
else
{
sem_close ( sem ) ;
sem_unlink ( name ) ;
}
return err ;
}
void linux_event : : reset_calc_abs_time ( unsigned us )
{
if ( us = = - 1 )
{
struct timeval now = { 0 } , after = { 0 } ;
struct timespec abst = { 0 } ;
linux_event : : to_abs_time_us = 10 ;
if ( chronograph : : now ( & now ) )
{
abst . tv_sec = now . tv_sec ;
abst . tv_nsec = USEC_2_NS ( now . tv_usec ) ;
abst . tv_nsec + = MSEC_2_NS ( 1 ) + linux_event : : to_abs_time_us ;
// overflow ...
abst . tv_sec + = abst . tv_nsec / SEC_2_NS ( 1 ) ;
abst . tv_nsec % = SEC_2_NS ( 1 ) ;
if ( chronograph : : now ( & after ) )
{
if ( after . tv_usec > now . tv_usec )
linux_event : : to_abs_time_us = after . tv_usec - now . tv_usec ;
else
linux_event : : to_abs_time_us = SEC_2_US ( 1 ) + after . tv_usec - now . tv_usec ;
}
}
}
else
{
linux_event : : to_abs_time_us = us ;
}
}
bool linux_event : : abs_time_after ( struct timespec * abstm , unsigned ms )
{
struct timeval now = { 0 } ;
if ( ! chronograph : : now ( & now ) )
{
log_cls : : log ( LOG_LEVEL_FATAL , " gettimeofday faied: %s \n ! " , strerror ( errno ) ) ;
time ( & now . tv_sec ) ;
}
abstm - > tv_sec = now . tv_sec ;
abstm - > tv_nsec = USEC_2_NS ( now . tv_usec ) ;
abstm - > tv_nsec + = MSEC_2_NS ( ms ) + USEC_2_NS ( linux_event : : to_abs_time_us ) ;
// overflow ...
abstm - > tv_sec + = abstm - > tv_nsec / SEC_2_NS ( 1 ) ;
abstm - > tv_nsec % = SEC_2_NS ( 1 ) ;
return true ;
}
bool linux_event : : is_ready ( void )
{
return sem_ ! = nullptr ;
}
bool linux_event : : is_named_first ( void )
{
return ! name_ . empty ( ) ;
}
bool linux_event : : wait_try ( void )
{
return sem_trywait ( sem_ ) = = 0 ;
}
bool linux_event : : wait ( unsigned timeout )
{
bool waited = true ;
log_cls : : log ( LOG_LEVEL_ALL , " linux_event(%p): waiting(%u) ... \n " , this , timeout ) ;
waiting_ = true ;
if ( timeout = = WAIT_INFINITE )
{
sem_wait ( sem_ ) ;
}
else
{
struct timespec to = { 0 } ;
linux_event : : abs_time_after ( & to , timeout ) ;
waited = sem_timedwait ( sem_ , & to ) = = 0 ;
}
waiting_ = false ;
log_cls : : log ( LOG_LEVEL_ALL , " linux_event(%p): waited(%u) = %d \n " , this , timeout , waited ) ;
return waited ;
}
void linux_event : : trigger ( void )
{
err_ = sem_post ( sem_ ) ;
if ( err_ )
err_ = errno ;
log_cls : : log ( LOG_LEVEL_ALL , " linux_event(%p): trigger = %s \n " , this , err_ = = 0 ? " OK " : strerror ( errno ) ) ;
}
void linux_event : : reset ( void )
{
err_ = sem_init ( sem_ , multi_proc_ , 0 ) ;
if ( err_ )
err_ = errno ;
log_cls : : log ( LOG_LEVEL_ALL , " linux_event(%p): reset = %s \n " , this , err_ = = 0 ? " OK " : strerror ( errno ) ) ;
}
bool linux_event : : is_waiting ( void )
{
return waiting_ ;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// shared_mem
uint64_t shared_mem : : mem_total_ = 0 ;
uint64_t shared_mem : : page_unit_ = 0 ;
uint64_t shared_mem : : huge_page_unit_ = 0 ;
shared_mem : : shared_mem ( ) : name_ ( " " ) , id_ ( 0 ) , size_ ( 0 ) , shm_buf_ ( shared_mem : : invalid_map_addr ( ) ) , first_ ( false ) , shm_id_ ( - 1 )
{
if ( shared_mem : : page_unit_ = = 0 )
shared_mem : : init_page_info ( ) ;
log_cls : : log ( LOG_LEVEL_ALL , " +shared_mem(%p) constructed, page size = %ld \n " , this , page_unit_ ) ;
}
shared_mem : : ~ shared_mem ( )
{
close ( ) ;
log_cls : : log ( LOG_LEVEL_ALL , " -shared_mem(%p) destroyed. \n " , this ) ;
}
void shared_mem : : init_page_info ( void )
{
shared_mem : : page_unit_ = sys_util : : get_page_size ( ) ;
// Hugepagesize: 2048 kB
if ( sys_util : : get_inf_file_data ( " /proc/meminfo " , 80 , " MemTotal: %ld " , & shared_mem : : mem_total_ ) )
shared_mem : : mem_total_ * = 1024 ;
if ( sys_util : : get_inf_file_data ( " /proc/meminfo " , 80 , " Hugepagesize: %ld " , & shared_mem : : huge_page_unit_ ) )
shared_mem : : huge_page_unit_ * = 1024 ;
log_cls : : log ( LOG_LEVEL_DEBUG , " TotalMemory: %s, system page size: %s, huge page size %s \n "
, sys_util : : format_readable_bytes ( shared_mem : : mem_total_ ) . c_str ( )
, sys_util : : format_readable_bytes ( shared_mem : : page_unit_ ) . c_str ( )
, sys_util : : format_readable_bytes ( shared_mem : : huge_page_unit_ ) . c_str ( ) ) ;
}
char * shared_mem : : invalid_map_addr ( void )
{
return ( char * ) - 1 ;
}
int32_t shared_mem : : open ( int32_t id , size_t * bytes , const char * name )
{
key_t key = ( key_t ) - 1 ; // ftok(name, id);
int32_t ret = close ( ) ;
size_t size = bytes ? * bytes : 0 ;
std : : string pe ( " " ) ;
if ( ret )
return ret ;
if ( ! name | | * name = = 0 )
{
pe = sys_util : : get_module_path ( ) ;
name = pe . c_str ( ) ;
}
key = ftok ( name , id ) ;
if ( key = = ( key_t ) - 1 )
{
log_cls : : log ( LOG_LEVEL_FATAL , " shared_memory(%p): ftok('%s', %d) = %s \n " , this , name , id , strerror ( errno ) ) ;
return errno ;
}
2023-02-18 03:26:43 +00:00
log_cls : : log ( LOG_LEVEL_DEBUG , " shared memory key: %p \n " , key ) ;
2022-12-05 08:03:17 +00:00
size = ALIGN_INT ( size , shared_mem : : page_unit_ ) ;
if ( ! bytes | | * bytes ! = size )
{
log_cls : : log ( LOG_LEVEL_DEBUG , " add %ld upto multiple of page size: %ld \n " , bytes ? * bytes : 0 , size ) ;
if ( bytes )
* bytes = size ;
}
shm_id_ = shmget ( key , size , IPC_EXCL | IPC_CREAT | 0600 ) ;
if ( shm_id_ = = - 1 )
{
ret = errno ;
log_cls : : log ( LOG_LEVEL_WARNING , " %p: create shared memory('%s', %d) failed: %s \n " , this , name , id , strerror ( ret ) ) ;
if ( ret = = EEXIST )
{
shm_id_ = shmget ( key , size , 0600 ) ;
if ( shm_id_ = = - 1 )
{
ret = errno ;
log_cls : : log ( LOG_LEVEL_WARNING , " %p: open shared memory('%s', %d) failed: %s \n " , this , name , id , strerror ( ret ) ) ;
}
else
{
ret = 0 ;
first_ = false ;
}
}
}
else // i created the shared memory ...
{
first_ = true ;
}
if ( ret = = 0 )
{
shm_buf_ = ( char * ) shmat ( shm_id_ , nullptr , 0 ) ;
if ( shm_buf_ = = shared_mem : : invalid_map_addr ( ) )
{
ret = errno ;
log_cls : : log ( LOG_LEVEL_WARNING , " %p: shmat failed: %s \n " , this , strerror ( ret ) ) ;
close ( ) ;
}
else
{
log_cls : : log ( LOG_LEVEL_DEBUG , " %p: %s shared memory('%s', %d) at %p(+%s) OK. \n " , this , first_ ? " create " : " open " , name , id , shm_buf_ , sys_util : : format_readable_bytes ( size ) . c_str ( ) ) ;
name_ = name ;
id_ = id ;
size_ = size ;
}
}
return ret ;
}
int32_t shared_mem : : close ( void )
{
int32_t ret = 0 ;
if ( shm_buf_ ! = shared_mem : : invalid_map_addr ( ) )
{
ret = log_cls : : log_when_err ( shmdt ( shm_buf_ ) , " shmdt " ) ;
if ( ret )
return ret ;
shm_buf_ = shared_mem : : invalid_map_addr ( ) ;
}
if ( first_ & & shm_id_ > = 0 )
{
ret = log_cls : : log_when_err ( shmctl ( shm_id_ , IPC_RMID , nullptr ) , " shmctrl(IPC_RMID) " ) ;
2023-02-18 03:26:43 +00:00
if ( ret & & ret ! = ENOENT )
2022-12-05 08:03:17 +00:00
{
// re-map buffer ...
shm_buf_ = ( char * ) shmat ( shm_id_ , nullptr , 0 ) ;
return ret ;
}
shm_id_ = - 1 ;
}
name_ = " " ;
id_ = 0 ;
first_ = false ;
size_ = 0 ;
return ret ;
}
char * shared_mem : : get_mem ( size_t * size )
{
if ( size )
* size = size_ ;
return shm_buf_ = = shared_mem : : invalid_map_addr ( ) ? nullptr : shm_buf_ ;
}
bool shared_mem : : is_first ( void )
{
return first_ ;
}
void shared_mem : : clear_kernel_object ( void )
{
log_cls : : log_when_err ( shmctl ( shm_id_ , IPC_RMID , nullptr ) , " shmctrl(IPC_RMID) " ) ;
}