ha/service-mgmt/sm-common/src/sm_selobj.c

337 lines
8.9 KiB
C

//
// Copyright (c) 2014,2023 Wind River Systems, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
#include "sm_selobj.h"
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/select.h>
#include "sm_limits.h"
#include "sm_types.h"
#include "sm_debug.h"
#include "sm_list.h"
#include "sm_util_types.h"
#define SM_SEL_OBJ_ENTRY_VALID 0xFDFDFDFD
typedef struct
{
uint32_t valid;
int selobj;
SmSelObjCallbackT callback;
int64_t user_data;
} SmSelObjSelectEntryT;
typedef struct
{
bool inuse;
pthread_t thread_id;
int last_selobj;
fd_set selobjs_set;
SmSelObjSelectEntryT selobjs[SM_THREAD_SELECT_OBJS_MAX];
} SmSelObjThreadInfoT;
static pthread_mutex_t selobj_mutex;
static SmSelObjThreadInfoT _threads[SM_THREADS_MAX];
SmErrorT sm_selobj_mutex_initialize ( void )
{
return sm_mutex_initialize(&selobj_mutex, false);
}
SmErrorT sm_selobj_mutex_finalize ( void )
{
return sm_mutex_finalize(&selobj_mutex);
}
// ****************************************************************************
// Selection Object - Find Thread Info
// ===================================
static SmSelObjThreadInfoT* sm_selobj_find_thread_info( void )
{
pthread_t thread_id = pthread_self();
unsigned int thread_i;
for( thread_i=0; SM_THREADS_MAX > thread_i; ++thread_i )
{
if( !(_threads[thread_i].inuse) )
continue;
if( thread_id == _threads[thread_i].thread_id )
return( &(_threads[thread_i]) );
}
return( NULL );
}
// ****************************************************************************
// ****************************************************************************
// Selection Object - Find Selection Object
// ========================================
static SmSelObjSelectEntryT* sm_selobj_find( SmSelObjThreadInfoT* thread_info,
int selobj )
{
SmSelObjSelectEntryT* entry;
unsigned int entry_i;
for( entry_i=0; SM_THREAD_SELECT_OBJS_MAX > entry_i; ++entry_i )
{
entry = (SmSelObjSelectEntryT*) &(thread_info->selobjs[entry_i]);
if( SM_SEL_OBJ_ENTRY_VALID == entry->valid )
{
if( selobj == entry->selobj )
{
return( entry );
}
}
}
return( NULL );
}
// ****************************************************************************
// ****************************************************************************
// Selection Object - Register
// ===========================
SmErrorT sm_selobj_register( int selobj, SmSelObjCallbackT callback,
int64_t user_data )
{
SmSelObjThreadInfoT* thread_info;
SmSelObjSelectEntryT* entry;
thread_info = sm_selobj_find_thread_info();
if( NULL == thread_info )
{
DPRINTFE( "Failed to find thread information." );
return( SM_FAILED );
}
entry = sm_selobj_find( thread_info, selobj );
if( NULL == entry )
{
unsigned int entry_i;
for( entry_i=0; SM_THREAD_SELECT_OBJS_MAX > entry_i; ++entry_i )
{
entry = (SmSelObjSelectEntryT*) &(thread_info->selobjs[entry_i]);
if( SM_SEL_OBJ_ENTRY_VALID != entry->valid )
{
entry->valid = SM_SEL_OBJ_ENTRY_VALID;
entry->selobj = selobj;
entry->callback = callback;
entry->user_data = user_data;
FD_SET( selobj, &(thread_info->selobjs_set) );
if( selobj > thread_info->last_selobj )
{
thread_info->last_selobj = selobj;
}
break;
}
}
} else {
entry->callback = callback;
entry->user_data = user_data;
}
return( SM_OKAY );
}
// ****************************************************************************
// ****************************************************************************
// Selection Object - Deregister
// =============================
SmErrorT sm_selobj_deregister( int selobj )
{
SmSelObjThreadInfoT* thread_info;
SmSelObjSelectEntryT* entry;
thread_info = sm_selobj_find_thread_info();
if( NULL == thread_info )
{
DPRINTFE( "Failed to find thread information." );
return( SM_FAILED );
}
entry = sm_selobj_find( thread_info, selobj );
if( NULL != entry )
{
memset( entry, 0, sizeof(SmSelObjSelectEntryT) );
FD_CLR( selobj, &(thread_info->selobjs_set) );
thread_info->last_selobj = 0;
unsigned int entry_i;
for( entry_i=0; SM_THREAD_SELECT_OBJS_MAX > entry_i; ++entry_i )
{
entry = (SmSelObjSelectEntryT*) &(thread_info->selobjs[entry_i]);
if( SM_SEL_OBJ_ENTRY_VALID == entry->valid )
{
if( entry->selobj > thread_info->last_selobj )
{
thread_info->last_selobj = entry->selobj;
}
}
}
}
return( SM_OKAY );
}
// ****************************************************************************
// ****************************************************************************
// Selection Object - Dispatch
// ===========================
SmErrorT sm_selobj_dispatch( unsigned int timeout_in_ms )
{
SmSelObjThreadInfoT* thread_info;
SmSelObjSelectEntryT* entry;
int num_fds;
fd_set fds;
struct timeval tv;
int result;
thread_info = sm_selobj_find_thread_info();
if( NULL == thread_info )
{
DPRINTFE( "Failed to find thread information." );
return( SM_FAILED );
}
num_fds = thread_info->last_selobj;
fds = thread_info->selobjs_set;
tv.tv_sec = timeout_in_ms / 1000;
tv.tv_usec = (timeout_in_ms % 1000) * 1000;
result = select( num_fds+1, &fds, NULL, NULL, &tv );
if( 0 > result )
{
if( errno == EINTR )
{
DPRINTFD( "Interrupted by a signal." );
return( SM_OKAY );
} else {
DPRINTFE( "Select failed, error=%s.", strerror( errno ) );
return( SM_FAILED );
}
} else if( 0 == result ) {
DPRINTFD( "Nothing selected." );
return( SM_OKAY );
}
unsigned int entry_i;
for( entry_i=0; SM_THREAD_SELECT_OBJS_MAX > entry_i; ++entry_i )
{
entry = (SmSelObjSelectEntryT*) &(thread_info->selobjs[entry_i]);
if( SM_SEL_OBJ_ENTRY_VALID != entry->valid )
continue;
if( FD_ISSET( entry->selobj, &fds ) )
{
if( NULL != entry->callback )
{
entry->callback( entry->selobj, entry->user_data );
}
}
}
return( SM_OKAY );
}
// ****************************************************************************
// ****************************************************************************
// Selection Object - Initialize
// =============================
SmErrorT sm_selobj_initialize( void )
{
SmSelObjThreadInfoT* thread_info = NULL;
if( 0 != pthread_mutex_lock( &selobj_mutex ) )
{
DPRINTFE( "Failed to capture mutex." );
return( SM_FAILED );
}
unsigned int thread_i;
for( thread_i=0; SM_THREADS_MAX > thread_i; ++thread_i )
{
if( !(_threads[thread_i].inuse) )
{
thread_info = &(_threads[thread_i]);
break;
}
}
if( NULL == thread_info )
{
DPRINTFE( "Failed to allocate thread information." );
goto ERROR;
}
memset( thread_info, 0, sizeof(SmSelObjThreadInfoT) );
thread_info->inuse = true;
thread_info->thread_id = pthread_self();
FD_ZERO( &(thread_info->selobjs_set) );
if( 0 != pthread_mutex_unlock( &selobj_mutex ) )
{
DPRINTFE( "Failed to release mutex." );
}
return( SM_OKAY );
ERROR:
if( 0 != pthread_mutex_unlock( &selobj_mutex ) )
{
DPRINTFE( "Failed to release mutex." );
return( SM_FAILED );
}
return( SM_FAILED );
}
// ****************************************************************************
// ****************************************************************************
// Selection Object - Finalize
// ===========================
SmErrorT sm_selobj_finalize( void )
{
SmSelObjThreadInfoT* thread_info;
if( 0 != pthread_mutex_lock( &selobj_mutex ) )
{
DPRINTFE( "Failed to capture mutex." );
return( SM_FAILED );
}
thread_info = sm_selobj_find_thread_info();
if( NULL == thread_info )
{
DPRINTFE( "Failed to find thread information." );
return( SM_OKAY );
}
memset( thread_info, 0, sizeof(SmSelObjThreadInfoT) );
FD_ZERO( &(thread_info->selobjs_set) );
if( 0 != pthread_mutex_unlock( &selobj_mutex ) )
{
DPRINTFE( "Failed to release mutex." );
}
return( SM_OKAY );
}
// ****************************************************************************