MIDAS
Loading...
Searching...
No Matches
Common Functions (cm_xxx)

Classes

struct  exptab_entry
 
struct  exptab_struct
 
class  bm_lock_buffer_guard
 
struct  TrClient
 
struct  TrState
 

Functions

INT cm_synchronize (DWORD *seconds)
 
INT cm_asctime (char *str, INT buf_size)
 
std::string cm_asctime ()
 
INT cm_time (DWORD *t)
 
const char * cm_get_version ()
 
const char * cm_get_revision ()
 
INT cm_set_path (const char *path)
 
INT cm_get_path (char *path, int path_size)
 
std::string cm_get_path ()
 
INT EXPRT cm_get_path_string (std::string *path)
 
INT cm_set_experiment_name (const char *name)
 
INT cm_get_experiment_name (char *name, int name_length)
 
std::string cm_get_experiment_name ()
 
INT cm_read_exptab (exptab_struct *exptab)
 
int cm_get_exptab_filename (char *s, int size)
 
std::string cm_get_exptab_filename ()
 
int cm_get_exptab (const char *expname, std::string *dir, std::string *user)
 
int cm_get_exptab (const char *expname, char *dir, int dir_size, char *user, int user_size)
 
INT cm_delete_client_info (HNDLE hDB, INT pid)
 
INT cm_check_client (HNDLE hDB, HNDLE hKeyClient)
 
INT cm_set_client_info (HNDLE hDB, HNDLE *hKeyClient, const char *host_name, const char *program_name, INT hw_type, const char *password, DWORD watchdog_timeout)
 
std::string cm_get_client_name ()
 
INT cm_get_environment (char *host_name, int host_name_size, char *exp_name, int exp_name_size)
 
INT cm_get_environment (std::string *host_name, std::string *exp_name)
 
int cm_set_experiment_local (const char *exp_name)
 
void cm_check_connect (void)
 
INT cm_connect_experiment (const char *host_name, const char *exp_name, const char *client_name, void(*func)(char *))
 
INT cm_connect_experiment1 (const char *host_name, const char *default_exp_name, const char *client_name, void(*func)(char *), INT odb_size, DWORD watchdog_timeout)
 
INT cm_list_experiments_local (STRING_LIST *exp_names)
 
INT cm_list_experiments_remote (const char *host_name, STRING_LIST *exp_names)
 
INT cm_select_experiment_local (std::string *exp_name)
 
INT cm_select_experiment_remote (const char *host_name, std::string *exp_name)
 
INT cm_connect_client (const char *client_name, HNDLE *hConn)
 
static void rpc_client_shutdown ()
 
INT cm_disconnect_client (HNDLE hConn, BOOL bShutdown)
 
INT cm_disconnect_experiment (void)
 
INT cm_set_experiment_database (HNDLE hDB, HNDLE hKeyClient)
 
INT cm_set_experiment_semaphore (INT semaphore_alarm, INT semaphore_elog, INT semaphore_history, INT semaphore_msg)
 
INT cm_get_experiment_database (HNDLE *hDB, HNDLE *hKeyClient)
 
INT cm_get_experiment_semaphore (INT *semaphore_alarm, INT *semaphore_elog, INT *semaphore_history, INT *semaphore_msg)
 
static BUFFERbm_get_buffer (const char *who, INT buffer_handle, int *pstatus)
 
static int bm_lock_buffer_read_cache (BUFFER *pbuf)
 
static int bm_lock_buffer_write_cache (BUFFER *pbuf)
 
static int bm_lock_buffer_mutex (BUFFER *pbuf)
 
static int xbm_lock_buffer (BUFFER *pbuf)
 
static void xbm_unlock_buffer (BUFFER *pbuf)
 
static BUFFER_CLIENTbm_get_my_client_locked (bm_lock_buffer_guard &pbuf_guard)
 
static INT bm_notify_client (const char *buffer_name, int s)
 
static INT bm_push_event (const char *buffer_name)
 
static void bm_defragment_event (HNDLE buffer_handle, HNDLE request_id, EVENT_HEADER *pevent, void *pdata, EVENT_HANDLER *dispatcher)
 
INT cm_set_watchdog_params_local (BOOL call_watchdog, DWORD timeout)
 
INT cm_set_watchdog_params (BOOL call_watchdog, DWORD timeout)
 
INT cm_get_watchdog_params (BOOL *call_watchdog, DWORD *timeout)
 
INT cm_get_watchdog_info (HNDLE hDB, const char *client_name, DWORD *timeout, DWORD *last)
 
static void load_rpc_hosts (HNDLE hDB, HNDLE hKey, int index, void *info)
 
static void init_rpc_hosts (HNDLE hDB)
 
INT cm_register_server (void)
 
INT cm_register_transition (INT transition, INT(*func)(INT, char *), INT sequence_number)
 
INT cm_deregister_transition (INT transition)
 
INT cm_set_transition_sequence (INT transition, INT sequence_number)
 
INT cm_set_client_run_state (INT state)
 
INT cm_register_deferred_transition (INT transition, BOOL(*func)(INT, BOOL))
 
INT cm_check_deferred_transition ()
 
static bool tr_compare (const std::unique_ptr< TrClient > &arg1, const std::unique_ptr< TrClient > &arg2)
 
static int tr_finish (HNDLE hDB, TrState *tr, int transition, int status, const char *errorstr)
 
static void write_tr_client_to_odb (HNDLE hDB, const TrClient *tr_client)
 
static int cm_transition_detach (INT transition, INT run_number, char *errstr, INT errstr_size, INT async_flag, INT debug_flag)
 
static int cm_transition_call (TrState *s, int idx)
 
static int cm_transition_call_direct (TrClient *tr_client)
 
static INT cm_transition2 (INT transition, INT run_number, char *errstr, INT errstr_size, INT async_flag, INT debug_flag)
 
static INT cm_transition1 (INT transition, INT run_number, char *errstr, INT errstr_size, INT async_flag, INT debug_flag)
 
static INT tr_main_thread (void *param)
 
INT cm_transition_cleanup ()
 
INT cm_transition (INT transition, INT run_number, char *errstr, INT errstr_size, INT async_flag, INT debug_flag)
 
INT cm_dispatch_ipc (const char *message, int message_size, int client_socket)
 
void cm_ctrlc_handler (int sig)
 
BOOL cm_is_ctrlc_pressed ()
 
void cm_ack_ctrlc_pressed ()
 
int cm_exec_script (const char *odb_path_to_script)
 
static void bm_cleanup (const char *who, DWORD actual_time, BOOL wrong_interval)
 
INT cm_periodic_tasks ()
 
INT cm_yield (INT millisec)
 
INT cm_execute (const char *command, char *result, INT bufsize)
 
INT cm_register_function (INT id, INT(*func)(INT, void **))
 
std::string cm_get_history_path (const char *history_channel)
 
INT cm_watchdog_thread (void *unused)
 
static void xcm_watchdog_thread ()
 
INT cm_start_watchdog_thread ()
 
INT cm_stop_watchdog_thread ()
 
INT cm_shutdown (const char *name, BOOL bUnique)
 
INT cm_shutdown (const char *name)
 
INT cm_exist (const char *name, BOOL bClientName)
 
INT cm_cleanup (const char *client_name, BOOL ignore_timeout)
 
std::string cm_expand_env (const char *str)
 
static bool test_cm_expand_env1 (const char *str, const char *expected)
 
void cm_test_expand_env ()
 

Variables

static exptab_struct _exptab
 
static INT _requested_transition
 
static DWORD _deferred_transition_mask
 
static BOOL _ctrlc_pressed = FALSE
 
static std::atomic< bool > _watchdog_thread_run {false}
 
static std::atomic< bool > _watchdog_thread_is_running {false}
 
static std::atomic< std::thread * > _watchdog_thread {NULL}
 

Detailed Description

dox dox


dox


Function Documentation

◆ bm_cleanup()

static void bm_cleanup ( const char *  who,
DWORD  actual_time,
BOOL  wrong_interval 
)
static

dox

Check all clients on all buffers, remove invalid clients

Definition at line 6224 of file midas.cxx.

6225{
6226#ifdef LOCAL_ROUTINES
6227
6228 //printf("bm_cleanup: called by %s, actual_time %d, wrong_interval %d\n", who, actual_time, wrong_interval);
6229
6230 std::vector<BUFFER*> mybuffers;
6231
6232 gBuffersMutex.lock();
6233 mybuffers = gBuffers;
6234 gBuffersMutex.unlock();
6235
6236 /* check buffers */
6237 for (BUFFER* pbuf : mybuffers) {
6238 if (!pbuf)
6239 continue;
6240 if (pbuf->attached) {
6241 /* update the last_activity entry to show that we are alive */
6242
6243 bm_lock_buffer_guard pbuf_guard(pbuf);
6244
6245 if (!pbuf_guard.is_locked())
6246 continue;
6247
6248 BUFFER_CLIENT *pclient = bm_get_my_client_locked(pbuf_guard);
6249 pclient->last_activity = actual_time;
6250
6251 /* don't check other clients if interval is strange */
6252 if (!wrong_interval)
6254 }
6255 }
6256#endif // LOCAL_ROUTINES
6257}
static void bm_cleanup_buffer_locked(BUFFER *pbuf, const char *who, DWORD actual_time)
Definition midas.cxx:6138
static BUFFER_CLIENT * bm_get_my_client_locked(bm_lock_buffer_guard &pbuf_guard)
Definition midas.cxx:6071
DWORD actual_time
Definition mfe.cxx:37
static std::mutex gBuffersMutex
Definition midas.cxx:195
static std::vector< BUFFER * > gBuffers
Definition midas.cxx:196
DWORD last_activity
Definition midas.h:951
Here is the call graph for this function:
Here is the caller graph for this function:

◆ bm_defragment_event()

static void bm_defragment_event ( HNDLE  buffer_handle,
HNDLE  request_id,
EVENT_HEADER pevent,
void *  pdata,
EVENT_HANDLER dispatcher 
)
static

Definition at line 11525 of file midas.cxx.

11551{
11552 INT i;
11553
11554 if ((uint16_t(pevent->event_id) & uint16_t(0xF000)) == uint16_t(EVENTID_FRAG1)) {
11555 /*---- start new event ----*/
11556
11557 //printf("First Frag detected : Ser#:%d ID=0x%x \n", pevent->serial_number, pevent->event_id);
11558
11559 /* check if fragments already stored */
11560 for (i = 0; i < MAX_DEFRAG_EVENTS; i++)
11561 if (defrag_buffer[i].event_id == (pevent->event_id & 0x0FFF))
11562 break;
11563
11564 if (i < MAX_DEFRAG_EVENTS) {
11565 free(defrag_buffer[i].pevent);
11566 defrag_buffer[i].pevent = NULL;
11567 memset(&defrag_buffer[i].event_id, 0, sizeof(EVENT_DEFRAG_BUFFER));
11568 cm_msg(MERROR, "bm_defragement_event",
11569 "Received new event with ID %d while old fragments were not completed",
11570 (pevent->event_id & 0x0FFF));
11571 }
11572
11573 /* search new slot */
11574 for (i = 0; i < MAX_DEFRAG_EVENTS; i++)
11575 if (defrag_buffer[i].event_id == 0)
11576 break;
11577
11578 if (i == MAX_DEFRAG_EVENTS) {
11579 cm_msg(MERROR, "bm_defragment_event",
11580 "Not enough defragment buffers, please increase MAX_DEFRAG_EVENTS and recompile");
11581 return;
11582 }
11583
11584 /* check event size */
11585 if (pevent->data_size != sizeof(DWORD)) {
11586 cm_msg(MERROR, "bm_defragment_event",
11587 "Received first event fragment with %d bytes instead of %d bytes, event ignored",
11588 pevent->data_size, (int) sizeof(DWORD));
11589 return;
11590 }
11591
11592 /* setup defragment buffer */
11593 defrag_buffer[i].event_id = (pevent->event_id & 0x0FFF);
11594 defrag_buffer[i].data_size = *(DWORD *) pdata;
11597
11598 if (defrag_buffer[i].pevent == NULL) {
11599 memset(&defrag_buffer[i].event_id, 0, sizeof(EVENT_DEFRAG_BUFFER));
11600 cm_msg(MERROR, "bm_defragement_event", "Not enough memory to allocate event defragment buffer");
11601 return;
11602 }
11603
11604 memcpy(defrag_buffer[i].pevent, pevent, sizeof(EVENT_HEADER));
11607
11608 // printf("First frag[%d] (ID %d) Ser#:%d sz:%d\n", i, defrag_buffer[i].event_id,
11609 // pevent->serial_number, defrag_buffer[i].data_size);
11610
11611 return;
11612 }
11613
11614 /* search buffer for that event */
11615 for (i = 0; i < MAX_DEFRAG_EVENTS; i++)
11616 if (defrag_buffer[i].event_id == (pevent->event_id & 0xFFF))
11617 break;
11618
11619 if (i == MAX_DEFRAG_EVENTS) {
11620 /* no buffer available -> no first fragment received */
11621 cm_msg(MERROR, "bm_defragement_event",
11622 "Received fragment without first fragment (ID %d) Ser#:%d",
11623 pevent->event_id & 0x0FFF, pevent->serial_number);
11624 return;
11625 }
11626
11627 /* add fragment to buffer */
11629 free(defrag_buffer[i].pevent);
11630 defrag_buffer[i].pevent = NULL;
11631 memset(&defrag_buffer[i].event_id, 0, sizeof(EVENT_DEFRAG_BUFFER));
11632 cm_msg(MERROR, "bm_defragement_event",
11633 "Received fragments with more data (%d) than event size (%d)",
11635 return;
11636 }
11637
11638 memcpy(((char *) defrag_buffer[i].pevent) + sizeof(EVENT_HEADER) +
11639 defrag_buffer[i].received, pdata, pevent->data_size);
11640
11641 defrag_buffer[i].received += pevent->data_size;
11642
11643 //printf("Other frag[%d][%d] (ID %d) Ser#:%d sz:%d\n", i, j++,
11644 // defrag_buffer[i].event_id, pevent->serial_number, pevent->data_size);
11645
11646 if (defrag_buffer[i].received == defrag_buffer[i].data_size) {
11647 /* event complete */
11648 dispatcher(buffer_handle, request_id, defrag_buffer[i].pevent, defrag_buffer[i].pevent + 1);
11649 free(defrag_buffer[i].pevent);
11650 defrag_buffer[i].pevent = NULL;
11651 memset(&defrag_buffer[i].event_id, 0, sizeof(EVENT_DEFRAG_BUFFER));
11652 }
11653}
#define MAX_DEFRAG_EVENTS
Definition midas.cxx:11513
static EVENT_DEFRAG_BUFFER defrag_buffer[MAX_DEFRAG_EVENTS]
Definition midas.cxx:11522
unsigned int DWORD
Definition mcstd.h:51
#define MERROR
Definition midas.h:559
INT cm_msg(INT message_type, const char *filename, INT line, const char *routine, const char *format,...)
Definition midas.cxx:939
INT i
Definition mdump.cxx:32
int INT
Definition midas.h:129
#define EVENTID_FRAG1
Definition midas.h:907
#define event_id
EVENT_HEADER * pevent
Definition midas.cxx:11519
short int event_id
Definition midas.h:853
DWORD data_size
Definition midas.h:857
DWORD serial_number
Definition midas.h:855
Here is the call graph for this function:
Here is the caller graph for this function:

◆ bm_get_buffer()

static BUFFER * bm_get_buffer ( const char *  who,
INT  buffer_handle,
int *  pstatus 
)
static

dox

Definition at line 6687 of file midas.cxx.

6688{
6689 size_t sbuffer_handle = buffer_handle;
6690
6691 size_t nbuf = 0;
6692 BUFFER* pbuf = NULL;
6693
6694 gBuffersMutex.lock();
6695
6696 nbuf = gBuffers.size();
6697 if (buffer_handle >=1 && sbuffer_handle <= nbuf) {
6698 pbuf = gBuffers[buffer_handle-1];
6699 }
6700
6701 gBuffersMutex.unlock();
6702
6703 if (sbuffer_handle > nbuf || buffer_handle <= 0) {
6704 if (who)
6705 cm_msg(MERROR, who, "invalid buffer handle %d: out of range [1..%d]", buffer_handle, (int)nbuf);
6706 if (pstatus)
6707 *pstatus = BM_INVALID_HANDLE;
6708 return NULL;
6709 }
6710
6711 if (!pbuf) {
6712 if (who)
6713 cm_msg(MERROR, who, "invalid buffer handle %d: empty slot", buffer_handle);
6714 if (pstatus)
6715 *pstatus = BM_INVALID_HANDLE;
6716 return NULL;
6717 }
6718
6719 if (!pbuf->attached) {
6720 if (who)
6721 cm_msg(MERROR, who, "invalid buffer handle %d: not attached", buffer_handle);
6722 if (pstatus)
6723 *pstatus = BM_INVALID_HANDLE;
6724 return NULL;
6725 }
6726
6727 if (pstatus)
6728 *pstatus = BM_SUCCESS;
6729
6730 return pbuf;
6731}
#define BM_INVALID_HANDLE
Definition midas.h:609
#define BM_SUCCESS
Definition midas.h:605
std::atomic_bool attached
Definition midas.h:988
Here is the call graph for this function:
Here is the caller graph for this function:

◆ bm_get_my_client_locked()

static BUFFER_CLIENT * bm_get_my_client_locked ( bm_lock_buffer_guard pbuf_guard)
static

Definition at line 6071 of file midas.cxx.

6071 {
6072 int my_client_index = bm_validate_client_index_locked(pbuf_guard);
6073 return pbuf_guard.get_pbuf()->buffer_header->client + my_client_index;
6074}
BUFFER * get_pbuf() const
Definition midas.cxx:3253
static int bm_validate_client_index_locked(bm_lock_buffer_guard &pbuf_guard)
Definition midas.cxx:5994
BUFFER_CLIENT client[MAX_CLIENTS]
Definition midas.h:968
BUFFER_HEADER * buffer_header
Definition midas.h:993
Here is the call graph for this function:
Here is the caller graph for this function:

◆ bm_lock_buffer_mutex()

static int bm_lock_buffer_mutex ( BUFFER pbuf)
static

Definition at line 8059 of file midas.cxx.

8060{
8061 //printf("bm_lock_buffer_mutex %s!\n", pbuf->buffer_name);
8062
8063 bool locked = ss_timed_mutex_wait_for_sec(pbuf->buffer_mutex, "buffer mutex", _bm_mutex_timeout_sec);
8064
8065 if (!locked) {
8066 fprintf(stderr, "bm_lock_buffer_mutex: Error: Cannot lock buffer \"%s\", ss_timed_mutex_wait_for_sec() timeout, aborting...\n", pbuf->buffer_name);
8067 cm_msg(MERROR, "bm_lock_buffer_mutex", "Cannot lock buffer \"%s\", ss_timed_mutex_wait_for_sec() timeout, aborting...", pbuf->buffer_name);
8068 abort();
8069 /* DOES NOT RETURN */
8070 }
8071
8072 if (!pbuf->attached) {
8073 pbuf->buffer_mutex.unlock();
8074 fprintf(stderr, "bm_lock_buffer_mutex: Error: Cannot lock buffer \"%s\", buffer was closed while we waited for the buffer_mutex\n", pbuf->buffer_name);
8075 return BM_INVALID_HANDLE;
8076 }
8077
8078 //static int counter = 0;
8079 //counter++;
8080 //printf("locked %d!\n", counter);
8081 //if (counter > 50)
8082 // ::sleep(3);
8083
8084 return BM_SUCCESS;
8085}
static double _bm_mutex_timeout_sec
Definition midas.cxx:5992
bool ss_timed_mutex_wait_for_sec(std::timed_mutex &mutex, const char *mutex_name, double timeout_sec)
Definition system.cxx:3344
std::timed_mutex buffer_mutex
Definition midas.h:989
char buffer_name[NAME_LENGTH]
Definition midas.h:992
Here is the call graph for this function:
Here is the caller graph for this function:

◆ bm_lock_buffer_read_cache()

static int bm_lock_buffer_read_cache ( BUFFER pbuf)
static

Definition at line 8017 of file midas.cxx.

8018{
8019 bool locked = ss_timed_mutex_wait_for_sec(pbuf->read_cache_mutex, "buffer read cache", _bm_mutex_timeout_sec);
8020
8021 if (!locked) {
8022 fprintf(stderr, "bm_lock_buffer_read_cache: Error: Cannot lock read cache of buffer \"%s\", ss_timed_mutex_wait_for_sec() timeout, aborting...\n", pbuf->buffer_name);
8023 cm_msg(MERROR, "bm_lock_buffer_read_cache", "Cannot lock read cache of buffer \"%s\", ss_timed_mutex_wait_for_sec() timeout, aborting...", pbuf->buffer_name);
8024 abort();
8025 /* DOES NOT RETURN */
8026 }
8027
8028 if (!pbuf->attached) {
8029 pbuf->read_cache_mutex.unlock();
8030 fprintf(stderr, "bm_lock_buffer_read_cache: Error: Cannot lock read cache of buffer \"%s\", buffer was closed while we waited for the buffer_mutex\n", pbuf->buffer_name);
8031 return BM_INVALID_HANDLE;
8032 }
8033
8034 return BM_SUCCESS;
8035}
std::timed_mutex read_cache_mutex
Definition midas.h:994
Here is the call graph for this function:
Here is the caller graph for this function:

◆ bm_lock_buffer_write_cache()

static int bm_lock_buffer_write_cache ( BUFFER pbuf)
static

Definition at line 8038 of file midas.cxx.

8039{
8040 bool locked = ss_timed_mutex_wait_for_sec(pbuf->write_cache_mutex, "buffer write cache", _bm_mutex_timeout_sec);
8041
8042 if (!locked) {
8043 fprintf(stderr, "bm_lock_buffer_write_cache: Error: Cannot lock write cache of buffer \"%s\", ss_timed_mutex_wait_for_sec() timeout, aborting...\n", pbuf->buffer_name);
8044 cm_msg(MERROR, "bm_lock_buffer_write_cache", "Cannot lock write cache of buffer \"%s\", ss_timed_mutex_wait_for_sec() timeout, aborting...", pbuf->buffer_name);
8045 abort();
8046 /* DOES NOT RETURN */
8047 }
8048
8049 if (!pbuf->attached) {
8050 pbuf->write_cache_mutex.unlock();
8051 fprintf(stderr, "bm_lock_buffer_write_cache: Error: Cannot lock write cache of buffer \"%s\", buffer was closed while we waited for the buffer_mutex\n", pbuf->buffer_name);
8052 return BM_INVALID_HANDLE;
8053 }
8054
8055 return BM_SUCCESS;
8056}
std::timed_mutex write_cache_mutex
Definition midas.h:999
Here is the call graph for this function:
Here is the caller graph for this function:

◆ bm_notify_client()

static INT bm_notify_client ( const char *  buffer_name,
int  s 
)
static

Definition at line 11289 of file midas.cxx.

11309{
11310 static DWORD last_time = 0;
11311 DWORD now = ss_millitime();
11312
11313 //printf("bm_notify_client: buffer [%s], socket %d, time %d\n", buffer_name, client_socket, now - last_time);
11314
11315 BUFFER* fbuf = NULL;
11316
11317 gBuffersMutex.lock();
11318
11319 for (size_t i = 0; i < gBuffers.size(); i++) {
11320 BUFFER* pbuf = gBuffers[i];
11321 if (!pbuf || !pbuf->attached)
11322 continue;
11323 if (strcmp(buffer_name, pbuf->buffer_header->name) == 0) {
11324 fbuf = pbuf;
11325 break;
11326 }
11327 }
11328
11329 gBuffersMutex.unlock();
11330
11331 if (!fbuf)
11332 return BM_INVALID_HANDLE;
11333
11334 /* don't send notification if client has no callback defined
11335 to receive events -> client calls bm_receive_event manually */
11336 if (!fbuf->callback)
11337 return DB_SUCCESS;
11338
11339 int convert_flags = rpc_get_convert_flags();
11340
11341 /* only send notification once each 500ms */
11342 if (now - last_time < 500)
11343 return DB_SUCCESS;
11344
11345 last_time = now;
11346
11347 char buffer[32];
11348 NET_COMMAND *nc = (NET_COMMAND *) buffer;
11349
11350 nc->header.routine_id = MSG_BM;
11351 nc->header.param_size = 0;
11352
11353 if (convert_flags) {
11356 }
11357
11358 //printf("bm_notify_client: Sending MSG_BM! buffer [%s]\n", buffer_name);
11359
11360 /* send the update notification to the client */
11361 send_tcp(client_socket, (char *) buffer, sizeof(NET_COMMAND_HEADER), 0);
11362
11363 return BM_SUCCESS;
11364}
#define DB_SUCCESS
Definition midas.h:632
#define TID_UINT32
Definition midas.h:337
#define MSG_BM
Definition msystem.h:302
DWORD ss_millitime()
Definition system.cxx:3472
INT send_tcp(int sock, char *buffer, DWORD buffer_size, INT flags)
Definition system.cxx:5364
INT rpc_get_convert_flags(void)
Definition midas.cxx:13263
void rpc_convert_single(void *data, INT tid, INT flags, INT convert_flags)
Definition midas.cxx:11914
DWORD last_time
Definition mana.cxx:3070
char buffer_name[NAME_LENGTH]
Definition mevb.cxx:45
#define RPC_OUTGOING
Definition midas.h:1520
char name[NAME_LENGTH]
Definition midas.h:959
BOOL callback
Definition midas.h:1007
NET_COMMAND_HEADER header
Definition msystem.h:293
Here is the call graph for this function:
Here is the caller graph for this function:

◆ bm_push_event()

static INT bm_push_event ( const char *  buffer_name)
static

Check a buffer if an event is available and call the dispatch function if found.

Parameters
buffer_nameName of buffer
Returns
BM_SUCCESS, BM_INVALID_HANDLE, BM_TRUNCATED, BM_ASYNC_RETURN, BM_CORRUPTED, RPC_NET_ERROR

Definition at line 11159 of file midas.cxx.

11160{
11161 std::vector<BUFFER*> mybuffers;
11162
11163 gBuffersMutex.lock();
11164 mybuffers = gBuffers;
11165 gBuffersMutex.unlock();
11166
11167 for (size_t i = 0; i < mybuffers.size(); i++) {
11168 BUFFER *pbuf = mybuffers[i];
11169 if (!pbuf || !pbuf->attached)
11170 continue;
11171 // FIXME: unlocked read access to pbuf->buffer_name!
11172 if (strcmp(buffer_name, pbuf->buffer_name) == 0) {
11173 return bm_push_buffer(pbuf, i + 1);
11174 }
11175 }
11176
11177 return BM_INVALID_HANDLE;
11178}
static INT bm_push_buffer(BUFFER *pbuf, int buffer_handle)
Definition midas.cxx:11143
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_ack_ctrlc_pressed()

void cm_ack_ctrlc_pressed ( void  )

Definition at line 5530 of file midas.cxx.

5530 {
5532}
#define FALSE
Definition cfortran.h:309
static BOOL _ctrlc_pressed
Definition midas.cxx:5513
Here is the caller graph for this function:

◆ cm_asctime() [1/2]

std::string cm_asctime ( )

Get time from MIDAS server and set local time.

Returns
return time string

Definition at line 1462 of file midas.cxx.

1462 {
1463 /* if connected to server, get time from there */
1464 if (rpc_is_remote()) {
1465 char buf[256];
1466 int status = rpc_call(RPC_CM_ASCTIME, buf, sizeof(buf));
1467 if (status == CM_SUCCESS) {
1468 return buf;
1469 } else {
1470 return "";
1471 }
1472 }
1473
1474 /* return local time */
1475 return ss_asctime();
1476}
#define CM_SUCCESS
Definition midas.h:582
std::string ss_asctime()
Definition system.cxx:3628
#define RPC_CM_ASCTIME
Definition mrpc.h:28
bool rpc_is_remote(void)
Definition midas.cxx:12994
INT rpc_call(DWORD routine_id,...)
Definition midas.cxx:14217
DWORD status
Definition odbhist.cxx:39
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_asctime() [2/2]

INT cm_asctime ( char *  str,
INT  buf_size 
)

Get time from MIDAS server and set local time.

Parameters
strreturn time string
buf_sizeMaximum size of str
Returns
CM_SUCCESS

Definition at line 1446 of file midas.cxx.

1446 {
1447 /* if connected to server, get time from there */
1448 if (rpc_is_remote())
1449 return rpc_call(RPC_CM_ASCTIME, str, buf_size);
1450
1451 /* return local time */
1452 mstrlcpy(str, ss_asctime().c_str(), buf_size);
1453
1454 return CM_SUCCESS;
1455}
char str[256]
Definition odbhist.cxx:33
Here is the call graph for this function:

◆ cm_check_client()

INT cm_check_client ( HNDLE  hDB,
HNDLE  hKeyClient 
)

Check if a client with a /system/client/xxx entry has a valid entry in the ODB client table. If not, remove that client from the /system/client tree.

Parameters
hDBHandle to online database
hKeyClientHandle to client key
Returns
CM_SUCCESS, CM_NO_CLIENT

Definition at line 1919 of file midas.cxx.

1919 {
1920 if (rpc_is_remote())
1921 return rpc_call(RPC_CM_CHECK_CLIENT, hDB, hKeyClient);
1922
1923#ifdef LOCAL_ROUTINES
1924 return db_check_client(hDB, hKeyClient);
1925#endif /*LOCAL_ROUTINES */
1926 return CM_SUCCESS;
1927}
INT db_check_client(HNDLE hDB, HNDLE hKeyClient)
Definition odb.cxx:3638
#define RPC_CM_CHECK_CLIENT
Definition mrpc.h:34
HNDLE hDB
main ODB handle
Definition mana.cxx:207
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_check_connect()

void cm_check_connect ( void  )

Definition at line 2275 of file midas.cxx.

2275 {
2276 if (_hKeyClient) {
2277 cm_msg(MERROR, "cm_check_connect", "cm_disconnect_experiment not called at end of program");
2279 }
2280}
INT cm_msg_flush_buffer()
Definition midas.cxx:889
static HNDLE _hKeyClient
Definition midas.cxx:1506
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_check_deferred_transition()

INT cm_check_deferred_transition ( void  )

Check for any deferred transition. If a deferred transition handler has been registered via the cm_register_deferred_transition function, this routine should be called regularly. It checks if a transition request is pending. If so, it calld the registered handler if the transition should be done and then actually does the transition.

Returns
CM_SUCCESS, <error> Error from cm_transition()

Definition at line 3969 of file midas.cxx.

3969 {
3970 INT i, status;
3971 char str[256];
3972 static BOOL first;
3973
3974 if (_requested_transition == 0)
3975 first = TRUE;
3976
3978 for (i = 0; _deferred_trans_table[i].transition; i++)
3980 break;
3981
3983 if (((BOOL(*)(INT, BOOL)) _deferred_trans_table[i].func)(_requested_transition, first)) {
3985 if (status != CM_SUCCESS)
3986 cm_msg(MERROR, "cm_check_deferred_transition", "Cannot perform deferred transition: %s", str);
3987
3988 /* bypass hotlink and set _requested_transition directly to zero */
3990
3991 return status;
3992 }
3993 first = FALSE;
3994 }
3995 }
3996
3997 return SUCCESS;
3998}
INT transition(INT run_number, char *error)
Definition consume.cxx:35
INT cm_transition(INT transition, INT run_number, char *errstr, INT errstr_size, INT async_flag, INT debug_flag)
Definition midas.cxx:5360
static DWORD _deferred_transition_mask
Definition midas.cxx:3899
static INT _requested_transition
Definition midas.cxx:3898
#define SUCCESS
Definition mcstd.h:54
#define TR_SYNC
Definition midas.h:358
#define TR_DEFERRED
Definition midas.h:410
static TRANS_TABLE _deferred_trans_table[]
Definition midas.cxx:250
DWORD BOOL
Definition midas.h:105
#define TRUE
Definition midas.h:182
INT transition
Definition midas.cxx:242
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_cleanup()

INT cm_cleanup ( const char *  client_name,
BOOL  ignore_timeout 
)

Remove hanging clients independent of their watchdog timeout.

Since this function does not obey the client watchdog timeout, it should be only called to remove clients which have their watchdog checking turned off or which are known to be dead. The normal client removement is done via cm_watchdog().

Currently (Sept. 02) there are two applications for that:

  1. The ODBEdit command "cleanup", which can be used to remove clients which have their watchdog checking off, like the analyzer started with the "-d" flag for a debugging session.
  2. The frontend init code to remove previous frontends. This can be helpful if a frontend dies. Normally, one would have to wait 60 sec. for a crashed frontend to be removed. Only then one can start again the frontend. Since the frontend init code contains a call to cm_cleanup(<frontend_name>), one can restart a frontend immediately.

Added ignore_timeout on Nov.03. A logger might have an increased tiemout of up to 60 sec. because of tape operations. If ignore_timeout is FALSE, the logger is then not killed if its inactivity is less than 60 sec., while in the previous implementation it was always killed after 2*WATCHDOG_INTERVAL.

Parameters
client_nameClient name, if zero check all clients
ignore_timeoutIf TRUE, ignore a possible increased timeout defined by each client.
Returns
CM_SUCCESS

Definition at line 7723 of file midas.cxx.

7723 {
7724 if (rpc_is_remote())
7725 return rpc_call(RPC_CM_CLEANUP, client_name);
7726
7727#ifdef LOCAL_ROUTINES
7728 {
7729 DWORD interval;
7730 DWORD now = ss_millitime();
7731
7732 std::vector<BUFFER*> mybuffers;
7733
7734 gBuffersMutex.lock();
7735 mybuffers = gBuffers;
7736 gBuffersMutex.unlock();
7737
7738 /* check buffers */
7739 for (BUFFER* pbuf : mybuffers) {
7740 if (!pbuf)
7741 continue;
7742 if (pbuf->attached) {
7743 std::string msg;
7744
7745 bm_lock_buffer_guard pbuf_guard(pbuf);
7746
7747 if (!pbuf_guard.is_locked())
7748 continue;
7749
7750 /* update the last_activity entry to show that we are alive */
7751 BUFFER_HEADER *pheader = pbuf->buffer_header;
7752 BUFFER_CLIENT *pclient = bm_get_my_client_locked(pbuf_guard);
7753 pclient->last_activity = ss_millitime();
7754
7755 /* now check other clients */
7756 for (int j = 0; j < pheader->max_client_index; j++) {
7757 BUFFER_CLIENT *pbclient = &pheader->client[j];
7758 if (j != pbuf->client_index && pbclient->pid &&
7759 (client_name == NULL || client_name[0] == 0
7760 || strncmp(pbclient->name, client_name, strlen(client_name)) == 0)) {
7761 if (ignore_timeout)
7762 interval = 2 * WATCHDOG_INTERVAL;
7763 else
7764 interval = pbclient->watchdog_timeout;
7765
7766 /* If client process has no activity, clear its buffer entry. */
7767 if (interval > 0
7768 && now > pbclient->last_activity && now - pbclient->last_activity > interval) {
7769
7770 /* now make again the check with the buffer locked */
7771 if (interval > 0
7772 && now > pbclient->last_activity && now - pbclient->last_activity > interval) {
7773 msg = msprintf(
7774 "Client \'%s\' on \'%s\' removed by cm_cleanup (idle %1.1lfs, timeout %1.0lfs)",
7775 pbclient->name, pheader->name,
7776 (ss_millitime() - pbclient->last_activity) / 1000.0,
7777 interval / 1000.0);
7778
7779 bm_remove_client_locked(pheader, j);
7780 }
7781
7782 /* go again through whole list */
7783 j = 0;
7784 }
7785 }
7786 }
7787
7788 // unlock buffer before calling cm_msg(), if we are SYSMSG, we will deadlock.
7789 pbuf_guard.unlock();
7790
7791 /* display info message after unlocking buffer */
7792 if (!msg.empty())
7793 cm_msg(MINFO, "cm_cleanup", "%s", msg.c_str());
7794 }
7795 }
7796
7797 db_cleanup2(client_name, ignore_timeout, now, "cm_cleanup");
7798 }
7799#endif /* LOCAL_ROUTINES */
7800
7801 return CM_SUCCESS;
7802}
void bm_remove_client_locked(BUFFER_HEADER *pheader, int j)
Definition midas.cxx:6107
#define MINFO
Definition midas.h:560
void db_cleanup2(const char *client_name, int ignore_timeout, DWORD actual_time, const char *who)
Definition odb.cxx:3476
#define RPC_CM_CLEANUP
Definition mrpc.h:23
std::string msprintf(const char *format,...)
Definition midas.cxx:419
#define WATCHDOG_INTERVAL
Definition midas.h:288
INT j
Definition odbhist.cxx:40
DWORD watchdog_timeout
Definition midas.h:952
char name[NAME_LENGTH]
Definition midas.h:936
INT max_client_index
Definition midas.h:961
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_connect_client()

INT cm_connect_client ( const char *  client_name,
HNDLE hConn 
)

Connect to a MIDAS client of the current experiment

Parameters
client_nameName of client to connect to. This name is set by the other client via the cm_connect_experiment call.
hConnConnection handle
Returns
CM_SUCCESS, CM_NO_CLIENT

Definition at line 2838 of file midas.cxx.

2838 {
2839 HNDLE hDB, hKeyRoot, hSubkey, hKey;
2840 INT status, i, length, port;
2842
2843 /* find client entry in ODB */
2845
2846 status = db_find_key(hDB, 0, "System/Clients", &hKeyRoot);
2847 if (status != DB_SUCCESS)
2848 return status;
2849
2850 i = 0;
2851 do {
2852 /* search for client with specific name */
2853 status = db_enum_key(hDB, hKeyRoot, i++, &hSubkey);
2855 return CM_NO_CLIENT;
2856
2857 status = db_find_key(hDB, hSubkey, "Name", &hKey);
2858 if (status != DB_SUCCESS)
2859 return status;
2860
2861 length = NAME_LENGTH;
2862 status = db_get_data(hDB, hKey, name, &length, TID_STRING);
2863 if (status != DB_SUCCESS)
2864 return status;
2865
2866 if (equal_ustring(name, client_name)) {
2867 status = db_find_key(hDB, hSubkey, "Server Port", &hKey);
2868 if (status != DB_SUCCESS)
2869 return status;
2870
2871 length = sizeof(INT);
2872 status = db_get_data(hDB, hKey, &port, &length, TID_INT32);
2873 if (status != DB_SUCCESS)
2874 return status;
2875
2876 status = db_find_key(hDB, hSubkey, "Host", &hKey);
2877 if (status != DB_SUCCESS)
2878 return status;
2879
2880 length = sizeof(host_name);
2882 if (status != DB_SUCCESS)
2883 return status;
2884
2885 /* client found -> connect to its server port */
2886 return rpc_client_connect(host_name, port, client_name, hConn);
2887 }
2888
2889
2890 } while (TRUE);
2891}
INT cm_get_experiment_database(HNDLE *hDB, HNDLE *hKeyClient)
Definition midas.cxx:3083
#define CM_NO_CLIENT
Definition midas.h:584
#define DB_NO_MORE_SUBKEYS
Definition midas.h:647
#define TID_INT32
Definition midas.h:339
#define TID_STRING
Definition midas.h:346
BOOL equal_ustring(const char *str1, const char *str2)
Definition odb.cxx:3780
INT db_get_data(HNDLE hDB, HNDLE hKey, void *data, INT *buf_size, DWORD type)
Definition odb.cxx:7058
INT db_find_key(HNDLE hDB, HNDLE hKey, const char *key_name, HNDLE *subhKey)
Definition odb.cxx:4751
INT db_enum_key(HNDLE hDB, HNDLE hKey, INT idx, HNDLE *subkey_handle)
Definition odb.cxx:5852
INT rpc_client_connect(const char *host_name, INT port, const char *client_name, HNDLE *hConnection)
Definition midas.cxx:12245
HNDLE hKey
char host_name[HOST_NAME_LENGTH]
Definition mana.cxx:242
HNDLE hSubkey
Definition mdump.cxx:35
INT HNDLE
Definition midas.h:132
#define HOST_NAME_LENGTH
Definition midas.h:273
#define NAME_LENGTH
Definition midas.h:272
#define name(x)
Definition midas_macro.h:24
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_connect_experiment()

INT cm_connect_experiment ( const char *  host_name,
const char *  exp_name,
const char *  client_name,
void(*)(char *)  func 
)

This function connects to an existing MIDAS experiment. This must be the first call in a MIDAS application. It opens three TCP connection to the remote host (one for RPC calls, one to send events and one for hot-link notifications from the remote host) and writes client information into the ODB under /System/Clients.

Attention
All MIDAS applications should evaluate the MIDAS_SERVER_HOST and MIDAS_EXPT_NAME environment variables as defaults to the host name and experiment name (see Environment_variables). For that purpose, the function cm_get_environment() should be called prior to cm_connect_experiment(). If command line parameters -h and -e are used, the evaluation should be done between cm_get_environment() and cm_connect_experiment(). The function cm_disconnect_experiment() must be called before a MIDAS application exits.
#include <stdio.h>
#include <midas.h>
main(int argc, char *argv[])
{
char host_name[256],exp_name[32];
// get default values from environment
// parse command line parameters
for (i=1 ; i<argc ; i++)
{
if (argv[i][0] == '-')
{
if (i+1 >= argc || argv[i+1][0] == '-')
goto usage;
if (argv[i][1] == 'e')
strcpy(exp_name, argv[++i]);
else if (argv[i][1] == 'h')
strcpy(host_name, argv[++i]);
else
{
printf("usage: test [-h Hostname] [-e Experiment]\n\n");
return 1;
}
}
}
return 1;
...do operations...
}
static void usage()
INT cm_connect_experiment(const char *host_name, const char *exp_name, const char *client_name, void(*func)(char *))
Definition midas.cxx:2352
INT cm_disconnect_experiment(void)
Definition midas.cxx:2918
INT cm_get_environment(char *host_name, int host_name_size, char *exp_name, int exp_name_size)
Definition midas.cxx:2208
int main()
Definition hwtest.cxx:23
char exp_name[NAME_LENGTH]
Definition mana.cxx:243
Parameters
host_nameSpecifies host to connect to. Must be a valid IP host name. The string can be empty ("") if to connect to the local computer.
exp_nameSpecifies the experiment to connect to. If this string is empty, the number of defined experiments in exptab is checked. If only one experiment is defined, the function automatically connects to this one. If more than one experiment is defined, a list is presented and the user can interactively select one experiment.
client_nameClient name of the calling program as it can be seen by others (like the scl command in ODBEdit).
funcCallback function to read in a password if security has been enabled. In all command line applications this function is NULL which invokes an internal ss_gets() function to read in a password. In windows environments (MS Windows, X Windows) a function can be supplied to open a dialog box and read in the password. The argument of this function must be the returned password.
Returns
CM_SUCCESS, CM_UNDEF_EXP, CM_SET_ERROR, RPC_NET_ERROR
CM_VERSION_MISMATCH MIDAS library version different on local and remote computer

Definition at line 2352 of file midas.cxx.

2352 {
2353 INT status;
2354
2357 if (status != CM_SUCCESS) {
2358 std::string s = cm_get_error(status);
2359 puts(s.c_str());
2360 }
2361
2362 return status;
2363}
INT cm_connect_experiment1(const char *host_name, const char *default_exp_name, const char *client_name, void(*func)(char *), INT odb_size, DWORD watchdog_timeout)
Definition midas.cxx:2371
std::string cm_get_error(INT code)
Definition midas.cxx:473
#define DEFAULT_WATCHDOG_TIMEOUT
Definition midas.h:290
#define DEFAULT_ODB_SIZE
Definition midas.h:270
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_connect_experiment1()

INT cm_connect_experiment1 ( const char *  host_name,
const char *  default_exp_name,
const char *  client_name,
void(*)(char *)  func,
INT  odb_size,
DWORD  watchdog_timeout 
)

Connect to a MIDAS experiment (to the online database) on a specific host.

Definition at line 2371 of file midas.cxx.

2372 {
2373 INT status, size;
2374 char password[NAME_LENGTH], str[256];
2375 HNDLE hDB = 0, hKeyClient = 0;
2376 BOOL call_watchdog;
2377
2378 ss_tzset(); // required for localtime_r()
2379
2380 if (_hKeyClient)
2382
2384
2385 //cm_msg(MERROR, "cm_connect_experiment", "test cm_msg before connecting to experiment");
2386 //cm_msg_flush_buffer();
2387
2388 rpc_set_name(client_name);
2389
2390 /* check for local host */
2391 if (equal_ustring(host_name, "local"))
2392 host_name = NULL;
2393
2394#ifdef OS_WINNT
2395 {
2396 WSADATA WSAData;
2397
2398 /* Start windows sockets */
2399 if (WSAStartup(MAKEWORD(1, 1), &WSAData) != 0)
2400 return RPC_NET_ERROR;
2401 }
2402#endif
2403
2404 std::string default_exp_name1;
2405 if (default_exp_name)
2406 default_exp_name1 = default_exp_name;
2407
2408 /* connect to MIDAS server */
2409 if (host_name && host_name[0]) {
2410 if (default_exp_name1.length() == 0) {
2411 status = cm_select_experiment_remote(host_name, &default_exp_name1);
2412 if (status != CM_SUCCESS)
2413 return status;
2414 }
2415
2416 cm_set_experiment_name(default_exp_name1.c_str());
2417
2418 status = rpc_server_connect(host_name, default_exp_name1.c_str());
2419 if (status != RPC_SUCCESS)
2420 return status;
2421
2422 /* register MIDAS library functions */
2424 if (status != RPC_SUCCESS)
2425 return status;
2426 } else {
2427 /* lookup path for *SHM files and save it */
2428
2429#ifdef LOCAL_ROUTINES
2430 status = cm_set_experiment_local(default_exp_name1.c_str());
2431 if (status != CM_SUCCESS)
2432 return status;
2433
2434 default_exp_name1 = cm_get_experiment_name();
2435
2437
2438 INT semaphore_elog, semaphore_alarm, semaphore_history, semaphore_msg;
2439
2440 /* create alarm and elog semaphores */
2441 status = ss_semaphore_create("ALARM", &semaphore_alarm);
2442 if (status != SS_CREATED && status != SS_SUCCESS) {
2443 cm_msg(MERROR, "cm_connect_experiment", "Cannot create alarm semaphore");
2444 return status;
2445 }
2446 status = ss_semaphore_create("ELOG", &semaphore_elog);
2447 if (status != SS_CREATED && status != SS_SUCCESS) {
2448 cm_msg(MERROR, "cm_connect_experiment", "Cannot create elog semaphore");
2449 return status;
2450 }
2451 status = ss_semaphore_create("HISTORY", &semaphore_history);
2452 if (status != SS_CREATED && status != SS_SUCCESS) {
2453 cm_msg(MERROR, "cm_connect_experiment", "Cannot create history semaphore");
2454 return status;
2455 }
2456 status = ss_semaphore_create("MSG", &semaphore_msg);
2457 if (status != SS_CREATED && status != SS_SUCCESS) {
2458 cm_msg(MERROR, "cm_connect_experiment", "Cannot create message semaphore");
2459 return status;
2460 }
2461
2462 cm_set_experiment_semaphore(semaphore_alarm, semaphore_elog, semaphore_history, semaphore_msg);
2463#else
2464 return CM_UNDEF_EXP;
2465#endif
2466 }
2467
2468 //cm_msg(MERROR, "cm_connect_experiment", "test cm_msg before open ODB");
2469 //cm_msg_flush_buffer();
2470
2471 /* open ODB */
2472 if (odb_size == 0)
2474
2475 status = db_open_database("ODB", odb_size, &hDB, client_name);
2476 if (status != DB_SUCCESS && status != DB_CREATED) {
2477 cm_msg(MERROR, "cm_connect_experiment1", "cannot open database, db_open_database() status %d", status);
2478 return status;
2479 }
2480
2481 //cm_msg(MERROR, "cm_connect_experiment", "test cm_msg after open ODB");
2482 //cm_msg_flush_buffer();
2483
2484 int odb_timeout = db_set_lock_timeout(hDB, 0);
2485 size = sizeof(odb_timeout);
2486 status = db_get_value(hDB, 0, "/Experiment/ODB timeout", &odb_timeout, &size, TID_INT32, TRUE);
2487 if (status != DB_SUCCESS) {
2488 cm_msg(MERROR, "cm_connect_experiment1", "cannot get ODB /Experiment/ODB timeout, status %d", status);
2489 }
2490
2491 if (odb_timeout > 0) {
2492 db_set_lock_timeout(hDB, odb_timeout);
2493 }
2494
2495 BOOL protect_odb = FALSE;
2496 size = sizeof(protect_odb);
2497 status = db_get_value(hDB, 0, "/Experiment/Protect ODB", &protect_odb, &size, TID_BOOL, TRUE);
2498 if (status != DB_SUCCESS) {
2499 cm_msg(MERROR, "cm_connect_experiment1", "cannot get ODB /Experiment/Protect ODB, status %d", status);
2500 }
2501
2502 if (protect_odb) {
2504 }
2505
2506 BOOL enable_core_dumps = FALSE;
2507 size = sizeof(enable_core_dumps);
2508 status = db_get_value(hDB, 0, "/Experiment/Enable core dumps", &enable_core_dumps, &size, TID_BOOL, TRUE);
2509 if (status != DB_SUCCESS) {
2510 cm_msg(MERROR, "cm_connect_experiment1", "cannot get ODB /Experiment/Enable core dumps, status %d", status);
2511 }
2512
2513 if (enable_core_dumps) {
2514#ifdef RLIMIT_CORE
2515 struct rlimit limit;
2516 limit.rlim_cur = RLIM_INFINITY;
2517 limit.rlim_max = RLIM_INFINITY;
2518 status = setrlimit(RLIMIT_CORE, &limit);
2519 if (status != 0) {
2520 cm_msg(MERROR, "cm_connect_experiment", "Cannot setrlimit(RLIMIT_CORE, RLIM_INFINITY), errno %d (%s)", errno,
2521 strerror(errno));
2522 }
2523#else
2524#warning setrlimit(RLIMIT_CORE) is not available
2525#endif
2526 }
2527
2528 size = sizeof(disable_bind_rpc_to_localhost);
2529 status = db_get_value(hDB, 0, "/Experiment/Security/Enable non-localhost RPC", &disable_bind_rpc_to_localhost, &size,
2530 TID_BOOL, TRUE);
2531 if (status != DB_SUCCESS) {
2532 cm_msg(MERROR, "cm_connect_experiment1",
2533 "cannot get ODB /Experiment/Security/Enable non-localhost RPC, status %d", status);
2534 }
2535
2536 std::string local_host_name;
2537
2538 /* now setup client info */
2540 local_host_name = "localhost";
2541 else
2542 local_host_name = ss_gethostname();
2543
2544 /* check watchdog timeout */
2545 if (watchdog_timeout == 0)
2546 watchdog_timeout = DEFAULT_WATCHDOG_TIMEOUT;
2547
2548 password[0] = 0;
2549 status = cm_set_client_info(hDB, &hKeyClient, local_host_name.c_str(), client_name, rpc_get_hw_type(), password, watchdog_timeout);
2550
2551 if (status == CM_WRONG_PASSWORD) {
2552 if (func == NULL)
2553 strcpy(str, ss_getpass("Password: "));
2554 else
2555 func(str);
2556
2557 strcpy(password, ss_crypt(str, "mi"));
2558 status = cm_set_client_info(hDB, &hKeyClient, local_host_name.c_str(), client_name, rpc_get_hw_type(), password, watchdog_timeout);
2559 if (status != CM_SUCCESS) {
2560 /* disconnect */
2561 if (rpc_is_remote())
2564
2565 return status;
2566 }
2567 }
2568
2569 //cm_msg(MERROR, "cm_connect_experiment", "test cm_msg after set client info");
2570 //cm_msg_flush_buffer();
2571
2572 /* tell the rest of MIDAS that ODB is open for business */
2573
2574 cm_set_experiment_database(hDB, hKeyClient);
2575
2576 //cm_msg(MERROR, "cm_connect_experiment", "test cm_msg after set experiment database");
2577 //cm_msg_flush_buffer();
2578
2579 /* cm_msg_open_buffer() calls bm_open_buffer() calls ODB function
2580 * to get event buffer size, etc */
2581
2583 if (status != CM_SUCCESS) {
2584 cm_msg(MERROR, "cm_connect_experiment1", "cannot open message buffer, cm_msg_open_buffer() status %d", status);
2585 return status;
2586 }
2587
2588 //cm_msg(MERROR, "cm_connect_experiment", "test cm_msg after message system is ready");
2589 //cm_msg_flush_buffer();
2590
2591 /* set experiment name in ODB if not present */
2592 std::string current_name;
2593 db_get_value_string(hDB, 0, "/Experiment/Name", 0, &current_name, TRUE);
2594 if (current_name.length() == 0 || current_name == "Default") {
2595 db_set_value_string(hDB, 0, "/Experiment/Name", &default_exp_name1);
2596 }
2597
2598 if (!rpc_is_remote()) {
2599 /* experiment path is only set for local connections */
2600 /* set data dir in ODB */
2601 std::string path = cm_get_path();
2602 db_get_value_string(hDB, 0, "/Logger/Data dir", 0, &path, TRUE);
2603 }
2604
2605 /* register server to be able to be called by other clients */
2607 if (status != CM_SUCCESS) {
2608 cm_msg(MERROR, "cm_connect_experiment", "Cannot register RPC server, cm_register_server() status %d", status);
2609 if (!equal_ustring(client_name, "odbedit")) {
2610 return status;
2611 }
2612 }
2613
2614 /* set watchdog timeout */
2615 cm_get_watchdog_params(&call_watchdog, &watchdog_timeout);
2616 size = sizeof(watchdog_timeout);
2617 sprintf(str, "/Programs/%s/Watchdog Timeout", client_name);
2618 db_get_value(hDB, 0, str, &watchdog_timeout, &size, TID_INT32, TRUE);
2619 cm_set_watchdog_params(call_watchdog, watchdog_timeout);
2620
2621 /* set command line */
2622 std::string cmdline = ss_get_cmdline();
2623 std::string path = "/Programs/" + std::string(client_name);
2624 midas::odb prog(path);
2625 if (!midas::odb::exists(path + "/Start command") ||
2626 prog["Start command"] == std::string(""))
2627 prog["Start command"].set_string_size(cmdline, 256);
2628
2629 /* get final client name */
2630 std::string xclient_name = rpc_get_name();
2631
2632 /* startup message is not displayed */
2633 cm_msg(MLOG, "cm_connect_experiment", "Program %s on host %s started", xclient_name.c_str(), local_host_name.c_str());
2634
2635 /* enable system and user messages to stdout as default */
2637
2638 /* call cm_check_connect when exiting */
2639 atexit((void (*)(void)) cm_check_connect);
2640
2641 /* register ctrl-c handler */
2643
2644 //cm_msg(MERROR, "cm_connect_experiment", "test cm_msg after connect to experiment is complete");
2645 //cm_msg_flush_buffer();
2646
2647 return CM_SUCCESS;
2648}
static bool exists(const std::string &name)
Definition odbxx.cxx:76
INT cm_get_watchdog_params(BOOL *call_watchdog, DWORD *timeout)
Definition midas.cxx:3397
INT cm_select_experiment_remote(const char *host_name, std::string *exp_name)
Definition midas.cxx:2791
INT cm_register_server(void)
Definition midas.cxx:3532
void cm_check_connect(void)
Definition midas.cxx:2275
INT cm_set_client_info(HNDLE hDB, HNDLE *hKeyClient, const char *host_name, const char *program_name, INT hw_type, const char *password, DWORD watchdog_timeout)
Definition midas.cxx:1943
std::string cm_get_path()
Definition midas.cxx:1587
int cm_set_experiment_local(const char *exp_name)
Definition midas.cxx:2240
std::string cm_get_experiment_name()
Definition midas.cxx:1630
INT cm_set_experiment_database(HNDLE hDB, HNDLE hKeyClient)
Definition midas.cxx:3011
void cm_ctrlc_handler(int sig)
Definition midas.cxx:5515
INT cm_set_watchdog_params(BOOL call_watchdog, DWORD timeout)
Definition midas.cxx:3355
INT cm_set_experiment_semaphore(INT semaphore_alarm, INT semaphore_elog, INT semaphore_history, INT semaphore_msg)
Definition midas.cxx:3030
INT cm_set_experiment_name(const char *name)
Definition midas.cxx:1608
#define CM_UNDEF_EXP
Definition midas.h:586
#define CM_WRONG_PASSWORD
Definition midas.h:589
#define DB_CREATED
Definition midas.h:633
#define SS_SUCCESS
Definition midas.h:664
#define SS_CREATED
Definition midas.h:665
#define RPC_SUCCESS
Definition midas.h:699
#define RPC_NET_ERROR
Definition midas.h:702
#define TID_BOOL
Definition midas.h:340
#define MT_ALL
Definition midas.h:549
#define MLOG
Definition midas.h:563
RPC_LIST * rpc_get_internal_list(INT flag)
Definition mrpc.cxx:787
std::string ss_gethostname()
Definition system.cxx:5791
INT ss_suspend_init_odb_port()
Definition system.cxx:4384
INT ss_semaphore_create(const char *name, HNDLE *semaphore_handle)
Definition system.cxx:2532
char * ss_getpass(const char *prompt)
Definition system.cxx:7525
void ss_tzset()
Definition system.cxx:3434
std::string ss_get_cmdline(void)
Definition system.cxx:1519
char * ss_crypt(const char *buf, const char *salt)
Definition system.cxx:7976
void * ss_ctrlc_handler(void(*func)(int))
Definition system.cxx:3978
int cm_msg_early_init(void)
Definition midas.cxx:485
int cm_msg_open_buffer(void)
Definition midas.cxx:492
INT cm_set_msg_print(INT system_mask, INT user_mask, int(*func)(const char *))
Definition midas.cxx:665
INT db_get_value(HNDLE hDB, HNDLE hKeyRoot, const char *key_name, void *data, INT *buf_size, DWORD type, BOOL create)
Definition odb.cxx:5680
INT db_open_database(const char *xdatabase_name, INT database_size, HNDLE *hDB, const char *client_name)
Definition odb.cxx:2315
INT EXPRT db_get_value_string(HNDLE hdb, HNDLE hKeyRoot, const char *key_name, int index, std::string *s, BOOL create, int create_string_length)
Definition odb.cxx:14528
INT EXPRT db_set_value_string(HNDLE hDB, HNDLE hKeyRoot, const char *key_name, const std::string *s)
Definition odb.cxx:14599
INT db_set_lock_timeout(HNDLE hDB, int timeout_millisec)
Definition odb.cxx:3243
INT db_protect_database(HNDLE hDB)
Definition odb.cxx:3746
INT rpc_register_functions(const RPC_LIST *new_list, RPC_HANDLER func)
Definition midas.cxx:12060
INT rpc_server_connect(const char *host_name, const char *exp_name)
Definition midas.cxx:12614
std::string rpc_get_name()
Definition midas.cxx:13317
INT rpc_get_hw_type()
Definition midas.cxx:13067
INT rpc_server_disconnect()
Definition midas.cxx:12938
INT rpc_set_name(const char *name)
Definition midas.cxx:13341
INT odb_size
Definition analyzer.cxx:46
static int disable_bind_rpc_to_localhost
Definition midas.cxx:237
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_ctrlc_handler()

void cm_ctrlc_handler ( int  sig)

Definition at line 5515 of file midas.cxx.

5515 {
5516 if (_ctrlc_pressed) {
5517 printf("Received 2nd Ctrl-C, hard abort\n");
5518 exit(0);
5519 }
5520 printf("Received Ctrl-C, aborting...\n");
5522
5524}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_delete_client_info()

INT cm_delete_client_info ( HNDLE  hDB,
INT  pid 
)

Delete client info from database

Parameters
hDBDatabase handle
pidPID of entry to delete, zero for this process.
Returns
CM_SUCCESS

Definition at line 1902 of file midas.cxx.

1902 {
1903 /* only do it if local */
1904 if (!rpc_is_remote()) {
1906 }
1907 return CM_SUCCESS;
1908}
int db_delete_client_info(HNDLE hDB, int pid)
Definition odb.cxx:3371
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_deregister_transition()

INT cm_deregister_transition ( INT  transition)

Definition at line 3749 of file midas.cxx.

3749 {
3750 INT status;
3751 HNDLE hDB, hKey, hKeyTrans;
3752 char str[256];
3753
3754 /* check for valid transition */
3756 cm_msg(MERROR, "cm_deregister_transition", "Invalid transition request \"%d\"", transition);
3757 return CM_INVALID_TRANSITION;
3758 }
3759
3761
3762 {
3763 std::lock_guard<std::mutex> guard(_trans_table_mutex);
3764
3765 /* remove existing transition request */
3766 for (size_t i = 0; i < _trans_table.size(); i++) {
3768 _trans_table[i].transition = 0;
3769 _trans_table[i].sequence_number = 0;
3770 _trans_table[i].func = NULL;
3771 }
3772 }
3773
3774 // implicit unlock
3775 }
3776
3777 sprintf(str, "Transition %s", cm_transition_name(transition).c_str());
3778
3779 /* unlock database */
3781
3782 /* set value */
3783 status = db_find_key(hDB, hKey, str, &hKeyTrans);
3784 if (hKeyTrans) {
3785 status = db_delete_key(hDB, hKeyTrans);
3786 if (status != DB_SUCCESS)
3787 return status;
3788 }
3789
3790 /* re-lock database */
3792
3793 return CM_SUCCESS;
3794}
#define CM_INVALID_TRANSITION
Definition midas.h:594
#define TR_RESUME
Definition midas.h:408
#define TR_PAUSE
Definition midas.h:407
#define TR_START
Definition midas.h:405
#define TR_STARTABORT
Definition midas.h:409
#define MODE_DELETE
Definition midas.h:372
#define MODE_WRITE
Definition midas.h:371
#define MODE_READ
Definition midas.h:370
#define TR_STOP
Definition midas.h:406
INT db_delete_key(HNDLE hDB, HNDLE hKey, BOOL follow_links)
Definition odb.cxx:4428
INT db_set_mode(HNDLE hDB, HNDLE hKey, WORD mode, BOOL recurse)
Definition odb.cxx:8535
static std::vector< TRANS_TABLE > _trans_table
Definition midas.cxx:248
std::string cm_transition_name(int transition)
Definition midas.cxx:133
static std::mutex _trans_table_mutex
Definition midas.cxx:247
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_disconnect_client()

INT cm_disconnect_client ( HNDLE  hConn,
BOOL  bShutdown 
)

Disconnect from a MIDAS client

Parameters
hConnConnection handle obtained via cm_connect_client()
bShutdownIf TRUE, disconnect from client and shut it down (exit the client program) by sending a RPC_SHUTDOWN message
Returns
see rpc_client_disconnect()

Definition at line 2905 of file midas.cxx.

2905 {
2906 return rpc_client_disconnect(hConn, bShutdown);
2907}
INT rpc_client_disconnect(HNDLE hConn, BOOL bShutdown)
Definition midas.cxx:12909
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_disconnect_experiment()

INT cm_disconnect_experiment ( void  )

Disconnect from a MIDAS experiment.

Attention
Should be the last call to a MIDAS library function in an application before it exits. This function removes the client information from the ODB, disconnects all TCP connections and frees all internal allocated memory. See cm_connect_experiment() for example.
Returns
CM_SUCCESS

Definition at line 2918 of file midas.cxx.

2918 {
2919 HNDLE hDB, hKey;
2920
2921 //cm_msg(MERROR, "cm_disconnect_experiment", "test cm_msg before disconnect from experiment");
2922 //cm_msg_flush_buffer();
2923
2924 /* wait on any transition thread */
2925 if (_trp.transition && !_trp.finished) {
2926 printf("Waiting for transition to finish...\n");
2927 do {
2928 ss_sleep(10);
2929 } while (!_trp.finished);
2930 }
2931
2932 /* stop the watchdog thread */
2934
2935 /* send shutdown notification */
2936 std::string client_name = rpc_get_name();
2937
2938 std::string local_host_name;
2939
2941 local_host_name = "localhost";
2942 else {
2943 local_host_name = ss_gethostname();
2944 //if (strchr(local_host_name, '.'))
2945 // *strchr(local_host_name, '.') = 0;
2946 }
2947
2948 /* disconnect message not displayed */
2949 cm_msg(MLOG, "cm_disconnect_experiment", "Program %s on host %s stopped", client_name.c_str(), local_host_name.c_str());
2951
2952 if (rpc_is_remote()) {
2953 if (rpc_is_connected()) {
2954 /* close open records */
2956
2958 }
2959
2962
2964 } else {
2966
2967 /* delete client info */
2969
2970 if (hDB)
2972
2973 //cm_msg(MERROR, "cm_disconnect_experiment", "test cm_msg before close all buffers, close all databases");
2974 //cm_msg_flush_buffer();
2975
2979
2981
2982 //cm_msg(MERROR, "cm_disconnect_experiment", "test cm_msg after close all buffers, close all databases");
2983 //cm_msg_flush_buffer();
2984 }
2985
2986 if (!rpc_is_mserver())
2988
2989 /* free RPC list */
2991
2992 //cm_msg(MERROR, "cm_disconnect_experiment", "test cm_msg before deleting the message ring buffer");
2993 //cm_msg_flush_buffer();
2994
2995 /* last flush before we delete the message ring buffer */
2997
2998 //cm_msg(MERROR, "cm_disconnect_experiment", "test cm_msg after disconnect is completed");
2999 //cm_msg_flush_buffer();
3000
3001 return CM_SUCCESS;
3002}
INT bm_close_all_buffers(void)
Definition midas.cxx:7317
INT cm_stop_watchdog_thread()
Definition midas.cxx:7444
static void rpc_client_shutdown()
Definition midas.cxx:12865
INT cm_delete_client_info(HNDLE hDB, INT pid)
Definition midas.cxx:1902
INT ss_sleep(INT millisec)
Definition system.cxx:3707
int cm_msg_close_buffer(void)
Definition midas.cxx:505
INT db_close_all_records()
Definition odb.cxx:14107
INT db_close_all_databases(void)
Definition odb.cxx:2893
INT rpc_deregister_functions()
Definition midas.cxx:12103
bool rpc_is_connected(void)
Definition midas.cxx:13016
INT rpc_server_shutdown(void)
Definition midas.cxx:17685
bool rpc_is_mserver(void)
Definition midas.cxx:13051
static TR_PARAM _trp
Definition midas.cxx:302
std::atomic_bool finished
Definition midas.cxx:298
INT transition
Definition midas.cxx:291
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_dispatch_ipc()

INT cm_dispatch_ipc ( const char *  message,
int  message_size,
int  client_socket 
)

dox

Definition at line 5459 of file midas.cxx.

5478{
5479 if (message[0] == 'O') {
5480 HNDLE hDB, hKey, hKeyRoot;
5481 INT index;
5482 index = 0;
5483 sscanf(message + 2, "%d %d %d %d", &hDB, &hKeyRoot, &hKey, &index);
5484 if (client_socket) {
5485 return db_update_record_mserver(hDB, hKeyRoot, hKey, index, client_socket);
5486 } else {
5487 return db_update_record_local(hDB, hKeyRoot, hKey, index);
5488 }
5489 }
5490
5491 /* message == "B" means "resume event sender" */
5492 if (message[0] == 'B' && message[2] != ' ') {
5493 char str[NAME_LENGTH];
5494
5495 //printf("cm_dispatch_ipc: message [%s], s=%d\n", message, s);
5496
5497 mstrlcpy(str, message + 2, sizeof(str));
5498 if (strchr(str, ' '))
5499 *strchr(str, ' ') = 0;
5500
5501 if (client_socket)
5502 return bm_notify_client(str, client_socket);
5503 else
5504 return bm_push_event(str);
5505 }
5506
5507 //printf("cm_dispatch_ipc: message [%s] ignored\n", message);
5508
5509 return CM_SUCCESS;
5510}
static INT bm_push_event(const char *buffer_name)
Definition midas.cxx:11159
static INT bm_notify_client(const char *buffer_name, int s)
Definition midas.cxx:11289
INT db_update_record_local(INT hDB, INT hKeyRoot, INT hKey, int index)
Definition odb.cxx:14145
INT db_update_record_mserver(INT hDB, INT hKeyRoot, INT hKey, int index, int client_socket)
Definition odb.cxx:14192
INT index
Definition mana.cxx:271
#define message(type, str)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_exec_script()

int cm_exec_script ( const char *  odb_path_to_script)

Definition at line 5535 of file midas.cxx.

5563{
5564 HNDLE hDB, hkey;
5565 KEY key;
5566 int status;
5567
5569 if (status != DB_SUCCESS)
5570 return status;
5571
5572 status = db_find_key(hDB, 0, odb_path_to_script, &hkey);
5573 if (status != DB_SUCCESS)
5574 return status;
5575
5576 status = db_get_key(hDB, hkey, &key);
5577 if (status != DB_SUCCESS)
5578 return status;
5579
5580 std::string command;
5581
5582 if (key.type == TID_STRING) {
5583 int status = db_get_value_string(hDB, 0, odb_path_to_script, 0, &command, FALSE);
5584 if (status != DB_SUCCESS) {
5585 cm_msg(MERROR, "cm_exec_script", "Script ODB \"%s\" of type TID_STRING, db_get_value_string() error %d",
5586 odb_path_to_script, status);
5587 return status;
5588 }
5589 } else if (key.type == TID_KEY) {
5590 for (int i = 0;; i++) {
5591 HNDLE hsubkey;
5592 KEY subkey;
5593 db_enum_key(hDB, hkey, i, &hsubkey);
5594 if (!hsubkey)
5595 break;
5596 db_get_key(hDB, hsubkey, &subkey);
5597
5598 if (i > 0)
5599 command += " ";
5600
5601 if (subkey.type == TID_KEY) {
5602 cm_msg(MERROR, "cm_exec_script", "Script ODB \"%s/%s\" should not be TID_KEY", odb_path_to_script,
5603 subkey.name);
5604 return DB_TYPE_MISMATCH;
5605 } else {
5606 int size = subkey.item_size;
5607 char *buf = (char *) malloc(size);
5608 assert(buf != NULL);
5609 int status = db_get_data(hDB, hsubkey, buf, &size, subkey.type);
5610 if (status != DB_SUCCESS) {
5611 cm_msg(MERROR, "cm_exec_script", "Script ODB \"%s/%s\" of type %d, db_get_data() error %d",
5612 odb_path_to_script, subkey.name, subkey.type, status);
5613 free(buf);
5614 return status;
5615 }
5616 if (subkey.type == TID_STRING) {
5617 command += buf;
5618 } else {
5619 command += db_sprintf(buf, subkey.item_size, 0, subkey.type);
5620 }
5621 free(buf);
5622 }
5623 }
5624 } else {
5625 cm_msg(MERROR, "cm_exec_script", "Script ODB \"%s\" has invalid type %d, should be TID_STRING or TID_KEY",
5626 odb_path_to_script, key.type);
5627 return DB_TYPE_MISMATCH;
5628 }
5629
5630 // printf("exec_script: %s\n", command.c_str());
5631
5632 if (command.length() > 0) {
5633 cm_msg(MINFO, "cm_exec_script", "Executing script \"%s\" from ODB \"%s\"", command.c_str(), odb_path_to_script);
5634 ss_system(command.c_str());
5635 }
5636
5637 return SUCCESS;
5638}
#define DB_TYPE_MISMATCH
Definition midas.h:646
#define TID_KEY
Definition midas.h:349
INT ss_system(const char *command)
Definition system.cxx:2188
INT db_get_key(HNDLE hDB, HNDLE hKey, KEY *key)
Definition odb.cxx:6538
INT db_sprintf(char *string, const void *data, INT data_size, INT idx, DWORD type)
Definition odb.cxx:11426
KEY key
Definition mdump.cxx:34
Definition midas.h:1027
DWORD type
Definition midas.h:1028
char name[NAME_LENGTH]
Definition midas.h:1030
INT item_size
Definition midas.h:1033
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_execute()

INT cm_execute ( const char *  command,
char *  result,
INT  bufsize 
)

Executes command via system() call

Parameters
commandCommand string to execute
resultstdout of command
bufsizestring size in byte
Returns
CM_SUCCESS

Definition at line 5797 of file midas.cxx.

5797 {
5798 INT n;
5799 int fh;
5800 int status = 0;
5801 static int check_cm_execute = 1;
5802 static int enable_cm_execute = 0;
5803
5804 if (rpc_is_remote())
5805 return rpc_call(RPC_CM_EXECUTE, command, result, bufsize);
5806
5807 if (check_cm_execute) {
5808 int status;
5809 int size;
5810 HNDLE hDB;
5811 check_cm_execute = 0;
5812
5814 assert(status == DB_SUCCESS);
5815
5816 size = sizeof(enable_cm_execute);
5817 status = db_get_value(hDB, 0, "/Experiment/Enable cm_execute", &enable_cm_execute, &size, TID_BOOL, TRUE);
5818 assert(status == DB_SUCCESS);
5819
5820 //printf("enable_cm_execute %d\n", enable_cm_execute);
5821 }
5822
5823 if (!enable_cm_execute) {
5824 char buf[32];
5825 mstrlcpy(buf, command, sizeof(buf));
5826 cm_msg(MERROR, "cm_execute", "cm_execute(%s...) is disabled by ODB \"/Experiment/Enable cm_execute\"", buf);
5827 return CM_WRONG_PASSWORD;
5828 }
5829
5830 if (bufsize > 0) {
5831 std::string filename = msprintf("%d.tmp", ss_getpid());
5832 std::string str = msprintf("%s > %s", command, filename.c_str());
5833
5834 status = system(str.c_str());
5835
5836 fh = open(filename.c_str(), O_RDONLY, 0644);
5837 result[0] = 0;
5838 if (fh >= 0) {
5839 n = read(fh, result, bufsize - 1);
5840 result[MAX(0, n)] = 0;
5841 close(fh);
5842 }
5843 remove(filename.c_str());
5844 } else {
5845 status = system(command);
5846 }
5847
5848 if (status < 0) {
5849 cm_msg(MERROR, "cm_execute", "cm_execute(%s) error %d", command, status);
5850 return CM_SET_ERROR;
5851 }
5852
5853 return CM_SUCCESS;
5854}
#define CM_SET_ERROR
Definition midas.h:583
#define MAX(a, b)
Definition midas.h:509
INT ss_getpid(void)
Definition system.cxx:1379
#define RPC_CM_EXECUTE
Definition mrpc.h:26
DWORD n[4]
Definition mana.cxx:247
#define read(n, a, f)
static std::string remove(const std::string s, char c)
Definition mjsonrpc.cxx:253
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_exist()

INT cm_exist ( const char *  name,
BOOL  bClientName 
)

Check if a MIDAS client exists in current experiment

Parameters
nameClient name
bClientNameIf true, look for the exact client name (odbedit, odbedit1, odbedit2, ...) If false, look for the exact program name (odbedit) a any number
Returns
CM_SUCCESS, CM_NO_CLIENT

Definition at line 7594 of file midas.cxx.

7594 {
7595 INT status;
7596 HNDLE hDB, hKeyClient, hKey, hSubkey;
7597
7598 if (rpc_is_remote())
7599 return rpc_call(RPC_CM_EXIST, name, bClientName);
7600
7601 //printf("cm_exist(\"%s\",%d)\n", name, bClientName);
7602
7603 cm_get_experiment_database(&hDB, &hKeyClient);
7604
7605 status = db_find_key(hDB, 0, "System/Clients", &hKey);
7606 if (status != DB_SUCCESS)
7607 return DB_NO_KEY;
7608
7610
7611 /* loop over all clients */
7612 for (int i = 0;; i++) {
7615 break;
7616
7617 if (hSubkey == hKeyClient)
7618 continue;
7619
7620 if (status == DB_SUCCESS) {
7621 std::string client_name;
7622
7623 /* get client name */
7624 status = db_get_value_string(hDB, hSubkey, "Name", 0, &client_name);
7625
7626 if (status != DB_SUCCESS) { // invalid /System/Clients/pid entry
7627 //fprintf(stderr, "cm_exist: name %s, i=%d, hSubkey=%d, status %d, client_name %s, my name %s\n", name, i, hSubkey, status, client_name, _client_name);
7628 continue;
7629 }
7630
7631 if (bClientName) { // name is client name
7632 if (equal_ustring(client_name.c_str(), name)) {
7633 //printf("cm_exist: exact client name match \"%s\" with \"%s\"\n", client_name.c_str(), name);
7635 return CM_SUCCESS;
7636 }
7637 continue; // go to next client, will not check the program name
7638 }
7639
7640 // name is program name
7641
7642 if (equal_ustring(client_name.c_str(), name)) { // exact match
7643 //printf("cm_exist: exact client name and program name match \"%s\" with \"%s\"\n", client_name.c_str(), name);
7645 return CM_SUCCESS;
7646 }
7647
7648 std::string program_name;
7649
7650 /* get program name */
7651 status = db_get_value_string(hDB, hSubkey, "Program", 0, &program_name);
7652
7653 if (status == DB_SUCCESS) {
7654 if (equal_ustring(program_name.c_str(), name)) { // exact match
7655 //printf("cm_exist: exact program name match \"%s\" with \"%s\", client name \"%s\"\n", program_name.c_str(), name, client_name.c_str());
7657 return CM_SUCCESS;
7658 }
7659 continue;
7660 }
7661
7662 // no program name in ODB, must be an old client
7663
7664 size_t name_len = strlen(name);
7665
7666 if (client_name.length() < name_len) { // client name too short, not us
7667 //printf("cm_exist: client name too short \"%s\" against \"%s\"\n", client_name.c_str(), name);
7668 continue;
7669 }
7670
7671 std::string truncated_client_name = client_name;
7672
7673 truncated_client_name.resize(name_len); /* strip number */
7674
7675 if (equal_ustring(truncated_client_name.c_str(), name)) {
7676 //printf("cm_exist: truncated client name and program name match \"%s\" with \"%s\", client_name \"%s\"\n", truncated_client_name.c_str(), name, client_name.c_str());
7678 return CM_SUCCESS;
7679 }
7680 }
7681 }
7682
7684
7685 return CM_NO_CLIENT;
7686}
#define DB_NO_KEY
Definition midas.h:643
static DATABASE * db_lock_database(HNDLE hDB, int *pstatus, const char *caller, bool check_attached=true)
Definition odb.cxx:3003
static void db_unlock_database(DATABASE *pdb, const char *caller)
Definition odb.cxx:3165
#define RPC_CM_EXIST
Definition mrpc.h:31
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_expand_env()

std::string cm_expand_env ( const char *  str)

Expand environment variables in filesystem file path names

Examples of expansion: $FOO=foo, $BAR=bar, $UNDEF is undefined (undefined, not empty)

ok &= test_cm_expand_env1("aaa", "aaa"); ok &= test_cm_expand_env1("$FOO", "foo"); ok &= test_cm_expand_env1("/$FOO", "/foo"); ok &= test_cm_expand_env1("/$FOO/", "/foo/"); ok &= test_cm_expand_env1("$FOO/$BAR", "foo/bar"); ok &= test_cm_expand_env1("$FOO1", "$FOO1"); ok &= test_cm_expand_env1("1$FOO", "1foo"); ok &= test_cm_expand_env1("$UNDEF", "$UNDEF"); ok &= test_cm_expand_env1("/$UNDEF/", "/$UNDEF/");

Parameters
strInput file path
Returns
expanded file path

Definition at line 7823 of file midas.cxx.

7823 {
7824 const char *s = str;
7825 std::string r;
7826 for (; *s;) {
7827 if (*s == '$') {
7828 s++;
7829 std::string envname;
7830 for (; *s;) {
7831 if (*s == DIR_SEPARATOR)
7832 break;
7833 envname += *s;
7834 s++;
7835 }
7836 const char *e = getenv(envname.c_str());
7837 //printf("expanding [%s] at [%s] envname [%s] value [%s]\n", filename, s, envname.c_str(), e);
7838 if (!e) {
7839 //cm_msg(MERROR, "expand_env", "Env.variable \"%s\" cannot be expanded in \"%s\"", envname.c_str(), filename);
7840 r += '$';
7841 r += envname;
7842 } else {
7843 r += e;
7844 //if (r[r.length()-1] != DIR_SEPARATOR)
7845 //r += DIR_SEPARATOR_STR;
7846 }
7847 } else {
7848 r += *s;
7849 s++;
7850 }
7851 }
7852 return r;
7853}
#define DIR_SEPARATOR
Definition midas.h:193
static double e(void)
Definition tinyexpr.c:136
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_get_client_name()

std::string cm_get_client_name ( )

Get current client name

Returns
current client name

Definition at line 2133 of file midas.cxx.

2134{
2135 INT status;
2136 HNDLE hDB, hKey;
2137
2138 /* get root key of client */
2140 if (!hDB) {
2141 return "unknown";
2142 }
2143
2144 std::string name;
2145
2146 status = db_get_value_string(hDB, hKey, "Name", 0, &name);
2147 if (status != DB_SUCCESS) {
2148 return "unknown";
2149 }
2150
2151 //printf("get client name: [%s]\n", name.c_str());
2152
2153 return name;
2154}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_get_environment() [1/2]

INT cm_get_environment ( char *  host_name,
int  host_name_size,
char *  exp_name,
int  exp_name_size 
)

Returns MIDAS environment variables.

Attention
This function can be used to evaluate the standard MIDAS environment variables before connecting to an experiment (see Environment_variables). The usual way is that the host name and experiment name are first derived from the environment variables MIDAS_SERVER_HOST and MIDAS_EXPT_NAME. They can then be superseded by command line parameters with -h and -e flags.
#include <stdio.h>
#include <midas.h>
main(int argc, char *argv[])
{
char host_name[256],exp_name[32];
// get default values from environment
// parse command line parameters
for (i=1 ; i<argc ; i++)
{
if (argv[i][0] == '-')
{
if (i+1 >= argc || argv[i+1][0] == '-')
goto usage;
if (argv[i][1] == 'e')
strcpy(exp_name, argv[++i]);
else if (argv[i][1] == 'h')
strcpy(host_name, argv[++i]);
else
{
printf("usage: test [-h Hostname] [-e Experiment]\n\n");
return 1;
}
}
}
return 1;
...do anyting...
}
Parameters
host_nameContents of MIDAS_SERVER_HOST environment variable.
host_name_sizestring length
exp_nameContents of MIDAS_EXPT_NAME environment variable.
exp_name_sizestring length
Returns
CM_SUCCESS

Definition at line 2208 of file midas.cxx.

2208 {
2209 if (host_name)
2210 host_name[0] = 0;
2211 if (exp_name)
2212 exp_name[0] = 0;
2213
2214 if (host_name && getenv("MIDAS_SERVER_HOST"))
2215 mstrlcpy(host_name, getenv("MIDAS_SERVER_HOST"), host_name_size);
2216
2217 if (exp_name && getenv("MIDAS_EXPT_NAME"))
2218 mstrlcpy(exp_name, getenv("MIDAS_EXPT_NAME"), exp_name_size);
2219
2220 return CM_SUCCESS;
2221}
Here is the caller graph for this function:

◆ cm_get_environment() [2/2]

INT cm_get_environment ( std::string *  host_name,
std::string *  exp_name 
)

Definition at line 2223 of file midas.cxx.

2223 {
2224 if (host_name)
2225 *host_name = "";
2226 if (exp_name)
2227 *exp_name = "";
2228
2229 if (host_name && getenv("MIDAS_SERVER_HOST"))
2230 *host_name = getenv("MIDAS_SERVER_HOST");
2231
2232 if (exp_name && getenv("MIDAS_EXPT_NAME"))
2233 *exp_name = getenv("MIDAS_EXPT_NAME");
2234
2235 return CM_SUCCESS;
2236}

◆ cm_get_experiment_database()

INT cm_get_experiment_database ( HNDLE hDB,
HNDLE hKeyClient 
)

dox Get the handle to the ODB from the currently connected experiment.

Attention
This function returns the handle of the online database (ODB) which can be used in future db_xxx() calls. The hkeyclient key handle can be used to access the client information in the ODB. If the client key handle is not needed, the parameter can be NULL.
HNDLE hDB, hkeyclient;
char name[32];
int size;
db_get_experiment_database(&hdb, &hkeyclient);
size = sizeof(name);
db_get_value(hdb, hkeyclient, "Name", name, &size, TID_STRING, TRUE);
printf("My name is %s\n", name);
HNDLE hdb
Definition midas_macro.h:21
Parameters
hDBDatabase handle.
hKeyClientHandle for key where search starts, zero for root.
Returns
CM_SUCCESS

Definition at line 3083 of file midas.cxx.

3083 {
3084 if (_hDB) {
3085 //printf("cm_get_experiment_database %d %d\n", _hDB, _hKeyClient);
3086 if (hDB != NULL)
3087 *hDB = _hDB;
3088 if (hKeyClient != NULL)
3089 *hKeyClient = _hKeyClient;
3090 return CM_SUCCESS;
3091 } else {
3092 //printf("cm_get_experiment_database no init\n");
3093 if (hDB != NULL)
3094 *hDB = 0;
3095 if (hKeyClient != NULL)
3096 *hKeyClient = 0;
3097 return CM_DB_ERROR;
3098 }
3099}
#define CM_DB_ERROR
Definition midas.h:585
static HNDLE _hDB
Definition midas.cxx:1507

◆ cm_get_experiment_name() [1/2]

std::string cm_get_experiment_name ( )

Return the experiment name

Returns
experiment name

Definition at line 1630 of file midas.cxx.

1630 {
1631 return _experiment_name;
1632}
static std::string _experiment_name
Definition midas.cxx:1508
Here is the caller graph for this function:

◆ cm_get_experiment_name() [2/2]

INT cm_get_experiment_name ( char *  name,
int  name_length 
)

Return the experiment name

Parameters
namePointer to user string, size should be at least NAME_LENGTH
name_sizeSize of user string
Returns
CM_SUCCESS

Definition at line 1620 of file midas.cxx.

1620 {
1621 mstrlcpy(name, _experiment_name.c_str(), name_length);
1622 return CM_SUCCESS;
1623}

◆ cm_get_experiment_semaphore()

INT cm_get_experiment_semaphore ( INT semaphore_alarm,
INT semaphore_elog,
INT semaphore_history,
INT semaphore_msg 
)

dox

Definition at line 3105 of file midas.cxx.

3125{
3126 if (semaphore_alarm)
3127 *semaphore_alarm = _semaphore_alarm;
3128 if (semaphore_elog)
3129 *semaphore_elog = _semaphore_elog;
3130 if (semaphore_history)
3131 *semaphore_history = _semaphore_history;
3132 //if (semaphore_msg)
3133 // *semaphore_msg = _semaphore_msg;
3134 if (semaphore_msg)
3135 *semaphore_msg = -1;
3136
3137 return CM_SUCCESS;
3138}
INT _semaphore_alarm
Definition midas.cxx:1512
INT _semaphore_elog
Definition midas.cxx:1513
INT _semaphore_history
Definition midas.cxx:1514
Here is the caller graph for this function:

◆ cm_get_exptab() [1/2]

int cm_get_exptab ( const char *  expname,
char *  dir,
int  dir_size,
char *  user,
int  user_size 
)

Return exptab information for given experiment

Parameters
sPointer to string buffer
sizeSize of string buffer
Returns
CM_SUCCESS

Definition at line 1880 of file midas.cxx.

1880 {
1881 std::string sdir, suser;
1882 int status = cm_get_exptab(expname, &sdir, &suser);
1883 if (status == CM_SUCCESS) {
1884 if (dir)
1885 mstrlcpy(dir, sdir.c_str(), dir_size);
1886 if (user)
1887 mstrlcpy(user, suser.c_str(), user_size);
1888 return CM_SUCCESS;
1889 }
1890 return CM_UNDEF_EXP;
1891}
int cm_get_exptab(const char *expname, std::string *dir, std::string *user)
Definition midas.cxx:1849
Here is the call graph for this function:

◆ cm_get_exptab() [2/2]

int cm_get_exptab ( const char *  expname,
std::string *  dir,
std::string *  user 
)

Return exptab information for given experiment

Parameters
sPointer to string buffer
sizeSize of string buffer
Returns
CM_SUCCESS

Definition at line 1849 of file midas.cxx.

1849 {
1850
1851 if (_exptab.exptab.size() == 0) {
1853 if (status != CM_SUCCESS)
1854 return status;
1855 }
1856
1857 for (unsigned i = 0; i < _exptab.exptab.size(); i++) {
1858 if (_exptab.exptab[i].name == expname) {
1859 if (dir)
1860 *dir = _exptab.exptab[i].directory;
1861 if (user)
1862 *user = _exptab.exptab[i].user;
1863 return CM_SUCCESS;
1864 }
1865 }
1866 if (dir)
1867 *dir = "";
1868 if (user)
1869 *user = "";
1870 return CM_UNDEF_EXP;
1871}
static exptab_struct _exptab
Definition midas.cxx:1655
INT cm_read_exptab(exptab_struct *exptab)
Definition midas.cxx:1664
std::vector< exptab_entry > exptab
Definition midas.cxx:1652
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_get_exptab_filename() [1/2]

std::string cm_get_exptab_filename ( )

Definition at line 1838 of file midas.cxx.

1838 {
1839 return _exptab.filename;
1840}
std::string filename
Definition midas.cxx:1651
Here is the caller graph for this function:

◆ cm_get_exptab_filename() [2/2]

int cm_get_exptab_filename ( char *  s,
int  size 
)

Return location of exptab file

Parameters
sPointer to string buffer
sizeSize of string buffer
Returns
CM_SUCCESS

Definition at line 1833 of file midas.cxx.

1833 {
1834 mstrlcpy(s, _exptab.filename.c_str(), size);
1835 return CM_SUCCESS;
1836}

◆ cm_get_history_path()

std::string cm_get_history_path ( const char *  history_channel)

dox

Definition at line 5915 of file midas.cxx.

5916{
5917 int status;
5918 HNDLE hDB;
5919 std::string path;
5920
5922
5923 if (history_channel && (strlen(history_channel) > 0)) {
5924 std::string p;
5925 p += "/Logger/History/";
5926 p += history_channel;
5927 p += "/History dir";
5928
5929 // NB: be careful to avoid creating odb entries under /logger
5930 // for whatever values of "history_channel" we get called with!
5931 status = db_get_value_string(hDB, 0, p.c_str(), 0, &path, FALSE);
5932 if (status == DB_SUCCESS && path.length() > 0) {
5933 // if not absolute path, prepend with experiment directory
5934 if (path[0] != DIR_SEPARATOR)
5935 path = cm_get_path() + path;
5936 // append directory separator
5937 if (path.back() != DIR_SEPARATOR)
5938 path += DIR_SEPARATOR_STR;
5939 //printf("for [%s] returning [%s] from [%s]\n", history_channel, path.c_str(), p.c_str());
5940 return path;
5941 }
5942 }
5943
5944 status = db_get_value_string(hDB, 0, "/Logger/History dir", 0, &path, TRUE);
5945 if (status == DB_SUCCESS && path.length() > 0) {
5946 // if not absolute path, prepend with experiment directory
5947 if (path[0] != DIR_SEPARATOR)
5948 path = cm_get_path() + path;
5949 // append directory separator
5950 if (path.back() != DIR_SEPARATOR)
5951 path += DIR_SEPARATOR_STR;
5952 //printf("for [%s] returning /Logger/History dir [%s]\n", history_channel, path.c_str());
5953 return path;
5954 }
5955
5956 status = db_get_value_string(hDB, 0, "/Logger/Data dir", 0, &path, FALSE);
5957 if (status == DB_SUCCESS && path.length() > 0) {
5958 // if not absolute path, prepend with experiment directory
5959 if (path[0] != DIR_SEPARATOR)
5960 path = cm_get_path() + path;
5961 // append directory separator
5962 if (path.back() != DIR_SEPARATOR)
5963 path += DIR_SEPARATOR_STR;
5964 //printf("for [%s] returning /Logger/Data dir [%s]\n", history_channel, path.c_str());
5965 return path;
5966 }
5967
5968 //printf("for [%s] returning experiment dir [%s]\n", history_channel, cm_get_path().c_str());
5969 return cm_get_path();
5970}
#define DIR_SEPARATOR_STR
Definition midas.h:194
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_get_path() [1/2]

std::string cm_get_path ( )

Return the path name previously set with cm_set_path.

Parameters
pathPathname
Returns
CM_SUCCESS

Definition at line 1587 of file midas.cxx.

1587 {
1588 assert(_path_name.length() > 0);
1589 return _path_name;
1590}
static std::string _path_name
Definition midas.cxx:1510
Here is the caller graph for this function:

◆ cm_get_path() [2/2]

INT cm_get_path ( char *  path,
int  path_size 
)

Return the path name previously set with cm_set_path.

Parameters
pathPathname
Returns
CM_SUCCESS

Definition at line 1568 of file midas.cxx.

1568 {
1569 // check that we were not accidentally called
1570 // with the size of the pointer to a string
1571 // instead of the size of the string buffer
1572 assert(path_size != sizeof(char *));
1573 assert(path);
1574 assert(_path_name.length() > 0);
1575
1576 mstrlcpy(path, _path_name.c_str(), path_size);
1577
1578 return CM_SUCCESS;
1579}

◆ cm_get_path_string()

INT EXPRT cm_get_path_string ( std::string *  path)

Definition at line 1595 of file midas.cxx.

1595 {
1596 assert(path != NULL);
1597 assert(_path_name.length() > 0);
1598 *path = _path_name;
1599 return CM_SUCCESS;
1600}

◆ cm_get_revision()

const char * cm_get_revision ( void  )

Return git revision number of current MIDAS library as a string

Returns
revision number

Definition at line 1534 of file midas.cxx.

1534 {
1535 return GIT_REVISION;
1536}
Here is the caller graph for this function:

◆ cm_get_version()

const char * cm_get_version ( void  )

Return version number of current MIDAS library as a string

Returns
version number

Definition at line 1526 of file midas.cxx.

1526 {
1527 return MIDAS_VERSION;
1528}
#define MIDAS_VERSION
Definition midas.h:37
Here is the caller graph for this function:

◆ cm_get_watchdog_info()

INT cm_get_watchdog_info ( HNDLE  hDB,
const char *  client_name,
DWORD timeout,
DWORD last 
)

Return watchdog information about specific client

Parameters
hDBODB handle
client_nameODB client name
timeoutTimeout for this application in seconds
lastLast time watchdog was called in msec
Returns
CM_SUCCESS, CM_NO_CLIENT, DB_INVALID_HANDLE

Definition at line 3416 of file midas.cxx.

3416 {
3417 if (rpc_is_remote())
3418 return rpc_call(RPC_CM_GET_WATCHDOG_INFO, hDB, client_name, timeout, last);
3419
3420#ifdef LOCAL_ROUTINES
3421 return db_get_watchdog_info(hDB, client_name, timeout, last);
3422#else /* LOCAL_ROUTINES */
3423 return CM_SUCCESS;
3424#endif /* LOCAL_ROUTINES */
3425}
INT db_get_watchdog_info(HNDLE hDB, const char *client_name, DWORD *timeout, DWORD *last)
Definition odb.cxx:3593
#define RPC_CM_GET_WATCHDOG_INFO
Definition mrpc.h:24
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_get_watchdog_params()

INT cm_get_watchdog_params ( BOOL call_watchdog,
DWORD timeout 
)

Return the current watchdog parameters

Parameters
call_watchdogCall the cm_watchdog routine periodically
timeoutTimeout for this application in seconds
Returns
CM_SUCCESS

Definition at line 3397 of file midas.cxx.

3397 {
3398 if (call_watchdog)
3399 *call_watchdog = FALSE;
3400 if (timeout)
3401 *timeout = _watchdog_timeout;
3402
3403 return CM_SUCCESS;
3404}
static INT _watchdog_timeout
Definition midas.cxx:1511
Here is the caller graph for this function:

◆ cm_is_ctrlc_pressed()

BOOL cm_is_ctrlc_pressed ( void  )

Definition at line 5526 of file midas.cxx.

5526 {
5527 return _ctrlc_pressed;
5528}
Here is the caller graph for this function:

◆ cm_list_experiments_local()

INT cm_list_experiments_local ( STRING_LIST exp_names)

Read exptab and return all defined experiments in *exp_name[MAX_EXPERIMENTS]

Parameters
host_nameInternet host name.
exp_namelist of experiment names
Returns
CM_SUCCESS, RPC_NET_ERROR

Definition at line 2658 of file midas.cxx.

2658 {
2659 assert(exp_names != NULL);
2660 exp_names->clear();
2661
2662 if (_exptab.exptab.size() == 0) {
2664 if (status != CM_SUCCESS)
2665 return status;
2666 }
2667
2668 for (unsigned i=0; i<_exptab.exptab.size(); i++) {
2669 exp_names->push_back(_exptab.exptab[i].name);
2670 }
2671
2672 return CM_SUCCESS;
2673}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_list_experiments_remote()

INT cm_list_experiments_remote ( const char *  host_name,
STRING_LIST exp_names 
)

Connect to a MIDAS server and return all defined experiments in *exp_name[MAX_EXPERIMENTS]

Parameters
host_nameInternet host name.
exp_namelist of experiment names
Returns
CM_SUCCESS, RPC_NET_ERROR

Definition at line 2684 of file midas.cxx.

2684 {
2685 INT status;
2686 INT sock;
2687 int port = MIDAS_TCP_PORT;
2688 char hname[256];
2689 char *s;
2690
2691 assert(exp_names != NULL);
2692 exp_names->clear();
2693
2694 /* extract port number from host_name */
2695 mstrlcpy(hname, host_name, sizeof(hname));
2696 s = strchr(hname, ':');
2697 if (s) {
2698 *s = 0;
2699 port = strtoul(s + 1, NULL, 0);
2700 }
2701
2702 std::string errmsg;
2703
2704 status = ss_socket_connect_tcp(hname, port, &sock, &errmsg);
2705
2706 if (status != SS_SUCCESS) {
2707 cm_msg(MERROR, "cm_list_experiments_remote", "Cannot connect to \"%s\" port %d: %s", hname, port, errmsg.c_str());
2708 return RPC_NET_ERROR;
2709 }
2710
2711 /* request experiment list */
2712 send(sock, "I", 2, 0);
2713
2714 while (1) {
2715 char str[256];
2716
2717 status = recv_string(sock, str, sizeof(str), _rpc_connect_timeout);
2718
2719 if (status < 0)
2720 return RPC_NET_ERROR;
2721
2722 if (status == 0)
2723 break;
2724
2725 exp_names->push_back(str);
2726 }
2727
2728 ss_socket_close(&sock);
2729
2730 return CM_SUCCESS;
2731}
INT recv_string(int sock, char *buffer, DWORD buffer_size, INT millisec)
Definition system.cxx:5478
INT ss_socket_connect_tcp(const char *hostname, int tcp_port, int *sockp, std::string *error_msg_p)
Definition system.cxx:5046
INT ss_socket_close(int *sockp)
Definition system.cxx:5310
static int _rpc_connect_timeout
Definition midas.cxx:233
#define MIDAS_TCP_PORT
Definition midas.h:283
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_periodic_tasks()

INT cm_periodic_tasks ( void  )

Perform midas periodic tasks - check alarms, update and check timeouts on odb and on event buffers, etc. Normally called by cm_yield(). Programs that do not use cm_yield(), i.e. the mserver, should call this function periodically, every 1 or 2 seconds.

Returns
CM_SUCCESS

Definition at line 5653 of file midas.cxx.

5653 {
5654 static DWORD alarm_last_checked_sec = 0;
5655 DWORD now_sec = ss_time();
5656
5657 DWORD now_millitime = ss_millitime();
5658 static DWORD last_millitime = 0;
5659 DWORD tdiff_millitime = now_millitime - last_millitime;
5660 const DWORD kPeriod = 1000;
5661 if (last_millitime == 0) {
5662 last_millitime = now_millitime;
5663 tdiff_millitime = kPeriod; // make sure first time we come here we do something.
5664 }
5665
5666 //printf("cm_periodic_tasks! tdiff_millitime %d\n", (int)tdiff_millitime);
5667
5668 //if (now_millitime < last_millitime) {
5669 // printf("millitime wraparound 0x%08x -> 0x%08x\n", last_millitime, now_millitime);
5670 //}
5671
5672 /* check alarms once every 10 seconds */
5673 if (now_sec - alarm_last_checked_sec > 10) {
5674 al_check();
5675 alarm_last_checked_sec = now_sec;
5676 }
5677
5678 /* run periodic checks previously done by cm_watchdog */
5679
5680 if (tdiff_millitime >= kPeriod) {
5681 BOOL wrong_interval = FALSE;
5682 if (tdiff_millitime > 60000)
5683 wrong_interval = TRUE;
5684
5685 //printf("millitime %u, diff %u, wrong_interval %d\n", now_millitime, tdiff_millitime, wrong_interval);
5686
5687 bm_cleanup("cm_periodic_tasks", now_millitime, wrong_interval);
5688 db_cleanup("cm_periodic_tasks", now_millitime, wrong_interval);
5689
5691
5692 last_millitime = now_millitime;
5693 }
5694
5695 /* reap transition thread */
5696
5698
5699 return CM_SUCCESS;
5700}
INT al_check()
Definition alarm.cxx:692
INT bm_write_statistics_to_odb(void)
Definition midas.cxx:7354
static void bm_cleanup(const char *who, DWORD actual_time, BOOL wrong_interval)
Definition midas.cxx:6224
INT cm_transition_cleanup()
Definition midas.cxx:5341
DWORD ss_time()
Definition system.cxx:3541
void db_cleanup(const char *who, DWORD actual_time, BOOL wrong_interval)
Definition odb.cxx:3406
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_read_exptab()

INT cm_read_exptab ( exptab_struct exptab)

Scan the "exptab" file for MIDAS experiment names and save them for later use by rpc_server_accept(). The file is first searched under $MIDAS/exptab if present, then the directory from argv[0] is probed.

Returns
CM_SUCCESS
CM_UNDEF_EXP exptab not found and MIDAS_DIR not set

Definition at line 1664 of file midas.cxx.

1665{
1666 exptab->exptab.clear();
1667
1668 /* MIDAS_DIR overrides exptab */
1669 if (getenv("MIDAS_DIR")) {
1670 exptab->filename = "MIDAS_DIR";
1671
1673
1674 if (getenv("MIDAS_EXPT_NAME")) {
1675 e.name = getenv("MIDAS_EXPT_NAME");
1676 } else {
1677 e.name = "Default";
1678 cm_msg(MERROR, "cm_read_exptab", "Experiments that use MIDAS_DIR must also set MIDAS_EXPT_NAME to the name of the experiment! Using experiment name \"%s\"", e.name.c_str());
1679 }
1680
1681 e.directory = getenv("MIDAS_DIR");
1682 e.user = "";
1683
1684 exptab->exptab.push_back(e);
1685
1686 return CM_SUCCESS;
1687 }
1688
1689 /* default directory for different OSes */
1690#if defined (OS_WINNT)
1691 std::string str;
1692 if (getenv("SystemRoot"))
1693 str = getenv("SystemRoot");
1694 else if (getenv("windir"))
1695 str = getenv("windir");
1696 else
1697 str = "";
1698
1699 std::string alt_str = str;
1700 str += "\\system32\\exptab";
1701 alt_str += "\\system\\exptab";
1702#elif defined (OS_UNIX)
1703 std::string str = "/etc/exptab";
1704 std::string alt_str = "/exptab";
1705#else
1706 std::strint str = "exptab";
1707 std::string alt_str = "exptab";
1708#endif
1709
1710 /* MIDAS_EXPTAB overrides default directory */
1711 if (getenv("MIDAS_EXPTAB")) {
1712 str = getenv("MIDAS_EXPTAB");
1713 alt_str = getenv("MIDAS_EXPTAB");
1714 }
1715
1716 exptab->filename = str;
1717
1718 /* read list of available experiments */
1719 FILE* f = fopen(str.c_str(), "r");
1720 if (f == NULL) {
1721 f = fopen(alt_str.c_str(), "r");
1722 if (f == NULL)
1723 return CM_UNDEF_ENVIRON;
1724 exptab->filename = alt_str;
1725 }
1726
1727 if (f != NULL) {
1728 do {
1729 char buf[256];
1730 memset(buf, 0, sizeof(buf));
1731 char* str = fgets(buf, sizeof(buf)-1, f);
1732 if (str == NULL)
1733 break;
1734 if (str[0] == 0) continue; // empty line
1735 if (str[0] == '#') continue; // comment line
1736
1738
1739 // following code emulates the function of this sprintf():
1740 //sscanf(str, "%s %s %s", exptab[i].name, exptab[i].directory, exptab[i].user);
1741
1742 // skip leading spaces
1743 while (*str && isspace(*str))
1744 str++;
1745
1746 char* p1 = str;
1747 char* p2 = str;
1748
1749 while (*p2 && !isspace(*p2))
1750 p2++;
1751
1752 ssize_t len = p2-p1;
1753
1754 if (len<1)
1755 continue;
1756
1757 //printf("str %d [%s] p1 [%s] p2 %d [%s] len %d\n", *str, str, p1, *p2, p2, (int)len);
1758
1759 e.name = std::string(p1, len);
1760
1761 if (*p2 == 0)
1762 continue;
1763
1764 str = p2;
1765
1766 // skip leading spaces
1767 while (*str && isspace(*str))
1768 str++;
1769
1770 p1 = str;
1771 p2 = str;
1772
1773 while (*p2 && !isspace(*p2))
1774 p2++;
1775
1776 len = p2-p1;
1777
1778 if (len<1)
1779 continue;
1780
1781 //printf("str %d [%s] p1 [%s] p2 %d [%s] len %d\n", *str, str, p1, *p2, p2, (int)len);
1782
1783 e.directory = std::string(p1, len);
1784
1785 if (*p2 == 0)
1786 continue;
1787
1788 str = p2;
1789
1790 // skip leading spaces
1791 while (*str && isspace(*str))
1792 str++;
1793
1794 p1 = str;
1795 p2 = str;
1796
1797 while (*p2 && !isspace(*p2))
1798 p2++;
1799
1800 len = p2-p1;
1801
1802 //printf("str %d [%s] p1 [%s] p2 %d [%s] len %d\n", *str, str, p1, *p2, p2, (int)len);
1803
1804 e.user = std::string(p1, len);
1805
1806 /* check for trailing directory separator */
1807 if (!ends_with_char(e.directory, DIR_SEPARATOR)) {
1808 e.directory += DIR_SEPARATOR_STR;
1809 }
1810
1811 exptab->exptab.push_back(e);
1812 } while (!feof(f));
1813 fclose(f);
1814 }
1815
1816#if 0
1817 cm_msg(MINFO, "cm_read_exptab", "Read exptab \"%s\":", exptab->filename.c_str());
1818 for (unsigned j=0; j<exptab->exptab.size(); j++) {
1819 cm_msg(MINFO, "cm_read_exptab", "entry %d, experiment \"%s\", directory \"%s\", user \"%s\"", j, exptab->exptab[j].name.c_str(), exptab->exptab[j].directory.c_str(), exptab->exptab[j].user.c_str());
1820 }
1821#endif
1822
1823 return CM_SUCCESS;
1824}
#define CM_UNDEF_ENVIRON
Definition midas.h:590
bool ends_with_char(const std::string &s, char c)
Definition midas.cxx:412
Definition midas.cxx:1644
std::string name
Definition midas.cxx:1645
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_register_deferred_transition()

INT cm_register_deferred_transition ( INT  transition,
BOOL(*)(INT, BOOL func 
)

dox Register a deferred transition handler. If a client is registered as a deferred transition handler, it may defer a requested transition by returning FALSE until a certain condition (like a motor reaches its end position) is reached.

Parameters
transitionOne of TR_xxx
(*func)Function which gets called whenever a transition is requested. If it returns FALSE, the transition is not performed.
Returns
CM_SUCCESS, <error> Error from ODB access

Definition at line 3917 of file midas.cxx.

3917 {
3918 INT status, size;
3919 char tr_key_name[256];
3920 HNDLE hDB, hKey;
3921
3923
3924 for (int i = 0; _deferred_trans_table[i].transition; i++)
3926 _deferred_trans_table[i].func = (int (*)(int, char *)) func;
3927
3928 /* set new transition mask */
3930
3931 sprintf(tr_key_name, "Transition %s DEFERRED", cm_transition_name(transition).c_str());
3932
3933 /* unlock database */
3935
3936 /* set value */
3937 int i = 0;
3938 status = db_set_value(hDB, hKey, tr_key_name, &i, sizeof(INT), 1, TID_INT32);
3939 if (status != DB_SUCCESS)
3940 return status;
3941
3942 /* re-lock database */
3944
3945 /* hot link requested transition */
3946 size = sizeof(_requested_transition);
3947 db_get_value(hDB, 0, "/Runinfo/Requested Transition", &_requested_transition, &size, TID_INT32, TRUE);
3948 db_find_key(hDB, 0, "/Runinfo/Requested Transition", &hKey);
3949 status = db_open_record(hDB, hKey, &_requested_transition, sizeof(INT), MODE_READ, NULL, NULL);
3950 if (status != DB_SUCCESS) {
3951 cm_msg(MERROR, "cm_register_deferred_transition", "Cannot hotlink /Runinfo/Requested Transition");
3952 return status;
3953 }
3954
3955 return CM_SUCCESS;
3956}
INT db_open_record(HNDLE hDB, HNDLE hKey, void *ptr, INT rec_size, WORD access_mode, void(*dispatcher)(INT, INT, void *), void *info)
Definition odb.cxx:13883
INT db_set_value(HNDLE hDB, HNDLE hKeyRoot, const char *key_name, const void *data, INT data_size, INT num_values, DWORD type)
Definition odb.cxx:5523
INT(* func)(INT, char *)
Definition midas.cxx:244
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_register_function()

INT cm_register_function ( INT  id,
INT(*)(INT, void **)  func 
)

dox

Definition at line 5862 of file midas.cxx.

5882{
5883 HNDLE hDB, hKey;
5884 INT status;
5885 char str[80];
5886
5887 status = rpc_register_function(id, func);
5888 if (status != RPC_SUCCESS)
5889 return status;
5890
5892
5893 /* create new key for this id */
5894 status = 1;
5895 sprintf(str, "RPC/%d", id);
5896
5898 status = db_set_value(hDB, hKey, str, &status, sizeof(BOOL), 1, TID_BOOL);
5900
5901 if (status != DB_SUCCESS)
5902 return status;
5903
5904 return CM_SUCCESS;
5905}
INT rpc_register_function(INT id, INT(*func)(INT, void **))
Definition midas.cxx:12130
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_register_server()

INT cm_register_server ( void  )

Definition at line 3532 of file midas.cxx.

3550{
3551 if (!_rpc_registered) {
3552 INT status;
3553 int size;
3554 HNDLE hDB, hKey;
3555 char name[NAME_LENGTH];
3556 char str[256];
3557 int port = 0;
3558
3560
3561 size = sizeof(name);
3562 status = db_get_value(hDB, hKey, "Name", &name, &size, TID_STRING, FALSE);
3563
3564 if (status != DB_SUCCESS) {
3565 cm_msg(MERROR, "cm_register_server", "cannot get client name, db_get_value() status %d", status);
3566 return status;
3567 }
3568
3569 mstrlcpy(str, "/Experiment/Security/RPC ports/", sizeof(str));
3570 mstrlcat(str, name, sizeof(str));
3571
3572 size = sizeof(port);
3573 status = db_get_value(hDB, 0, str, &port, &size, TID_UINT32, TRUE);
3574
3575 if (status != DB_SUCCESS) {
3576 cm_msg(MERROR, "cm_register_server", "cannot get RPC port number, db_get_value(%s) status %d", str, status);
3577 return status;
3578 }
3579
3580 int lport = 0; // actual port number assigned to us by the OS
3581
3583 if (status != RPC_SUCCESS) {
3584 cm_msg(MERROR, "cm_register_server", "error, rpc_register_server(port=%d) status %d", port, status);
3585 return status;
3586 }
3587
3589
3590 /* register MIDAS library functions */
3592
3593 /* store port number in ODB */
3594
3595 status = db_find_key(hDB, hKey, "Server Port", &hKey);
3596 if (status != DB_SUCCESS) {
3597 cm_msg(MERROR, "cm_register_server", "error, db_find_key(\"Server Port\") status %d", status);
3598 return status;
3599 }
3600
3601 /* unlock database */
3603
3604 /* set value */
3605 status = db_set_data(hDB, hKey, &lport, sizeof(INT), 1, TID_INT32);
3606 if (status != DB_SUCCESS) {
3607 cm_msg(MERROR, "cm_register_server", "error, db_set_data(\"Server Port\"=%d) status %d", port, status);
3608 return status;
3609 }
3610
3611 /* lock database */
3613
3615 }
3616
3617 return CM_SUCCESS;
3618}
static void init_rpc_hosts(HNDLE hDB)
Definition midas.cxx:3484
INT db_set_data(HNDLE hDB, HNDLE hKey, const void *data, INT buf_size, INT num_values, DWORD type)
Definition odb.cxx:7734
INT rpc_register_server(int port, int *plsock, int *pport)
Definition midas.cxx:15086
static BOOL _rpc_registered
Definition midas.cxx:258
static int _rpc_listen_socket
Definition midas.cxx:259
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_register_transition()

INT cm_register_transition ( INT  transition,
INT(*)(INT, char *)  func,
INT  sequence_number 
)

dox Registers a callback function for run transitions. This function internally registers the transition callback function and publishes its request for transition notification by writing a transition request to /System/Clients/<pid>/Transition XXX. Other clients making a transition scan the transition requests of all clients and call their transition callbacks via RPC.

Clients can register for transitions (Start/Stop/Pause/Resume) in a given sequence. All sequence numbers given in the registration are sorted on a transition and the clients are contacted in ascending order. By default, all programs register with a sequence number of 500. The logger however uses 200 for start, so that it can open files before the other clients are contacted, and 800 for stop, so that the files get closed when all other clients have gone already through the stop trantition.

The callback function returns CM_SUCCESS if it can perform the transition or a value larger than one in case of error. An error string can be copied into the error variable.

Attention
The callback function will be called on transitions from inside the cm_yield() function which therefore must be contained in the main program loop.
INT start(INT run_number, char *error)
{
if (<not ok>)
{
strcpy(error, "Cannot start because ...");
return 2;
}
printf("Starting run %d\n", run_number);
return CM_SUCCESS;
}
{
...
do
{
status = cm_yield(1000);
} while (status != RPC_SHUTDOWN &&
...
}
INT cm_register_transition(INT transition, INT(*func)(INT, char *), INT sequence_number)
Definition midas.cxx:3673
INT cm_yield(INT millisec)
Definition midas.cxx:5716
#define SS_ABORT
Definition midas.h:678
#define RPC_SHUTDOWN
Definition midas.h:708
INT run_number[2]
Definition mana.cxx:246
Parameters
transitionTransition to register for (see state_transition)
funcCallback function.
sequence_numberSequence number for that transition (1..1000)
Returns
CM_SUCCESS

Definition at line 3673 of file midas.cxx.

3673 {
3674 INT status;
3675 HNDLE hDB, hKey, hKeyTrans;
3676 KEY key;
3677 char str[256];
3678
3679 /* check for valid transition */
3681 cm_msg(MERROR, "cm_register_transition", "Invalid transition request \"%d\"", transition);
3682 return CM_INVALID_TRANSITION;
3683 }
3684
3686
3688
3689 /* register new transition request */
3690
3691 {
3692 std::lock_guard<std::mutex> guard(_trans_table_mutex);
3693
3694 for (size_t i = 0; i < _trans_table.size(); i++) {
3695 if (_trans_table[i].transition == transition && _trans_table[i].sequence_number == sequence_number) {
3696 cm_msg(MERROR, "cm_register_transition", "transition %s with sequence number %d is already registered", cm_transition_name(transition).c_str(), sequence_number);
3697 return CM_INVALID_TRANSITION;
3698 }
3699 }
3700
3701 bool found = false;
3702 for (size_t i = 0; i < _trans_table.size(); i++) {
3703 if (!_trans_table[i].transition) {
3704 _trans_table[i].transition = transition;
3705 _trans_table[i].sequence_number = sequence_number;
3706 _trans_table[i].func = func;
3707 found = true;
3708 break;
3709 }
3710 }
3711
3712 if (!found) {
3713 TRANS_TABLE tt;
3715 tt.sequence_number = sequence_number;
3716 tt.func = func;
3717 _trans_table.push_back(tt);
3718 }
3719
3720 // implicit unlock
3721 }
3722
3723 sprintf(str, "Transition %s", cm_transition_name(transition).c_str());
3724
3725 /* unlock database */
3727
3728 /* set value */
3729 status = db_find_key(hDB, hKey, str, &hKeyTrans);
3730 if (!hKeyTrans) {
3731 status = db_set_value(hDB, hKey, str, &sequence_number, sizeof(INT), 1, TID_INT32);
3732 if (status != DB_SUCCESS)
3733 return status;
3734 } else {
3735 status = db_get_key(hDB, hKeyTrans, &key);
3736 if (status != DB_SUCCESS)
3737 return status;
3738 status = db_set_data_index(hDB, hKeyTrans, &sequence_number, sizeof(INT), key.num_values, TID_INT32);
3739 if (status != DB_SUCCESS)
3740 return status;
3741 }
3742
3743 /* re-lock database */
3745
3746 return CM_SUCCESS;
3747}
INT db_set_data_index(HNDLE hDB, HNDLE hKey, const void *data, INT data_size, INT idx, DWORD type)
Definition odb.cxx:8163
#define RPC_RC_TRANSITION
Definition mrpc.h:117
static INT rpc_transition_dispatch(INT idx, void *prpc_param[])
Definition midas.cxx:14606
INT num_values
Definition midas.h:1029
INT sequence_number
Definition midas.cxx:243
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_select_experiment_local()

INT cm_select_experiment_local ( std::string *  exp_name)

Read exptab and select an experiment from the experiments available on this server

Parameters
exp_nameselected experiment name
Returns
CM_SUCCESS

Definition at line 2742 of file midas.cxx.

2742 {
2743 INT status;
2744 STRING_LIST expts;
2745
2746 assert(exp_name != NULL);
2747
2748 /* retrieve list of experiments and make selection */
2750 if (status != CM_SUCCESS)
2751 return status;
2752
2753 if (expts.size() == 1) {
2754 *exp_name = expts[0];
2755 } else if (expts.size() > 1) {
2756 printf("Available experiments on local computer:\n");
2757
2758 for (unsigned i = 0; i < expts.size(); i++) {
2759 printf("%d : %s\n", i, expts[i].c_str());
2760 }
2761
2762 while (1) {
2763 printf("Select number from 0 to %d: ", ((int)expts.size())-1);
2764 char str[32];
2765 ss_gets(str, 32);
2766 int isel = atoi(str);
2767 if (isel < 0)
2768 continue;
2769 if (isel >= (int)expts.size())
2770 continue;
2771 *exp_name = expts[isel];
2772 break;
2773 }
2774 } else {
2775 return CM_UNDEF_EXP;
2776 }
2777
2778 return CM_SUCCESS;
2779}
INT cm_list_experiments_local(STRING_LIST *exp_names)
Definition midas.cxx:2658
char * ss_gets(char *string, int size)
Definition system.cxx:7855
std::vector< std::string > STRING_LIST
Definition midas.h:246
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_select_experiment_remote()

INT cm_select_experiment_remote ( const char *  host_name,
std::string *  exp_name 
)

Connect to a MIDAS server and select an experiment from the experiments available on this server

Parameters
host_nameInternet host name.
exp_nameselected experiment name
Returns
CM_SUCCESS, RPC_NET_ERROR

Definition at line 2791 of file midas.cxx.

2791 {
2792 INT status;
2793 STRING_LIST expts;
2794
2795 assert(exp_name != NULL);
2796
2797 /* retrieve list of experiments and make selection */
2799 if (status != CM_SUCCESS)
2800 return status;
2801
2802 if (expts.size() > 1) {
2803 printf("Available experiments on server %s:\n", host_name);
2804
2805 for (unsigned i = 0; i < expts.size(); i++) {
2806 printf("%d : %s\n", i, expts[i].c_str());
2807 }
2808
2809 while (1) {
2810 printf("Select number from 0 to %d: ", ((int)expts.size())-1);
2811 char str[32];
2812 ss_gets(str, 32);
2813 int isel = atoi(str);
2814 if (isel < 0)
2815 continue;
2816 if (isel >= (int)expts.size())
2817 continue;
2818 *exp_name = expts[isel];
2819 break;
2820 }
2821 } else {
2822 *exp_name = expts[0];
2823 }
2824
2825 return CM_SUCCESS;
2826}
INT cm_list_experiments_remote(const char *host_name, STRING_LIST *exp_names)
Definition midas.cxx:2684
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_set_client_info()

INT cm_set_client_info ( HNDLE  hDB,
HNDLE hKeyClient,
const char *  host_name,
const char *  program_name,
INT  hw_type,
const char *  password,
DWORD  watchdog_timeout 
)

Set client information in online database and return handle

Parameters
hDBHandle to online database
hKeyClientreturned key
host_nameserver name
client_nameName of this program as it will be seen by other clients.
hw_typeType of byte order
passwordMIDAS password
watchdog_timeoutDefault watchdog timeout, can be overwritten by ODB setting /programs/<name>/Watchdog timeout
Returns
CM_SUCCESS

Definition at line 1943 of file midas.cxx.

1944 {
1945 if (rpc_is_remote())
1946 return rpc_call(RPC_CM_SET_CLIENT_INFO, hDB, hKeyClient,
1947 host_name, program_name, hw_type, password, watchdog_timeout);
1948
1949#ifdef LOCAL_ROUTINES
1950 {
1951 INT status, data, i, idx, size;
1953 char pwd[NAME_LENGTH];
1954 BOOL call_watchdog, allow;
1955
1956 std::string start_command(255, '\0');
1957 std::string alarm_class(31, '\0');
1958 midas::odb program_info = {
1959 {"Required", false},
1960 {"Watchdog timeout", 10000},
1961 {"Check interval", (uint32_t)180000},
1962 {"Start command", start_command},
1963 {"Auto start", false},
1964 {"Auto stop", false},
1965 {"Auto restart", false},
1966 {"Alarm class", alarm_class},
1967 {"First failed", (uint32_t)0}
1968 };
1969
1970 if (strlen(program_name) >= NAME_LENGTH) {
1971 cm_msg(MINFO, "cm_set_client_info", "Client name \"%s\" length %zu is longer than NAME_LENGTH %d", program_name, strlen(program_name), NAME_LENGTH);
1972 return CM_SET_ERROR;
1973 }
1974
1975 /* check security if password is present */
1976 status = db_find_key(hDB, 0, "/Experiment/Security/Password", &hKey);
1977 if (hKey) {
1978 /* get password */
1979 size = sizeof(pwd);
1980 db_get_data(hDB, hKey, pwd, &size, TID_STRING);
1981
1982 /* first check allowed hosts list */
1983 allow = FALSE;
1984 db_find_key(hDB, 0, "/Experiment/Security/Allowed hosts", &hKey);
1986 allow = TRUE;
1987
1988 /* check allowed programs list */
1989 db_find_key(hDB, 0, "/Experiment/Security/Allowed programs", &hKey);
1990 if (hKey && db_find_key(hDB, hKey, program_name, &hKey) == DB_SUCCESS)
1991 allow = TRUE;
1992
1993 /* now check password */
1994 if (!allow && strcmp(password, pwd) != 0) {
1995 if (password[0])
1996 cm_msg(MINFO, "cm_set_client_info", "Wrong password for host \"%s\"", host_name);
1997 return CM_WRONG_PASSWORD;
1998 }
1999 }
2000
2001 /* make following operation atomic by locking database */
2003
2004 /* check if entry with this pid exists already */
2005 pid_t pid = ss_getpid();
2006
2007 std::string str = msprintf("System/Clients/%0d", pid);
2008
2009 status = db_find_key(hDB, 0, str.c_str(), &hKey);
2010
2011 if (status == DB_SUCCESS) {
2013 db_delete(hDB, 0, str.c_str());
2014 hKey = 0; // invalid after db_delete(). K.O. Aug 2026
2015 }
2016
2017 std::string client_name = program_name;
2018
2019 /* check if client name already exists */
2020 status = db_find_key(hDB, 0, "System/Clients", &hKey);
2021
2022 for (idx = 1; status != DB_NO_MORE_SUBKEYS; idx++) {
2023 for (i = 0;; i++) {
2026 break;
2027
2028 if (status == DB_SUCCESS) {
2029 status = db_get_value_string(hDB, hSubkey, "Name", 0, &str);
2030 if (status != DB_SUCCESS)
2031 continue;
2032 }
2033
2034 /* check if client is living */
2036 continue;
2037
2038 if (equal_ustring(str.c_str(), client_name.c_str())) {
2039 client_name = msprintf("%s%d", program_name, idx);
2040 break;
2041 }
2042 }
2043 }
2044
2045 /* set name */
2046 str = msprintf("System/Clients/%0d/Name", pid);
2047
2048 status = db_set_value(hDB, 0, str.c_str(), client_name.c_str(), NAME_LENGTH, 1, TID_STRING);
2049 if (status != DB_SUCCESS) {
2051 cm_msg(MERROR, "cm_set_client_info", "cannot set client name, db_set_value(%s) status %d", str.c_str(), status);
2052 return status;
2053 }
2054
2055 /* name is the new client name */
2056
2057 db_set_client_name(hDB, client_name.c_str());
2058
2059 /* set also as rpc name */
2060 rpc_set_name(client_name.c_str());
2061
2062 /* use /system/clients/PID as root */
2063 str = msprintf("System/Clients/%0d", pid);
2064 db_find_key(hDB, 0, str.c_str(), &hKey);
2065
2066 /* set program name */
2067 status = db_set_value(hDB, hKey, "Program", program_name, NAME_LENGTH, 1, TID_STRING);
2068 if (status != DB_SUCCESS) {
2070 return status;
2071 }
2072
2073 /* set host name */
2075 if (status != DB_SUCCESS) {
2077 return status;
2078 }
2079
2080 /* set computer id */
2081 status = db_set_value(hDB, hKey, "Hardware type", &hw_type, sizeof(hw_type), 1, TID_INT32);
2082 if (status != DB_SUCCESS) {
2084 return status;
2085 }
2086
2087 /* set server port */
2088 data = 0;
2089 status = db_set_value(hDB, hKey, "Server Port", &data, sizeof(INT), 1, TID_INT32);
2090 if (status != DB_SUCCESS) {
2092 return status;
2093 }
2094
2095 /* lock client entry */
2097
2098 /* get (set) default watchdog timeout */
2099 size = sizeof(watchdog_timeout);
2100 str = msprintf("/Programs/%s/Watchdog Timeout", program_name);
2101 db_get_value(hDB, 0, str.c_str(), &watchdog_timeout, &size, TID_INT32, TRUE);
2102
2103 /* save handle for ODB and client */
2105
2106 /* define /programs entry */
2107 str = msprintf("/Programs/%s", program_name);
2108 program_info.connect(str.c_str());
2109
2110 /* save watchdog timeout */
2111 cm_get_watchdog_params(&call_watchdog, NULL);
2112 cm_set_watchdog_params(call_watchdog, watchdog_timeout);
2113
2114 /* end of atomic operations */
2116
2117 /* touch notify key to inform others */
2118 data = 0;
2119 db_set_value(hDB, 0, "/System/Client Notify", &data, sizeof(data), 1, TID_INT32);
2120
2121 *hKeyClient = hKey;
2122 }
2123#endif /* LOCAL_ROUTINES */
2124
2125 return CM_SUCCESS;
2126}
void connect(const std::string &path, const std::string &name, bool write_defaults, bool delete_keys_not_in_defaults=false)
Definition odbxx.cxx:1390
INT cm_check_client(HNDLE hDB, HNDLE hKeyClient)
Definition midas.cxx:1919
INT db_delete(HNDLE hDB, HNDLE hKeyRoot, const char *odb_path)
Definition odb.cxx:4494
INT db_set_client_name(HNDLE hDB, const char *client_name)
Definition odb.cxx:2935
#define RPC_CM_SET_CLIENT_INFO
Definition mrpc.h:21
void * data
Definition mana.cxx:268
char pwd[256]
Definition odbedit.cxx:24
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_set_client_run_state()

INT cm_set_client_run_state ( INT  state)

Definition at line 3863 of file midas.cxx.

3863 {
3864 INT status;
3865 HNDLE hDB, hKey;
3866 KEY key;
3867
3869
3870 /* check that hKey is still valid */
3872
3873 if (status != DB_SUCCESS) {
3874 cm_msg(MERROR, "cm_set_client_run_state",
3875 "Cannot set client run state, client hKey %d into /System/Clients is not valid, maybe this client was removed by a watchdog timeout",
3876 hKey);
3877 return status;
3878 }
3879
3880 /* unlock database */
3882
3883 /* set value */
3884 status = db_set_value(hDB, hKey, "Run state", &state, sizeof(INT), 1, TID_INT32);
3885 if (status != DB_SUCCESS)
3886 return status;
3887
3888 /* re-lock database */
3890
3891 return CM_SUCCESS;
3892
3893}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_set_experiment_database()

INT cm_set_experiment_database ( HNDLE  hDB,
HNDLE  hKeyClient 
)

Set the handle to the ODB for the currently connected experiment

Parameters
hDBDatabase handle
hKeyClientKey handle of client structure
Returns
CM_SUCCESS

Definition at line 3011 of file midas.cxx.

3011 {
3012 //printf("cm_set_experiment_database: hDB %d, hKeyClient %d\n", hDB, hKeyClient);
3013
3014 _hDB = hDB;
3015 _hKeyClient = hKeyClient;
3016
3017 //if (hDB == 0) {
3018 // rpc_set_server_option(RPC_ODB_HANDLE, 0);
3019 //}
3020
3021 return CM_SUCCESS;
3022}
Here is the caller graph for this function:

◆ cm_set_experiment_local()

int cm_set_experiment_local ( const char *  exp_name)

Definition at line 2240 of file midas.cxx.

2241{
2242 std::string exp_name1;
2243
2244 if ((exp_name != NULL) && (strlen(exp_name) > 0)) {
2245 exp_name1 = exp_name;
2246 } else {
2247 int status = cm_select_experiment_local(&exp_name1);
2248 if (status != CM_SUCCESS)
2249 return status;
2250 }
2251
2252 std::string expdir, expuser;
2253
2254 int status = cm_get_exptab(exp_name1.c_str(), &expdir, &expuser);
2255
2256 if (status != CM_SUCCESS) {
2257 cm_msg(MERROR, "cm_set_experiment_local", "Experiment \"%s\" not found in exptab file \"%s\"", exp_name1.c_str(), cm_get_exptab_filename().c_str());
2258 return CM_UNDEF_EXP;
2259 }
2260
2261 if (!ss_dir_exist(expdir.c_str())) {
2262 cm_msg(MERROR, "cm_set_experiment_local", "Experiment \"%s\" directory \"%s\" does not exist", exp_name1.c_str(), expdir.c_str());
2263 return CM_UNDEF_EXP;
2264 }
2265
2266 cm_set_experiment_name(exp_name1.c_str());
2267 cm_set_path(expdir.c_str());
2268
2269 return CM_SUCCESS;
2270}
INT cm_set_path(const char *path)
Definition midas.cxx:1547
INT cm_select_experiment_local(std::string *exp_name)
Definition midas.cxx:2742
std::string cm_get_exptab_filename()
Definition midas.cxx:1838
int ss_dir_exist(const char *path)
Definition system.cxx:7271
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_set_experiment_name()

INT cm_set_experiment_name ( const char *  name)

Set name of the experiment

Parameters
nameExperiment name
Returns
CM_SUCCESS

Definition at line 1608 of file midas.cxx.

1608 {
1610 return CM_SUCCESS;
1611}
Here is the caller graph for this function:

◆ cm_set_experiment_semaphore()

INT cm_set_experiment_semaphore ( INT  semaphore_alarm,
INT  semaphore_elog,
INT  semaphore_history,
INT  semaphore_msg 
)

dox

Definition at line 3030 of file midas.cxx.

3050{
3051 _semaphore_alarm = semaphore_alarm;
3052 _semaphore_elog = semaphore_elog;
3053 _semaphore_history = semaphore_history;
3054 //_semaphore_msg = semaphore_msg;
3055
3056 return CM_SUCCESS;
3057}
Here is the caller graph for this function:

◆ cm_set_path()

INT cm_set_path ( const char *  path)

Set path to actual experiment. This function gets called by cm_connect_experiment if the connection is established to a local experiment (not through the TCP/IP server). The path is then used for all shared memory routines.

Parameters
pathPathname
Returns
CM_SUCCESS

Definition at line 1547 of file midas.cxx.

1547 {
1548 assert(path);
1549 assert(path[0] != 0);
1550
1551 _path_name = path;
1552
1553 if (_path_name.back() != DIR_SEPARATOR) {
1555 }
1556
1557 //printf("cm_set_path [%s]\n", _path_name.c_str());
1558
1559 return CM_SUCCESS;
1560}
Here is the caller graph for this function:

◆ cm_set_transition_sequence()

INT cm_set_transition_sequence ( INT  transition,
INT  sequence_number 
)

Change the transition sequence for the calling program.

Parameters
transitionTR_START, TR_PAUSE, TR_RESUME or TR_STOP.
sequence_numberNew sequence number, should be between 1 and 1000
Returns
CM_SUCCESS

Definition at line 3803 of file midas.cxx.

3803 {
3804 INT status;
3805 HNDLE hDB, hKey;
3806 char str[256];
3807
3808 /* check for valid transition */
3810 cm_msg(MERROR, "cm_set_transition_sequence", "Invalid transition request \"%d\"", transition);
3811 return CM_INVALID_TRANSITION;
3812 }
3813
3814 {
3815 std::lock_guard<std::mutex> guard(_trans_table_mutex);
3816
3817 int count = 0;
3818 for (size_t i = 0; i < _trans_table.size(); i++) {
3820 _trans_table[i].sequence_number = sequence_number;
3821 count++;
3822 }
3823 }
3824
3825 if (count == 0) {
3826 cm_msg(MERROR, "cm_set_transition_sequence", "transition %s is not registered", cm_transition_name(transition).c_str());
3827 return CM_INVALID_TRANSITION;
3828 } else if (count > 1) {
3829 cm_msg(MERROR, "cm_set_transition_sequence", "cannot change sequence number, transition %s is registered %d times", cm_transition_name(transition).c_str(), count);
3830 return CM_INVALID_TRANSITION;
3831 }
3832
3833 /* Change local sequence number for this transition type */
3834
3835 for (size_t i = 0; i < _trans_table.size(); i++) {
3837 _trans_table[i].sequence_number = sequence_number;
3838 }
3839 }
3840
3841 // implicit unlock
3842 }
3843
3845
3846 /* unlock database */
3848
3849 sprintf(str, "Transition %s", cm_transition_name(transition).c_str());
3850
3851 /* set value */
3852 status = db_set_value(hDB, hKey, str, &sequence_number, sizeof(INT), 1, TID_INT32);
3853 if (status != DB_SUCCESS)
3854 return status;
3855
3856 /* re-lock database */
3858
3859 return CM_SUCCESS;
3860
3861}
double count
Definition mdump.cxx:33
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_set_watchdog_params()

INT cm_set_watchdog_params ( BOOL  call_watchdog,
DWORD  timeout 
)

Definition at line 3355 of file midas.cxx.

3356{
3357 /* set also local timeout to requested value (needed by cm_enable_watchdog()) */
3358 _watchdog_timeout = timeout;
3359
3360 if (rpc_is_remote()) { // we are connected remotely
3361
3362 return rpc_call(RPC_CM_SET_WATCHDOG_PARAMS, call_watchdog, timeout);
3363
3364 } else if (rpc_is_mserver()) { // we are the mserver
3365
3367 if (sa)
3368 sa->watchdog_timeout = timeout;
3369
3370 /* write timeout value to client entry in ODB */
3371 HNDLE hDB, hKey;
3373
3374 if (hDB) {
3376 db_set_value(hDB, hKey, "Link timeout", &timeout, sizeof(timeout), 1, TID_INT32);
3378 }
3379
3380 /* set the watchdog for the local mserver program */
3381 return cm_set_watchdog_params_local(call_watchdog, timeout);
3382
3383 } else { // only running locally
3384
3385 return cm_set_watchdog_params_local(call_watchdog, timeout);
3386
3387 }
3388}
INT cm_set_watchdog_params_local(BOOL call_watchdog, DWORD timeout)
Definition midas.cxx:3316
RPC_SERVER_ACCEPTION * rpc_get_mserver_acception()
Definition midas.cxx:11746
#define RPC_CM_SET_WATCHDOG_PARAMS
Definition mrpc.h:22
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_set_watchdog_params_local()

INT cm_set_watchdog_params_local ( BOOL  call_watchdog,
DWORD  timeout 
)

Sets the internal watchdog flags and the own timeout. If call_watchdog is TRUE, the cm_watchdog routine is called periodically from the system to show other clients that this application is "alive". On UNIX systems, the alarm() timer is used which is then not available for user purposes.

The timeout specifies the time, after which the calling application should be considered "dead" by other clients. Normally, the cm_watchdog() routines is called periodically. If a client crashes, this does not occur any more. Then other clients can detect this and clear all buffer and database entries of this application so they are not blocked any more. If this application should not checked by others, the timeout can be specified as zero. It might be useful for debugging purposes to do so, because if a debugger comes to a breakpoint and stops the application, the periodic call of cm_watchdog is disabled and the client looks like dead.

If the timeout is not zero, but the watchdog is not called (call_watchdog == FALSE), the user must ensure to call cm_watchdog periodically with a period of WATCHDOG_INTERVAL milliseconds or less.

An application which calles system routines which block the alarm signal for some time, might increase the timeout to the maximum expected blocking time before issuing the calls. One example is the logger doing Exabyte tape IO, which can take up to one minute.

Parameters
call_watchdogCall the cm_watchdog routine periodically
timeoutTimeout for this application in ms
Returns
CM_SUCCESS

Definition at line 3316 of file midas.cxx.

3317{
3318#ifdef LOCAL_ROUTINES
3319 _watchdog_timeout = timeout;
3320
3321 std::vector<BUFFER*> mybuffers;
3322
3323 gBuffersMutex.lock();
3324 mybuffers = gBuffers;
3325 gBuffersMutex.unlock();
3326
3327 /* set watchdog timeout of all open buffers */
3328 for (BUFFER* pbuf : mybuffers) {
3329
3330 if (!pbuf || !pbuf->attached)
3331 continue;
3332
3333 bm_lock_buffer_guard pbuf_guard(pbuf);
3334
3335 if (!pbuf_guard.is_locked())
3336 continue;
3337
3338 BUFFER_CLIENT *pclient = bm_get_my_client_locked(pbuf_guard);
3339
3340 /* clear entry from client structure in buffer header */
3341 pclient->watchdog_timeout = timeout;
3342
3343 /* show activity */
3344 pclient->last_activity = ss_millitime();
3345 }
3346
3347 /* set watchdog timeout for ODB */
3348 db_set_watchdog_params(timeout);
3349
3350#endif /* LOCAL_ROUTINES */
3351
3352 return CM_SUCCESS;
3353}
void db_set_watchdog_params(DWORD timeout)
Definition odb.cxx:3555
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_shutdown() [1/2]

INT cm_shutdown ( const char *  name)

Definition at line 7478 of file midas.cxx.

7478 {
7479 INT status, return_status, size;
7480 HNDLE hDB, hKeyClient, hKey, hSubkey, hKeyTmp, hConn;
7481 DWORD start_time;
7482 DWORD timeout;
7483 DWORD last;
7484
7485 cm_get_experiment_database(&hDB, &hKeyClient);
7486
7487 status = db_find_key(hDB, 0, "System/Clients", &hKey);
7488 if (status != DB_SUCCESS)
7489 return DB_NO_KEY;
7490
7491 return_status = CM_NO_CLIENT;
7492
7493 /* loop over all clients */
7494 for (int i = 0;; i++) {
7497 break;
7498
7499 /* don't shutdown ourselves */
7500 if (hSubkey == hKeyClient)
7501 continue;
7502
7503 if (status == DB_SUCCESS) {
7504 std::string client_name;
7505 std::string remote_host;
7506 KEY key;
7507 INT port = 0;
7508
7510
7511 /* contact client */
7512 size = sizeof(client_name);
7513 status = db_get_value_string(hDB, hSubkey, "Name", 0, &client_name);
7514 if (status != DB_SUCCESS)
7515 continue;
7516
7517 /* check if individual client */
7518 if (!equal_ustring("all", name) && !equal_ustring(client_name.c_str(), name))
7519 continue;
7520
7521 size = sizeof(port);
7522 status = db_get_value(hDB, hSubkey, "Server Port", &port, &size, TID_INT32, FALSE);
7523 if (status != DB_SUCCESS)
7524 continue;
7525
7526 status = db_get_value_string(hDB, hSubkey, "Host", 0, &remote_host);
7527 if (status != DB_SUCCESS)
7528 continue;
7529
7530 cm_get_watchdog_info(hDB, name, &timeout, &last);
7531 if (timeout == 0)
7532 timeout = 5000;
7533
7534 /* client found -> connect to its server port */
7535 status = rpc_client_connect(remote_host.c_str(), port, client_name.c_str(), &hConn);
7536 if (status != RPC_SUCCESS) {
7537 int client_pid = atoi(key.name);
7538 return_status = CM_NO_CLIENT;
7539 cm_msg(MERROR, "cm_shutdown", "Cannot connect to client \'%s\' on host \'%s\', port %d", client_name.c_str(), remote_host.c_str(), port);
7540#ifdef SIGKILL
7541 cm_msg(MERROR, "cm_shutdown", "Killing and Deleting client \'%s\' pid %d", client_name.c_str(), client_pid);
7542 kill(client_pid, SIGKILL);
7543 return_status = CM_SUCCESS;
7544 status = cm_delete_client_info(hDB, client_pid);
7545 if (status != CM_SUCCESS)
7546 cm_msg(MERROR, "cm_shutdown", "Cannot delete client info for client \'%s\', pid %d, status %d", name, client_pid, status);
7547#endif
7548 } else {
7549 /* call disconnect with shutdown=TRUE */
7551
7552 /* wait until client has shut down */
7553 start_time = ss_millitime();
7554 do {
7555 ss_sleep(100);
7556 status = db_find_key(hDB, hKey, key.name, &hKeyTmp);
7557 } while (status == DB_SUCCESS && (ss_millitime() - start_time < timeout));
7558
7559 if (status == DB_SUCCESS) {
7560 int client_pid = atoi(key.name);
7561 return_status = CM_NO_CLIENT;
7562 cm_msg(MERROR, "cm_shutdown", "Client \'%s\' not responding to shutdown command", client_name.c_str());
7563#ifdef SIGKILL
7564 cm_msg(MERROR, "cm_shutdown", "Killing and Deleting client \'%s\' pid %d", client_name.c_str(), client_pid);
7565 kill(client_pid, SIGKILL);
7566 status = cm_delete_client_info(hDB, client_pid);
7567 if (status != CM_SUCCESS)
7568 cm_msg(MERROR, "cm_shutdown", "Cannot delete client info for client \'%s\', pid %d, status %d", name, client_pid, status);
7569#endif
7570 return_status = CM_NO_CLIENT;
7571 } else {
7572 return_status = CM_SUCCESS;
7573 i--;
7574 }
7575 }
7576 }
7577
7578 /* display any message created during each shutdown */
7580 }
7581
7582 return return_status;
7583}
INT cm_get_watchdog_info(HNDLE hDB, const char *client_name, DWORD *timeout, DWORD *last)
Definition midas.cxx:3416
Here is the call graph for this function:

◆ cm_shutdown() [2/2]

INT cm_shutdown ( const char *  name,
BOOL  bUnique 
)

Shutdown (exit) other MIDAS client

Parameters
nameClient name or "all" for all clients
bUniqueIf true, look for the exact client name. If false, look for namexxx where xxx is a any number.
Returns
CM_SUCCESS, CM_NO_CLIENT, DB_NO_KEY

Definition at line 7474 of file midas.cxx.

7474 {
7475 return cm_shutdown(name);
7476}
INT cm_shutdown(const char *name, BOOL bUnique)
Definition midas.cxx:7474
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_start_watchdog_thread()

INT cm_start_watchdog_thread ( void  )

Definition at line 7429 of file midas.cxx.

7429 {
7430 /* watchdog does not run inside remote clients.
7431 * watchdog timeout timers are maintained by the mserver */
7432 if (rpc_is_remote())
7433 return CM_SUCCESS;
7434#ifdef LOCAL_ROUTINES
7435 /* only start once */
7436 if (_watchdog_thread)
7437 return CM_SUCCESS;
7438 _watchdog_thread_run = true;
7439 _watchdog_thread.store(new std::thread(xcm_watchdog_thread));
7440#endif
7441 return CM_SUCCESS;
7442}
static std::atomic< std::thread * > _watchdog_thread
Definition midas.cxx:7397
static void xcm_watchdog_thread()
Definition midas.cxx:7423
static std::atomic< bool > _watchdog_thread_run
Definition midas.cxx:7395
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_stop_watchdog_thread()

INT cm_stop_watchdog_thread ( void  )

Definition at line 7444 of file midas.cxx.

7444 {
7445 /* watchdog does not run inside remote clients.
7446 * watchdog timeout timers are maintained by the mserver */
7447 if (rpc_is_remote())
7448 return CM_SUCCESS;
7449#ifdef LOCAL_ROUTINES
7450 _watchdog_thread_run = false;
7452 //printf("waiting for watchdog thread to shut down\n");
7453 ss_sleep(10);
7454 }
7455 if (_watchdog_thread != NULL) {
7456 _watchdog_thread.load()->join();
7457 delete static_cast<std::thread *>(_watchdog_thread);
7458 _watchdog_thread = NULL;
7459 }
7460#endif
7461 return CM_SUCCESS;
7462}
static std::atomic< bool > _watchdog_thread_is_running
Definition midas.cxx:7396
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_synchronize()

INT cm_synchronize ( DWORD seconds)

Get time from MIDAS server and set local time.

Parameters
secondsTime in seconds
Returns
CM_SUCCESS

Definition at line 1419 of file midas.cxx.

1419 {
1420 INT sec, status;
1421
1422 /* if connected to server, get time from there */
1423 if (rpc_is_remote()) {
1425
1426 /* set local time */
1427 if (status == CM_SUCCESS)
1428 ss_settime(sec);
1429 }
1430
1431 /* return time to caller */
1432 if (seconds != NULL) {
1433 *seconds = ss_time();
1434 }
1435
1436 return CM_SUCCESS;
1437}
DWORD ss_settime(DWORD seconds)
Definition system.cxx:3554
#define RPC_CM_SYNCHRONIZE
Definition mrpc.h:27
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_test_expand_env()

void cm_test_expand_env ( )

Definition at line 7870 of file midas.cxx.

7870 {
7871 printf("Test expand_end()\n");
7872 setenv("FOO", "foo", 1);
7873 setenv("BAR", "bar", 1);
7874 setenv("EMPTY", "", 1);
7875 unsetenv("UNDEF");
7876
7877 bool ok = true;
7878
7879 ok &= test_cm_expand_env1("aaa", "aaa");
7880 ok &= test_cm_expand_env1("$FOO", "foo");
7881 ok &= test_cm_expand_env1("/$FOO", "/foo");
7882 ok &= test_cm_expand_env1("/$FOO/", "/foo/");
7883 ok &= test_cm_expand_env1("$FOO/$BAR", "foo/bar");
7884 ok &= test_cm_expand_env1("$FOO1", "$FOO1");
7885 ok &= test_cm_expand_env1("1$FOO", "1foo");
7886 ok &= test_cm_expand_env1("$UNDEF", "$UNDEF");
7887 ok &= test_cm_expand_env1("/$UNDEF/", "/$UNDEF/");
7888
7889 if (ok) {
7890 printf("test_expand_env: all tests passed!\n");
7891 } else {
7892 printf("test_expand_env: test FAILED!\n");
7893 }
7894}
static bool test_cm_expand_env1(const char *str, const char *expected)
Definition midas.cxx:7855
Here is the call graph for this function:

◆ cm_time()

INT cm_time ( DWORD t)

Get time from ss_time on server.

Parameters
tstring
Returns
CM_SUCCESS

Definition at line 1484 of file midas.cxx.

1484 {
1485 /* if connected to server, get time from there */
1486 if (rpc_is_remote())
1487 return rpc_call(RPC_CM_TIME, t);
1488
1489 /* return local time */
1490 *t = ss_time();
1491
1492 return CM_SUCCESS;
1493}
#define RPC_CM_TIME
Definition mrpc.h:29
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_transition()

INT cm_transition ( INT  transition,
INT  run_number,
char *  errstr,
INT  errstr_size,
INT  async_flag,
INT  debug_flag 
)

Definition at line 5360 of file midas.cxx.

5360 {
5361 int mflag = async_flag & TR_MTHREAD;
5362 int sflag = async_flag & TR_SYNC;
5363
5365
5366 if (status != CM_SUCCESS) {
5367 cm_msg(MERROR, "cm_transition", "previous transition did not finish yet");
5369 }
5370
5371 /* get key of local client */
5372 HNDLE hDB;
5374
5375 bool deferred = (transition & TR_DEFERRED) > 0;
5376 INT trans_raw = (transition & ~TR_DEFERRED);
5377
5378 /* check for valid transition */
5379 if (trans_raw != TR_START && trans_raw != TR_STOP && trans_raw != TR_PAUSE && trans_raw != TR_RESUME && trans_raw != TR_STARTABORT) {
5380 cm_msg(MERROR, "cm_transition", "Invalid transition request \"%d\"", transition);
5381 if (errstr) {
5382 mstrlcpy(errstr, "Invalid transition request", errstr_size);
5383 }
5384 return CM_INVALID_TRANSITION;
5385 }
5386
5387 /* check if transition in progress */
5388 if (!deferred) {
5389 int i = 0;
5390 int size = sizeof(i);
5391 db_get_value(hDB, 0, "/Runinfo/Transition in progress", &i, &size, TID_INT32, TRUE);
5392 if (i == 1) {
5393 if (errstr) {
5394 sprintf(errstr, "Start/Stop transition %d already in progress, please try again later\n", i);
5395 mstrlcat(errstr, "or set \"/Runinfo/Transition in progress\" manually to zero.\n", errstr_size);
5396 }
5397 cm_msg(MERROR, "cm_transition", "another transition is already in progress");
5399 }
5400 }
5401
5402 if (mflag) {
5405 if (sflag) {
5406 /* in MTHREAD|SYNC mode, we wait until the main thread finishes and it is safe for it to write into errstr */
5407 _trp.errstr = errstr;
5408 _trp.errstr_size = errstr_size;
5409 } else {
5410 /* in normal MTHREAD mode, we return right away and
5411 * if errstr is a local variable in the caller and they return too,
5412 * errstr becomes a stale reference and writing into it will corrupt the stack
5413 * in the mlogger, errstr is a local variable in "start_the_run", "stop_the_run"
5414 * and we definitely corrupt mlogger memory with out this: */
5415 _trp.errstr = NULL;
5416 _trp.errstr_size = 0;
5417 }
5418 _trp.async_flag = async_flag;
5419 _trp.debug_flag = debug_flag;
5420 _trp.status = 0;
5422
5423 if (errstr)
5424 *errstr = 0; // null error string
5425
5426 //ss_thread_create(tr_main_thread, &_trp);
5427
5428 std::thread* t = _trp.thread.exchange(new std::thread(tr_main_thread, &_trp));
5429
5430 assert(t==NULL); // previous thread should have been reaped by cm_transition_cleanup()
5431
5432 if (sflag) {
5433
5434 /* wait until main thread has finished */
5435 do {
5436 ss_sleep(10);
5437 } while (!_trp.finished);
5438
5439 std::thread* t = _trp.thread.exchange(NULL);
5440
5441 if (t) {
5442 t->join();
5443 delete t;
5444 t = NULL;
5445 }
5446
5447 return _trp.status;
5448 }
5449 } else
5450 return cm_transition1(transition, run_number, errstr, errstr_size, async_flag, debug_flag);
5451
5452 return CM_SUCCESS;
5453}
static INT cm_transition1(INT transition, INT run_number, char *errstr, INT errstr_size, INT async_flag, INT debug_flag)
Definition midas.cxx:5312
static INT tr_main_thread(void *param)
Definition midas.cxx:5328
#define CM_TRANSITION_IN_PROGRESS
Definition midas.h:592
#define TR_MTHREAD
Definition midas.h:361
std::atomic< std::thread * > thread
Definition midas.cxx:299
INT debug_flag
Definition midas.cxx:296
INT run_number
Definition midas.cxx:292
INT errstr_size
Definition midas.cxx:294
char * errstr
Definition midas.cxx:293
std::atomic_int status
Definition midas.cxx:297
INT async_flag
Definition midas.cxx:295
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_transition1()

static INT cm_transition1 ( INT  transition,
INT  run_number,
char *  errstr,
INT  errstr_size,
INT  async_flag,
INT  debug_flag 
)
static

Definition at line 5312 of file midas.cxx.

5312 {
5313 int status;
5314
5315 status = cm_transition2(transition, run_number, errstr, errstr_size, async_flag, debug_flag);
5316
5317 if (transition == TR_START && status != CM_SUCCESS) {
5318 cm_msg(MERROR, "cm_transition", "Could not start a run: cm_transition() status %d, message \'%s\'", status,
5319 errstr);
5320 cm_transition2(TR_STARTABORT, run_number, NULL, 0, async_flag, debug_flag);
5321 }
5322
5323 return status;
5324}
static INT cm_transition2(INT transition, INT run_number, char *errstr, INT errstr_size, INT async_flag, INT debug_flag)
Definition midas.cxx:4603
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_transition2()

static INT cm_transition2 ( INT  transition,
INT  run_number,
char *  errstr,
INT  errstr_size,
INT  async_flag,
INT  debug_flag 
)
static

Performs a run transition (Start/Stop/Pause/Resume).

Synchronous/Asynchronous flag. If set to TR_ASYNC, the transition is done asynchronously, meaning that clients are connected and told to execute their callback routine, but no result is awaited. The return value is specified by the transition callback function on the remote clients. If all callbacks can perform the transition, CM_SUCCESS is returned. If one callback cannot perform the transition, the return value of this callback is returned from cm_transition(). The async_flag is usually FALSE so that transition callbacks can block a run transition in case of problems and return an error string. The only exception are situations where a run transition is performed automatically by a program which cannot block in a transition. For example the logger can cause a run stop when a disk is nearly full but it cannot block in the cm_transition() function since it has its own run stop callback which must flush buffers and close disk files and tapes.

...
i = 1;
db_set_value(hDB, 0, "/Runinfo/Transition in progress", &i, sizeof(INT), 1, TID_INT32);
status = cm_transition(TR_START, new_run_number, str, sizeof(str), SYNC, debug_flag);
{
// in case of error
printf("Error: %s\n", str);
}
...
Parameters
transitionTR_START, TR_PAUSE, TR_RESUME or TR_STOP.
run_numberNew run number. If zero, use current run number plus one.
errstrreturned error string.
errstr_sizeSize of error string.
async_flagTR_SYNC: synchronization flag (TR_SYNC:wait completion, TR_ASYNC: retun immediately)
debug_flagIf 1 output debugging information, if 2 output via cm_msg().
Returns
CM_SUCCESS, <error> error code from remote client

Definition at line 4603 of file midas.cxx.

4604{
4605 INT i, status, size, sequence_number, port, state;
4606 HNDLE hDB, hRootKey, hSubkey, hKey, hKeylocal, hKeyTrans;
4607 DWORD seconds;
4608 char tr_key_name[256];
4609 KEY key;
4610 BOOL deferred;
4611 char xerrstr[TRANSITION_ERROR_STRING_LENGTH];
4612
4613 //printf("cm_transition2: transition %d, run_number %d, errstr %p, errstr_size %d, async_flag %d, debug_flag %d\n", transition, run_number, errstr, errstr_size, async_flag, debug_flag);
4614
4615 /* if needed, use internal error string */
4616 if (!errstr) {
4617 errstr = xerrstr;
4618 errstr_size = sizeof(xerrstr);
4619 }
4620
4621 /* erase error string */
4622 errstr[0] = 0;
4623
4624 /* get key of local client */
4625 cm_get_experiment_database(&hDB, &hKeylocal);
4626
4627 deferred = (transition & TR_DEFERRED) > 0;
4628 transition &= ~TR_DEFERRED;
4629
4630 /* check for valid transition */
4632 && transition != TR_STARTABORT) {
4633 cm_msg(MERROR, "cm_transition", "Invalid transition request \"%d\"", transition);
4634 mstrlcpy(errstr, "Invalid transition request", errstr_size);
4635 return CM_INVALID_TRANSITION;
4636 }
4637
4638 /* check if transition in progress */
4639 if (!deferred) {
4640 i = 0;
4641 size = sizeof(i);
4642 db_get_value(hDB, 0, "/Runinfo/Transition in progress", &i, &size, TID_INT32, TRUE);
4643 if (i == 1) {
4644 if (errstr) {
4645 sprintf(errstr, "Start/Stop transition %d already in progress, please try again later\n", i);
4646 mstrlcat(errstr, "or set \"/Runinfo/Transition in progress\" manually to zero.\n", errstr_size);
4647 }
4648 cm_msg(MERROR, "cm_transition", "another transition is already in progress");
4650 }
4651 }
4652
4653 /* indicate transition in progress */
4654 i = transition;
4655 db_set_value(hDB, 0, "/Runinfo/Transition in progress", &i, sizeof(INT), 1, TID_INT32);
4656
4657 /* clear run abort flag */
4658 i = 0;
4659 db_set_value(hDB, 0, "/Runinfo/Start abort", &i, sizeof(INT), 1, TID_INT32);
4660
4661 /* construct new transition state */
4662
4663 TrState s;
4664
4667 s.async_flag = async_flag;
4668 s.debug_flag = debug_flag;
4669 s.status = 0;
4670 s.errorstr[0] = 0;
4672 s.end_time = 0;
4673
4674 /* construct the ODB tree /System/Transition */
4675
4676 status = db_delete(hDB, 0, "/System/Transition/TR_STARTABORT");
4677
4678 if (transition != TR_STARTABORT) {
4679 status = db_delete(hDB, 0, "/System/Transition/Clients");
4680 }
4681
4682 if (transition != TR_STARTABORT) {
4683 db_set_value(hDB, 0, "/System/Transition/transition", &transition, sizeof(INT), 1, TID_INT32);
4684 db_set_value(hDB, 0, "/System/Transition/run_number", &run_number, sizeof(INT), 1, TID_INT32);
4685 db_set_value(hDB, 0, "/System/Transition/start_time", &s.start_time, sizeof(DWORD), 1, TID_UINT32);
4686 db_set_value(hDB, 0, "/System/Transition/end_time", &s.end_time, sizeof(DWORD), 1, TID_UINT32);
4687 status = 0;
4688 db_set_value(hDB, 0, "/System/Transition/status", &status, sizeof(INT), 1, TID_INT32);
4689 db_set_value(hDB, 0, "/System/Transition/error", "", 1, 1, TID_STRING);
4690 db_set_value(hDB, 0, "/System/Transition/deferred", "", 1, 1, TID_STRING);
4691 }
4692
4693 /* check for alarms */
4694 i = 0;
4695 size = sizeof(i);
4696 db_get_value(hDB, 0, "/Experiment/Prevent start on alarms", &i, &size, TID_BOOL, TRUE);
4697 if (i == TRUE && transition == TR_START) {
4698 al_check();
4699 std::string alarms;
4700 if (al_get_alarms(&alarms) > 0) {
4701 cm_msg(MERROR, "cm_transition", "Run start abort due to alarms: %s", alarms.c_str());
4702 mstrlcpy(errstr, "Cannot start run due to alarms: ", errstr_size);
4703 mstrlcat(errstr, alarms.c_str(), errstr_size);
4704 return tr_finish(hDB, &s, transition, AL_TRIGGERED, errstr);
4705 }
4706 }
4707
4708 /* check for required programs */
4709 i = 0;
4710 size = sizeof(i);
4711 db_get_value(hDB, 0, "/Experiment/Prevent start on required progs", &i, &size, TID_BOOL, TRUE);
4712 if (i == TRUE && transition == TR_START) {
4713
4714 HNDLE hkeyroot, hkey;
4715
4716 /* check /programs alarms */
4717 db_find_key(hDB, 0, "/Programs", &hkeyroot);
4718 if (hkeyroot) {
4719 for (i = 0;; i++) {
4720 BOOL program_info_required = FALSE;
4721 status = db_enum_key(hDB, hkeyroot, i, &hkey);
4723 break;
4724
4725 db_get_key(hDB, hkey, &key);
4726
4727 /* don't check "execute on xxx" */
4728 if (key.type != TID_KEY)
4729 continue;
4730
4731 size = sizeof(program_info_required);
4732 status = db_get_value(hDB, hkey, "Required", &program_info_required, &size, TID_BOOL, TRUE);
4733 if (status != DB_SUCCESS) {
4734 cm_msg(MERROR, "cm_transition", "Cannot get program info required, status %d", status);
4735 continue;
4736 }
4737
4738 if (program_info_required) {
4739 std::string name = rpc_get_name();
4740 std::string str = name;
4741 str.resize(strlen(key.name));
4742 if (!equal_ustring(str.c_str(), key.name) && cm_exist(key.name, FALSE) == CM_NO_CLIENT) {
4743 cm_msg(MERROR, "cm_transition", "Run start abort due to program \"%s\" not running", key.name);
4744 std::string serrstr = msprintf("Run start abort due to program \"%s\" not running", key.name);
4745 mstrlcpy(errstr, serrstr.c_str(), errstr_size);
4746 return tr_finish(hDB, &s, transition, AL_TRIGGERED, errstr);
4747 }
4748 }
4749 }
4750 }
4751 }
4752
4753 /* do detached transition via mtransition tool */
4754 if (async_flag & TR_DETACH) {
4755 status = cm_transition_detach(transition, run_number, errstr, errstr_size, async_flag, debug_flag);
4756 return tr_finish(hDB, &s, transition, status, errstr);
4757 }
4758
4759 mstrlcpy(errstr, "Unknown error", errstr_size);
4760
4761 if (debug_flag == 0) {
4762 size = sizeof(i);
4763 db_get_value(hDB, 0, "/Experiment/Transition debug flag", &debug_flag, &size, TID_INT32, TRUE);
4764 }
4765
4766 /* if no run number is given, get it from ODB and increment it */
4767 if (run_number == 0) {
4768 size = sizeof(run_number);
4769 status = db_get_value(hDB, 0, "Runinfo/Run number", &run_number, &size, TID_INT32, TRUE);
4770 assert(status == SUCCESS);
4771 if (transition == TR_START) {
4772 run_number++;
4773 }
4775
4776 if (transition != TR_STARTABORT) {
4777 db_set_value(hDB, 0, "/System/Transition/run_number", &run_number, sizeof(INT), 1, TID_INT32);
4778 }
4779 }
4780
4781 if (run_number <= 0) {
4782 cm_msg(MERROR, "cm_transition", "aborting on attempt to use invalid run number %d", run_number);
4783 abort();
4784 }
4785
4786 /* Set new run number in ODB */
4787 if (transition == TR_START) {
4788 if (debug_flag == 1)
4789 printf("Setting run number %d in ODB\n", run_number);
4790 if (debug_flag == 2)
4791 cm_msg(MINFO, "cm_transition", "cm_transition: Setting run number %d in ODB", run_number);
4792
4793 status = db_set_value(hDB, 0, "Runinfo/Run number", &run_number, sizeof(run_number), 1, TID_INT32);
4794 if (status != DB_SUCCESS) {
4795 cm_msg(MERROR, "cm_transition", "cannot set Runinfo/Run number in database, status %d", status);
4796 abort();
4797 }
4798 }
4799
4800 if (deferred) {
4801 if (debug_flag == 1)
4802 printf("Clearing /Runinfo/Requested transition\n");
4803 if (debug_flag == 2)
4804 cm_msg(MINFO, "cm_transition", "cm_transition: Clearing /Runinfo/Requested transition");
4805
4806 /* remove transition request */
4807 i = 0;
4808 db_set_value(hDB, 0, "/Runinfo/Requested transition", &i, sizeof(int), 1, TID_INT32);
4809 } else {
4810 status = db_find_key(hDB, 0, "System/Clients", &hRootKey);
4811 if (status != DB_SUCCESS) {
4812 cm_msg(MERROR, "cm_transition", "cannot find System/Clients entry in database");
4813 if (errstr)
4814 mstrlcpy(errstr, "Cannot find /System/Clients in ODB", errstr_size);
4815 return tr_finish(hDB, &s, transition, status, errstr);
4816 }
4817
4818 /* check if deferred transition already in progress */
4819 size = sizeof(i);
4820 db_get_value(hDB, 0, "/Runinfo/Requested transition", &i, &size, TID_INT32, TRUE);
4821 if (i) {
4822 if (errstr) {
4823 mstrlcpy(errstr, "Deferred transition already in progress", errstr_size);
4824 mstrlcat(errstr, ", to cancel, set \"/Runinfo/Requested transition\" to zero", errstr_size);
4825 }
4826 return tr_finish(hDB, &s, transition, CM_TRANSITION_IN_PROGRESS, errstr);
4827 }
4828
4829 std::string trname = cm_transition_name(transition);
4830
4831 sprintf(tr_key_name, "Transition %s DEFERRED", trname.c_str());
4832
4833 /* search database for clients with deferred transition request */
4834 for (i = 0, status = 0;; i++) {
4835 status = db_enum_key(hDB, hRootKey, i, &hSubkey);
4837 break;
4838
4839 if (status == DB_SUCCESS) {
4840 size = sizeof(sequence_number);
4841 status = db_get_value(hDB, hSubkey, tr_key_name, &sequence_number, &size, TID_INT32, FALSE);
4842
4843 /* if registered for deferred transition, set flag in ODB and return */
4844 if (status == DB_SUCCESS) {
4845 char str[256];
4846 size = NAME_LENGTH;
4847 db_get_value(hDB, hSubkey, "Name", str, &size, TID_STRING, TRUE);
4848
4849 if (debug_flag == 1)
4850 printf("---- Transition %s deferred by client \"%s\" ----\n", trname.c_str(), str);
4851 if (debug_flag == 2)
4852 cm_msg(MINFO, "cm_transition", "cm_transition: ---- Transition %s deferred by client \"%s\" ----", trname.c_str(), str);
4853
4854 if (debug_flag == 1)
4855 printf("Setting /Runinfo/Requested transition\n");
4856 if (debug_flag == 2)
4857 cm_msg(MINFO, "cm_transition", "cm_transition: Setting /Runinfo/Requested transition");
4858
4859 /* /Runinfo/Requested transition is hot-linked by mfe.c and writing to it
4860 * will activate the deferred transition code in the frontend.
4861 * the transition itself will be run from the frontend via cm_transition(TR_DEFERRED) */
4862
4863 db_set_value(hDB, 0, "/Runinfo/Requested transition", &transition, sizeof(int), 1, TID_INT32);
4864
4865 db_set_value(hDB, 0, "/System/Transition/deferred", str, strlen(str) + 1, 1, TID_STRING);
4866
4867 if (errstr)
4868 sprintf(errstr, "Transition %s deferred by client \"%s\"", trname.c_str(), str);
4869
4870 return tr_finish(hDB, &s, transition, CM_DEFERRED_TRANSITION, errstr);
4871 }
4872 }
4873 }
4874 }
4875
4876 /* execute programs on start */
4877 if (transition == TR_START) {
4878 char str[256];
4879 str[0] = 0;
4880 size = sizeof(str);
4881 db_get_value(hDB, 0, "/Programs/Execute on start run", str, &size, TID_STRING, TRUE);
4882 if (str[0])
4883 ss_system(str);
4884
4885 db_find_key(hDB, 0, "/Programs", &hRootKey);
4886 if (hRootKey) {
4887 for (i = 0;; i++) {
4888 BOOL program_info_auto_start = FALSE;
4889 status = db_enum_key(hDB, hRootKey, i, &hKey);
4891 break;
4892
4893 db_get_key(hDB, hKey, &key);
4894
4895 /* don't check "execute on xxx" */
4896 if (key.type != TID_KEY)
4897 continue;
4898
4899 size = sizeof(program_info_auto_start);
4900 status = db_get_value(hDB, hKey, "Auto start", &program_info_auto_start, &size, TID_BOOL, TRUE);
4901 if (status != DB_SUCCESS) {
4902 cm_msg(MERROR, "cm_transition", "Cannot get program info auto start, status %d", status);
4903 continue;
4904 }
4905
4906 if (program_info_auto_start) {
4907 char start_command[MAX_STRING_LENGTH];
4908 start_command[0] = 0;
4909
4910 size = sizeof(start_command);
4911 status = db_get_value(hDB, hKey, "Start command", &start_command, &size, TID_STRING, TRUE);
4912 if (status != DB_SUCCESS) {
4913 cm_msg(MERROR, "cm_transition", "Cannot get program info start command, status %d", status);
4914 continue;
4915 }
4916
4917 if (start_command[0]) {
4918 cm_msg(MINFO, "cm_transition", "Auto Starting program \"%s\", command \"%s\"", key.name,
4919 start_command);
4920 ss_system(start_command);
4921 }
4922 }
4923 }
4924 }
4925 }
4926
4927 /* execute programs on startabort */
4928 if (transition == TR_STARTABORT) {
4929 /* make sure odb entry is always created, otherwise we only see it after the first aborted run start, maybe never */
4930 std::string cmd;
4931 db_get_value_string(hDB, 0, "/Programs/Execute on start abort", 0, &cmd, TRUE, 256);
4932
4933 if (!cmd.empty())
4934 ss_system(cmd.c_str());
4935 }
4936
4937 /* set new start time in database */
4938 if (transition == TR_START) {
4939 /* ASCII format */
4940 std::string now = cm_asctime();
4941 now.reserve(32);
4942 db_set_value(hDB, 0, "Runinfo/Start Time", now.c_str(), 32, 1, TID_STRING);
4943
4944 /* reset stop time */
4945 seconds = 0;
4946 db_set_value(hDB, 0, "Runinfo/Stop Time binary", &seconds, sizeof(seconds), 1, TID_UINT32);
4947
4948 /* Seconds since 1.1.1970 */
4949 cm_time(&seconds);
4950 db_set_value(hDB, 0, "Runinfo/Start Time binary", &seconds, sizeof(seconds), 1, TID_UINT32);
4951 }
4952
4953 size = sizeof(state);
4954 status = db_get_value(hDB, 0, "Runinfo/State", &state, &size, TID_INT32, TRUE);
4955
4956 /* set stop time in database */
4957 if (transition == TR_STOP) {
4958 if (status != DB_SUCCESS)
4959 cm_msg(MERROR, "cm_transition", "cannot get Runinfo/State in database");
4960
4961 if (state != STATE_STOPPED) {
4962 /* stop time binary */
4963 cm_time(&seconds);
4964 status = db_set_value(hDB, 0, "Runinfo/Stop Time binary", &seconds, sizeof(seconds), 1, TID_UINT32);
4965 if (status != DB_SUCCESS)
4966 cm_msg(MERROR, "cm_transition", "cannot set \"Runinfo/Stop Time binary\" in database");
4967
4968 /* stop time ascii */
4969 std::string now = cm_asctime();
4970 now.reserve(32);
4971 status = db_set_value(hDB, 0, "Runinfo/Stop Time", now.c_str(), 32, 1, TID_STRING);
4972 if (status != DB_SUCCESS)
4973 cm_msg(MERROR, "cm_transition", "cannot set \"Runinfo/Stop Time\" in database");
4974 }
4975 }
4976
4977 status = db_find_key(hDB, 0, "System/Clients", &hRootKey);
4978 if (status != DB_SUCCESS) {
4979 cm_msg(MERROR, "cm_transition", "cannot find System/Clients entry in database");
4980 if (errstr)
4981 mstrlcpy(errstr, "Cannot find /System/Clients in ODB", errstr_size);
4982 return tr_finish(hDB, &s, transition, status, errstr);
4983 }
4984
4985 std::string trname = cm_transition_name(transition);
4986
4987 /* check that all transition clients are alive */
4988 for (int i = 0;;) {
4989 status = db_enum_key(hDB, hRootKey, i, &hSubkey);
4990 if (status != DB_SUCCESS)
4991 break;
4992
4994
4995 if (status == DB_SUCCESS) {
4996 /* this client is alive. Check next one! */
4997 i++;
4998 continue;
4999 }
5000
5001 assert(status == CM_NO_CLIENT);
5002
5003 /* start from scratch: removing odb entries as we iterate over them
5004 * does strange things to db_enum_key() */
5005 i = 0;
5006 }
5007
5008 /* check for broken RPC connections */
5010
5011 if (debug_flag == 1)
5012 printf("---- Transition %s started ----\n", trname.c_str());
5013 if (debug_flag == 2)
5014 cm_msg(MINFO, "cm_transition", "cm_transition: ---- Transition %s started ----", trname.c_str());
5015
5016 sprintf(tr_key_name, "Transition %s", trname.c_str());
5017
5018 /* search database for clients which registered for transition */
5019
5020 for (int i = 0, status = 0;; i++) {
5021 KEY subkey;
5022 status = db_enum_key(hDB, hRootKey, i, &hSubkey);
5024 break;
5025
5026 status = db_get_key(hDB, hSubkey, &subkey);
5027 assert(status == DB_SUCCESS);
5028
5029 if (status == DB_SUCCESS) {
5030 status = db_find_key(hDB, hSubkey, tr_key_name, &hKeyTrans);
5031
5032 if (status == DB_SUCCESS) {
5033
5034 db_get_key(hDB, hKeyTrans, &key);
5035
5036 for (int j = 0; j < key.num_values; j++) {
5037 size = sizeof(sequence_number);
5038 status = db_get_data_index(hDB, hKeyTrans, &sequence_number, &size, j, TID_INT32);
5039 assert(status == DB_SUCCESS);
5040
5041 TrClient *c = new TrClient;
5042
5044 c->transition = transition;
5045 c->run_number = run_number;
5046 c->async_flag = async_flag;
5047 c->debug_flag = debug_flag;
5048 c->sequence_number = sequence_number;
5049 c->status = 0;
5050 c->key_name = subkey.name;
5051
5052 /* get client info */
5053 char client_name[NAME_LENGTH];
5054 size = sizeof(client_name);
5055 db_get_value(hDB, hSubkey, "Name", client_name, &size, TID_STRING, TRUE);
5056 c->client_name = client_name;
5057
5059 size = sizeof(host_name);
5060 db_get_value(hDB, hSubkey, "Host", host_name, &size, TID_STRING, TRUE);
5061 c->host_name = host_name;
5062
5063 //printf("Found client [%s] name [%s] transition [%s], i=%d, j=%d\n", subkey.name, client_name, tr_key_name, i, j);
5064
5065 if (hSubkey == hKeylocal && ((async_flag & TR_MTHREAD) == 0)) {
5066 /* remember own client */
5067 c->port = 0;
5068 } else {
5069 size = sizeof(port);
5070 db_get_value(hDB, hSubkey, "Server Port", &port, &size, TID_INT32, TRUE);
5071 c->port = port;
5072 }
5073
5074 /* check for duplicates */
5075
5076 bool found = false;
5077 for (size_t k=0; k<s.clients.size(); k++) {
5078 TrClient* cc = s.clients[k].get();
5079 if (cc->client_name == c->client_name)
5080 if (cc->host_name == c->host_name)
5081 if (cc->port == c->port)
5082 if (cc->sequence_number == c->sequence_number)
5083 found = true;
5084 }
5085
5086 if (!found) {
5087 s.clients.push_back(std::unique_ptr<TrClient>(c));
5088 c = NULL;
5089 } else {
5090 cm_msg(MERROR, "cm_transition", "transition %s: client \"%s\" is registered with sequence number %d more than once", trname.c_str(), c->client_name.c_str(), c->sequence_number);
5091 delete c;
5092 c = NULL;
5093 }
5094 }
5095 }
5096 }
5097 }
5098
5099 std::sort(s.clients.begin(), s.clients.end(), tr_compare);
5100
5101 /* set predecessor for multi-threaded transitions */
5102 for (size_t idx = 0; idx < s.clients.size(); idx++) {
5103 if (s.clients[idx]->sequence_number == 0) {
5104 // sequence number 0 means "don't care"
5105 } else {
5106 /* find clients with smaller sequence number */
5107 if (idx > 0) {
5108 for (size_t i = idx - 1; ; i--) {
5109 if (s.clients[i]->sequence_number < s.clients[idx]->sequence_number) {
5110 if (s.clients[i]->sequence_number > 0) {
5111 s.clients[idx]->wait_for_index.push_back(i);
5112 }
5113 }
5114 if (i==0)
5115 break;
5116 }
5117 }
5118 }
5119 }
5120
5121 for (size_t idx = 0; idx < s.clients.size(); idx++) {
5122 write_tr_client_to_odb(hDB, s.clients[idx].get());
5123 }
5124
5125#if 0
5126 for (size_t idx = 0; idx < s.clients.size(); idx++) {
5127 printf("TrClient[%d]: ", int(idx));
5128 s.clients[idx]->Print();
5129 printf("\n");
5130 }
5131#endif
5132
5133 /* contact ordered clients for transition -----------------------*/
5135 for (size_t idx = 0; idx < s.clients.size(); idx++) {
5136 if (debug_flag == 1)
5137 printf("\n==== Found client \"%s\" with sequence number %d\n",
5138 s.clients[idx]->client_name.c_str(), s.clients[idx]->sequence_number);
5139 if (debug_flag == 2)
5140 cm_msg(MINFO, "cm_transition",
5141 "cm_transition: ==== Found client \"%s\" with sequence number %d",
5142 s.clients[idx]->client_name.c_str(), s.clients[idx]->sequence_number);
5143
5144 if (async_flag & TR_MTHREAD) {
5146 assert(s.clients[idx]->thread == NULL);
5147 s.clients[idx]->thread = new std::thread(cm_transition_call, &s, idx);
5148 } else {
5149 if (s.clients[idx]->port == 0) {
5150 /* if own client call transition callback directly */
5152 } else {
5153 /* if other client call transition via RPC layer */
5154 status = cm_transition_call(&s, idx);
5155 }
5156
5157 if (status == CM_SUCCESS && transition != TR_STOP)
5158 if (s.clients[idx]->status != SUCCESS) {
5159 cm_msg(MERROR, "cm_transition", "transition %s aborted: client \"%s\" returned status %d", trname.c_str(),
5160 s.clients[idx]->client_name.c_str(), int(s.clients[idx]->status));
5161 break;
5162 }
5163 }
5164
5165 if (status != CM_SUCCESS)
5166 break;
5167 }
5168
5169 /* wait until all threads have finished */
5170 for (size_t idx = 0; idx < s.clients.size(); idx++) {
5171 if (s.clients[idx]->thread) {
5172 // join() will wait forever until thread finishes
5173 s.clients[idx]->thread->join();
5174 delete s.clients[idx]->thread;
5175 s.clients[idx]->thread = NULL;
5176 }
5177 }
5178
5179 /* at this point, all per-client threads have stopped and it is safe to delete TrState and return */
5180
5181 i = 0;
5182 size = sizeof(i);
5183 status = db_get_value(hDB, 0, "/Runinfo/Transition in progress", &i, &size, TID_INT32, FALSE);
5184
5185 if (status == DB_SUCCESS && i == 0) {
5186 cm_msg(MERROR, "cm_transition", "transition %s aborted: \"/Runinfo/Transition in progress\" was cleared", trname.c_str());
5187
5188 if (errstr != NULL)
5189 mstrlcpy(errstr, "Canceled", errstr_size);
5190
5191 return tr_finish(hDB, &s, transition, CM_TRANSITION_CANCELED, "Canceled");
5192 }
5193
5194 /* search for any error */
5195 for (size_t idx = 0; idx < s.clients.size(); idx++)
5196 if (s.clients[idx]->status != CM_SUCCESS) {
5197 status = s.clients[idx]->status;
5198 if (errstr)
5199 mstrlcpy(errstr, s.clients[idx]->errorstr.c_str(), errstr_size);
5200 s.errorstr = msprintf("Aborted by client \"%s\"", s.clients[idx]->client_name.c_str());
5201 break;
5202 }
5203
5204 if (transition != TR_STOP && status != CM_SUCCESS) {
5205 /* indicate abort */
5206 i = 1;
5207 db_set_value(hDB, 0, "/Runinfo/Start abort", &i, sizeof(INT), 1, TID_INT32);
5208 i = 0;
5209 db_set_value(hDB, 0, "/Runinfo/Transition in progress", &i, sizeof(INT), 1, TID_INT32);
5210
5211 return tr_finish(hDB, &s, transition, status, errstr);
5212 }
5213
5214 if (debug_flag == 1)
5215 printf("\n---- Transition %s finished ----\n", trname.c_str());
5216 if (debug_flag == 2)
5217 cm_msg(MINFO, "cm_transition", "cm_transition: ---- Transition %s finished ----", trname.c_str());
5218
5219 /* set new run state in database */
5222
5223 if (transition == TR_PAUSE)
5225
5226 if (transition == TR_STOP)
5228
5231
5232 size = sizeof(state);
5233 status = db_set_value(hDB, 0, "Runinfo/State", &state, size, 1, TID_INT32);
5234 if (status != DB_SUCCESS)
5235 cm_msg(MERROR, "cm_transition", "cannot set Runinfo/State in database, db_set_value() status %d", status);
5236
5237 /* send notification message */
5238 if (transition == TR_START)
5239 cm_msg(MINFO, "cm_transition", "Run #%d started", run_number);
5240 if (transition == TR_STOP)
5241 cm_msg(MINFO, "cm_transition", "Run #%d stopped", run_number);
5242 if (transition == TR_PAUSE)
5243 cm_msg(MINFO, "cm_transition", "Run #%d paused", run_number);
5244 if (transition == TR_RESUME)
5245 cm_msg(MINFO, "cm_transition", "Run #%d resumed", run_number);
5247 cm_msg(MINFO, "cm_transition", "Run #%d start aborted", run_number);
5248
5249 /* lock/unlock ODB values if present */
5250 db_find_key(hDB, 0, "/Experiment/Lock when running", &hKey);
5251 if (hKey) {
5252 if (state == STATE_STOPPED)
5254 else
5256 }
5257
5258 /* flush online database */
5259 if (transition == TR_STOP)
5261
5262 /* execute/stop programs on stop */
5263 if (transition == TR_STOP) {
5264 std::string cmd;
5265 db_get_value_string(hDB, 0, "/Programs/Execute on stop run", 0, &cmd, TRUE, 256);
5266 if (!cmd.empty())
5267 ss_system(cmd.c_str());
5268
5269 db_find_key(hDB, 0, "/Programs", &hRootKey);
5270 if (hRootKey) {
5271 for (i = 0;; i++) {
5272 BOOL program_info_auto_stop = FALSE;
5273 status = db_enum_key(hDB, hRootKey, i, &hKey);
5275 break;
5276
5277 db_get_key(hDB, hKey, &key);
5278
5279 /* don't check "execute on xxx" */
5280 if (key.type != TID_KEY)
5281 continue;
5282
5283 size = sizeof(program_info_auto_stop);
5284 status = db_get_value(hDB, hKey, "Auto stop", &program_info_auto_stop, &size, TID_BOOL, TRUE);
5285 if (status != DB_SUCCESS) {
5286 cm_msg(MERROR, "cm_transition", "Cannot get program info auto stop, status %d", status);
5287 continue;
5288 }
5289
5290 if (program_info_auto_stop) {
5291 cm_msg(MINFO, "cm_transition", "Auto Stopping program \"%s\"", key.name);
5293 }
5294 }
5295 }
5296 }
5297
5298
5299 /* indicate success */
5300 i = 0;
5301 db_set_value(hDB, 0, "/Runinfo/Transition in progress", &i, sizeof(INT), 1, TID_INT32);
5302
5303 if (errstr != NULL)
5304 mstrlcpy(errstr, "Success", errstr_size);
5305
5306 return tr_finish(hDB, &s, transition, CM_SUCCESS, "Success");
5307}
INT al_get_alarms(std::string *presult)
Definition alarm.cxx:924
static int cm_transition_call(TrState *s, int idx)
Definition midas.cxx:4245
static int cm_transition_detach(INT transition, INT run_number, char *errstr, INT errstr_size, INT async_flag, INT debug_flag)
Definition midas.cxx:4162
static int tr_finish(HNDLE hDB, TrState *tr, int transition, int status, const char *errorstr)
Definition midas.cxx:4076
static void write_tr_client_to_odb(HNDLE hDB, const TrClient *tr_client)
Definition midas.cxx:4109
std::string cm_asctime()
Definition midas.cxx:1462
INT cm_exist(const char *name, BOOL bClientName)
Definition midas.cxx:7594
static bool tr_compare(const std::unique_ptr< TrClient > &arg1, const std::unique_ptr< TrClient > &arg2)
Definition midas.cxx:4056
INT cm_time(DWORD *t)
Definition midas.cxx:1484
static int cm_transition_call_direct(TrClient *tr_client)
Definition midas.cxx:4480
#define CM_DEFERRED_TRANSITION
Definition midas.h:591
#define CM_TRANSITION_CANCELED
Definition midas.h:597
#define AL_TRIGGERED
Definition midas.h:759
#define STATE_STOPPED
Definition midas.h:305
#define TR_DETACH
Definition midas.h:360
#define STATE_PAUSED
Definition midas.h:306
#define STATE_RUNNING
Definition midas.h:307
#define MAX_STRING_LENGTH
Definition msystem.h:113
INT db_flush_database(HNDLE hDB)
Definition odb.cxx:2801
INT db_get_data_index(HNDLE hDB, HNDLE hKey, void *data, INT *buf_size, INT idx, DWORD type)
Definition odb.cxx:7412
void rpc_client_check()
Definition midas.cxx:12503
#define TRANSITION_ERROR_STRING_LENGTH
Definition midas.h:280
INT k
Definition odbhist.cxx:40
std::string host_name
Definition midas.cxx:4016
DWORD init_time
Definition midas.cxx:4023
int port
Definition midas.cxx:4018
int sequence_number
Definition midas.cxx:4014
std::string client_name
Definition midas.cxx:4017
int transition
Definition midas.cxx:4063
std::vector< std::unique_ptr< TrClient > > clients
Definition midas.cxx:4071
int async_flag
Definition midas.cxx:4065
DWORD end_time
Definition midas.cxx:4070
int run_number
Definition midas.cxx:4064
int status
Definition midas.cxx:4067
DWORD start_time
Definition midas.cxx:4069
std::string errorstr
Definition midas.cxx:4068
int debug_flag
Definition midas.cxx:4066
char c
Definition system.cxx:1312
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_transition_call()

static int cm_transition_call ( TrState s,
int  idx 
)
static

Definition at line 4245 of file midas.cxx.

4245 {
4246 INT old_timeout, status, i, t1, t0, size;
4247 HNDLE hDB;
4248 HNDLE hConn = -1;
4249 int connect_timeout = 10000;
4250 int timeout = 120000;
4251
4253 assert(hDB);
4254
4255 TrClient *tr_client = s->clients[idx].get();
4256
4257 tr_client->errorstr = "";
4258 //tr_client->init_time = ss_millitime();
4259 tr_client->waiting_for_client = "";
4260 tr_client->connect_timeout = 0;
4261 tr_client->connect_start_time = 0;
4262 tr_client->connect_end_time = 0;
4263 tr_client->rpc_timeout = 0;
4264 tr_client->rpc_start_time = 0;
4265 tr_client->rpc_end_time = 0;
4266 tr_client->end_time = 0;
4267
4268 write_tr_client_to_odb(hDB, tr_client);
4269
4270 /* wait for predecessor if set */
4271 if (tr_client->async_flag & TR_MTHREAD && !tr_client->wait_for_index.empty()) {
4272 while (1) {
4273 TrClient* wait_for = NULL;
4274
4275 for (size_t i = 0; i < tr_client->wait_for_index.size(); i++) {
4276 int wait_for_index = tr_client->wait_for_index[i];
4277
4278 assert(wait_for_index >= 0);
4279 assert(wait_for_index < (int)s->clients.size());
4280
4281 TrClient *t = s->clients[wait_for_index].get();
4282
4283 if (!t)
4284 continue;
4285
4286 if (t->status == 0) {
4287 wait_for = t;
4288 break;
4289 }
4290
4291 if (t->status != SUCCESS && tr_client->transition != TR_STOP) {
4292 cm_msg(MERROR, "cm_transition_call", "Transition %d aborted: client \"%s\" returned status %d", tr_client->transition, t->client_name.c_str(), int(t->status));
4293 tr_client->status = -1;
4294 tr_client->errorstr = msprintf("Aborted by failure of client \"%s\"", t->client_name.c_str());
4295 tr_client->end_time = ss_millitime();
4296 write_tr_client_to_odb(hDB, tr_client);
4297 return CM_SUCCESS;
4298 }
4299 }
4300
4301 if (wait_for == NULL)
4302 break;
4303
4304 tr_client->waiting_for_client = wait_for->client_name;
4305 write_tr_client_to_odb(hDB, tr_client);
4306
4307 if (tr_client->debug_flag == 1)
4308 printf("Client \"%s\" waits for client \"%s\"\n", tr_client->client_name.c_str(), wait_for->client_name.c_str());
4309
4310 i = 0;
4311 size = sizeof(i);
4312 status = db_get_value(hDB, 0, "/Runinfo/Transition in progress", &i, &size, TID_INT32, FALSE);
4313
4314 if (status == DB_SUCCESS && i == 0) {
4315 cm_msg(MERROR, "cm_transition_call", "Client \"%s\" transition %d aborted while waiting for client \"%s\": \"/Runinfo/Transition in progress\" was cleared", tr_client->client_name.c_str(), tr_client->transition, wait_for->client_name.c_str());
4316 tr_client->status = -1;
4317 tr_client->errorstr = "Canceled";
4318 tr_client->end_time = ss_millitime();
4319 write_tr_client_to_odb(hDB, tr_client);
4320 return CM_SUCCESS;
4321 }
4322
4323 ss_sleep(100);
4324 };
4325 }
4326
4327 tr_client->waiting_for_client[0] = 0;
4328
4329 /* contact client if transition mask set */
4330 if (tr_client->debug_flag == 1)
4331 printf("Connecting to client \"%s\" on host %s...\n", tr_client->client_name.c_str(), tr_client->host_name.c_str());
4332 if (tr_client->debug_flag == 2)
4333 cm_msg(MINFO, "cm_transition_call", "cm_transition_call: Connecting to client \"%s\" on host %s...", tr_client->client_name.c_str(), tr_client->host_name.c_str());
4334
4335 /* get transition timeout for rpc connect */
4336 size = sizeof(timeout);
4337 db_get_value(hDB, 0, "/Experiment/Transition connect timeout", &connect_timeout, &size, TID_INT32, TRUE);
4338
4339 if (connect_timeout < 1000)
4340 connect_timeout = 1000;
4341
4342 /* get transition timeout */
4343 size = sizeof(timeout);
4344 db_get_value(hDB, 0, "/Experiment/Transition timeout", &timeout, &size, TID_INT32, TRUE);
4345
4346 if (timeout < 1000)
4347 timeout = 1000;
4348
4349 /* set our timeout for rpc_client_connect() */
4350 //old_timeout = rpc_get_timeout(RPC_HNDLE_CONNECT);
4351 rpc_set_timeout(RPC_HNDLE_CONNECT, connect_timeout, &old_timeout);
4352
4353 tr_client->connect_timeout = connect_timeout;
4354 tr_client->connect_start_time = ss_millitime();
4355
4356 write_tr_client_to_odb(hDB, tr_client);
4357
4358 /* client found -> connect to its server port */
4359 status = rpc_client_connect(tr_client->host_name.c_str(), tr_client->port, tr_client->client_name.c_str(), &hConn);
4360
4361 rpc_set_timeout(RPC_HNDLE_CONNECT, old_timeout);
4362
4363 tr_client->connect_end_time = ss_millitime();
4364 write_tr_client_to_odb(hDB, tr_client);
4365
4366 if (status != RPC_SUCCESS) {
4367 cm_msg(MERROR, "cm_transition_call",
4368 "cannot connect to client \"%s\" on host %s, port %d, status %d",
4369 tr_client->client_name.c_str(), tr_client->host_name.c_str(), tr_client->port, status);
4370 tr_client->errorstr = msprintf("Cannot connect to client \"%s\"", tr_client->client_name.c_str());
4371
4372 /* clients that do not respond to transitions are dead or defective, get rid of them. K.O. */
4373 cm_shutdown(tr_client->client_name.c_str());
4374 cm_cleanup(tr_client->client_name.c_str(), TRUE);
4375
4376 if (tr_client->transition != TR_STOP) {
4377 /* indicate abort */
4378 i = 1;
4379 db_set_value(hDB, 0, "/Runinfo/Start abort", &i, sizeof(INT), 1, TID_INT32);
4380 i = 0;
4381 db_set_value(hDB, 0, "/Runinfo/Transition in progress", &i, sizeof(INT), 1, TID_INT32);
4382 }
4383
4384 tr_client->status = status;
4385 tr_client->end_time = ss_millitime();
4386
4387 write_tr_client_to_odb(hDB, tr_client);
4388 return status;
4389 }
4390
4391 if (tr_client->debug_flag == 1)
4392 printf("Connection established to client \"%s\" on host %s\n", tr_client->client_name.c_str(), tr_client->host_name.c_str());
4393 if (tr_client->debug_flag == 2)
4394 cm_msg(MINFO, "cm_transition_call",
4395 "cm_transition: Connection established to client \"%s\" on host %s",
4396 tr_client->client_name.c_str(), tr_client->host_name.c_str());
4397
4398 /* call RC_TRANSITION on remote client with increased timeout */
4399 //old_timeout = rpc_get_timeout(hConn);
4400 rpc_set_timeout(hConn, timeout, &old_timeout);
4401
4402 tr_client->rpc_timeout = timeout;
4403 tr_client->rpc_start_time = ss_millitime();
4404 write_tr_client_to_odb(hDB, tr_client);
4405
4406 if (tr_client->debug_flag == 1)
4407 printf("Executing RPC transition client \"%s\" on host %s...\n",
4408 tr_client->client_name.c_str(), tr_client->host_name.c_str());
4409 if (tr_client->debug_flag == 2)
4410 cm_msg(MINFO, "cm_transition_call",
4411 "cm_transition: Executing RPC transition client \"%s\" on host %s...",
4412 tr_client->client_name.c_str(), tr_client->host_name.c_str());
4413
4414 t0 = ss_millitime();
4415
4416 char errorstr[TRANSITION_ERROR_STRING_LENGTH];
4417 errorstr[0] = 0;
4418
4419 status = rpc_client_call(hConn, RPC_RC_TRANSITION, tr_client->transition, tr_client->run_number, errorstr, sizeof(errorstr), tr_client->sequence_number);
4420
4421 tr_client->errorstr = errorstr;
4422
4423 t1 = ss_millitime();
4424
4425 tr_client->rpc_end_time = ss_millitime();
4426
4427 write_tr_client_to_odb(hDB, tr_client);
4428
4429 /* fix for clients returning 0 as error code */
4430 if (status == 0)
4431 status = FE_ERR_HW;
4432
4433 /* reset timeout */
4434 rpc_set_timeout(hConn, old_timeout);
4435
4436 //DWORD t2 = ss_millitime();
4437
4438 if (tr_client->debug_flag == 1)
4439 printf("RPC transition finished client \"%s\" on host \"%s\" in %d ms with status %d\n",
4440 tr_client->client_name.c_str(), tr_client->host_name.c_str(), t1 - t0, status);
4441 if (tr_client->debug_flag == 2)
4442 cm_msg(MINFO, "cm_transition_call",
4443 "cm_transition: RPC transition finished client \"%s\" on host \"%s\" in %d ms with status %d",
4444 tr_client->client_name.c_str(), tr_client->host_name.c_str(), t1 - t0, status);
4445
4446 if (status == RPC_NET_ERROR || status == RPC_TIMEOUT) {
4447 tr_client->errorstr = msprintf("RPC network error or timeout from client \'%s\' on host \"%s\"", tr_client->client_name.c_str(), tr_client->host_name.c_str());
4448 /* clients that do not respond to transitions are dead or defective, get rid of them. K.O. */
4449 cm_shutdown(tr_client->client_name.c_str());
4450 cm_cleanup(tr_client->client_name.c_str(), TRUE);
4451 } else if (status != CM_SUCCESS && tr_client->errorstr.empty()) {
4452 tr_client->errorstr = msprintf("Unknown error %d from client \'%s\' on host \"%s\"", status, tr_client->client_name.c_str(), tr_client->host_name.c_str());
4453 }
4454
4455 tr_client->status = status;
4456 tr_client->end_time = ss_millitime();
4457
4458 // write updated status and end_time to ODB
4459
4460 write_tr_client_to_odb(hDB, tr_client);
4461
4462#if 0
4463 printf("hconn %d cm_transition_call(%s) finished init %d connect %d end %d rpc %d end %d xxx %d end %d\n",
4464 hConn,
4465 tr_client->client_name.c_str(),
4466 tr_client->init_time - tr_client->init_time,
4467 tr_client->connect_start_time - tr_client->init_time,
4468 tr_client->connect_end_time - tr_client->init_time,
4469 tr_client->rpc_start_time - tr_client->init_time,
4470 tr_client->rpc_end_time - tr_client->init_time,
4471 t2 - tr_client->init_time,
4472 tr_client->end_time - tr_client->init_time);
4473#endif
4474
4475 return CM_SUCCESS;
4476}
INT cm_cleanup(const char *client_name, BOOL ignore_timeout)
Definition midas.cxx:7723
#define RPC_TIMEOUT
Definition midas.h:703
#define FE_ERR_HW
Definition midas.h:720
#define RPC_HNDLE_CONNECT
Definition midas.h:394
INT rpc_client_call(HNDLE hConn, DWORD routine_id,...)
Definition midas.cxx:14028
INT rpc_set_timeout(HNDLE hConn, int timeout_msec, int *old_timeout_msec)
Definition midas.cxx:13231
DWORD connect_timeout
Definition midas.cxx:4025
int transition
Definition midas.cxx:4010
DWORD connect_end_time
Definition midas.cxx:4027
std::atomic_int status
Definition midas.cxx:4020
std::vector< int > wait_for_index
Definition midas.cxx:4015
DWORD rpc_end_time
Definition midas.cxx:4030
std::string waiting_for_client
Definition midas.cxx:4024
DWORD rpc_timeout
Definition midas.cxx:4028
int async_flag
Definition midas.cxx:4012
DWORD rpc_start_time
Definition midas.cxx:4029
int debug_flag
Definition midas.cxx:4013
int run_number
Definition midas.cxx:4011
DWORD end_time
Definition midas.cxx:4031
DWORD connect_start_time
Definition midas.cxx:4026
std::string errorstr
Definition midas.cxx:4022
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_transition_call_direct()

static int cm_transition_call_direct ( TrClient tr_client)
static

Definition at line 4480 of file midas.cxx.

4481{
4482 HNDLE hDB;
4483
4485
4486 DWORD now = ss_millitime();
4487
4488 tr_client->errorstr = "";
4489 //tr_client->init_time = now;
4490 tr_client->waiting_for_client = "";
4491 tr_client->connect_timeout = 0;
4492 tr_client->connect_start_time = now;
4493 tr_client->connect_end_time = now;
4494 tr_client->rpc_timeout = 0;
4495 tr_client->rpc_start_time = 0;
4496 tr_client->rpc_end_time = 0;
4497 tr_client->end_time = 0;
4498
4499 write_tr_client_to_odb(hDB, tr_client);
4500
4501 // find registered handler
4502 // NB: this code should match same code in rpc_transition_dispatch()
4503 // NB: only use the first handler, this is how MIDAS always worked
4504 // NB: we could run all handlers, but we can return the status and error string of only one of them.
4505
4506 _trans_table_mutex.lock();
4507 size_t n = _trans_table.size();
4508 _trans_table_mutex.unlock();
4509
4510 for (size_t i = 0; i < n; i++) {
4511 _trans_table_mutex.lock();
4513 _trans_table_mutex.unlock();
4514 if (tt.transition == tr_client->transition && tt.sequence_number == tr_client->sequence_number) {
4515 /* call registered function */
4516 if (tt.func) {
4517 if (tr_client->debug_flag == 1)
4518 printf("Calling local transition callback\n");
4519 if (tr_client->debug_flag == 2)
4520 cm_msg(MINFO, "cm_transition_call_direct", "cm_transition: Calling local transition callback");
4521
4522 tr_client->rpc_start_time = ss_millitime();
4523
4524 write_tr_client_to_odb(hDB, tr_client);
4525
4526 char errorstr[TRANSITION_ERROR_STRING_LENGTH];
4527 errorstr[0] = 0;
4528
4529 tr_client->status = tt.func(tr_client->run_number, errorstr);
4530
4531 tr_client->errorstr = errorstr;
4532
4533 tr_client->rpc_end_time = ss_millitime();
4534
4535 if (tr_client->debug_flag == 1)
4536 printf("Local transition callback finished, status %d\n", int(tr_client->status));
4537 if (tr_client->debug_flag == 2)
4538 cm_msg(MINFO, "cm_transition_call_direct", "cm_transition: Local transition callback finished, status %d", int(tr_client->status));
4539
4540 tr_client->end_time = ss_millitime();
4541
4542 // write status and end_time to ODB
4543
4544 write_tr_client_to_odb(hDB, tr_client);
4545
4546 return tr_client->status;
4547 }
4548 }
4549 }
4550
4551 cm_msg(MERROR, "cm_transition_call_direct", "no handler for transition %d with sequence number %d", tr_client->transition, tr_client->sequence_number);
4552
4553 tr_client->status = CM_SUCCESS;
4554 tr_client->end_time = ss_millitime();
4555
4556 // write status and end_time to ODB
4557
4558 write_tr_client_to_odb(hDB, tr_client);
4559
4560 return CM_SUCCESS;
4561}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_transition_cleanup()

INT cm_transition_cleanup ( )

Definition at line 5341 of file midas.cxx.

5342{
5343 if (_trp.thread && !_trp.finished) {
5344 //printf("main transition thread did not finish yet!\n");
5346 }
5347
5348 std::thread* t = _trp.thread.exchange(NULL);
5349
5350 if (t) {
5351 t->join();
5352 delete t;
5353 t = NULL;
5354 }
5355
5356 return CM_SUCCESS;
5357}
Here is the caller graph for this function:

◆ cm_transition_detach()

static int cm_transition_detach ( INT  transition,
INT  run_number,
char *  errstr,
INT  errstr_size,
INT  async_flag,
INT  debug_flag 
)
static

Definition at line 4162 of file midas.cxx.

4162 {
4163 HNDLE hDB;
4164 int status;
4165 const char *args[100];
4166 std::string path;
4167 char debug_arg[256];
4168 char start_arg[256];
4169 std::string expt_name;
4170 std::string mserver_hostname;
4171
4172 int iarg = 0;
4173
4175
4176 const char *midassys = getenv("MIDASSYS");
4177 if (midassys) {
4178 path += midassys;
4179 path += DIR_SEPARATOR_STR;
4180 path += "bin";
4181 path += DIR_SEPARATOR_STR;
4182 }
4183 path += "mtransition";
4184
4185 args[iarg++] = path.c_str();
4186
4187 if (rpc_is_remote()) {
4188 /* if connected to mserver, pass connection info to mtransition */
4189 mserver_hostname = rpc_get_mserver_hostname();
4190 args[iarg++] = "-h";
4191 args[iarg++] = mserver_hostname.c_str();
4192 }
4193
4194 /* get experiment name from ODB */
4195 db_get_value_string(hDB, 0, "/Experiment/Name", 0, &expt_name, FALSE);
4196
4197 if (expt_name.length() > 0) {
4198 args[iarg++] = "-e";
4199 args[iarg++] = expt_name.c_str();
4200 }
4201
4202 if (debug_flag) {
4203 args[iarg++] = "-d";
4204
4205 sprintf(debug_arg, "%d", debug_flag);
4206 args[iarg++] = debug_arg;
4207 }
4208
4209 if (transition == TR_STOP)
4210 args[iarg++] = "STOP";
4211 else if (transition == TR_PAUSE)
4212 args[iarg++] = "PAUSE";
4213 else if (transition == TR_RESUME)
4214 args[iarg++] = "RESUME";
4215 else if (transition == TR_START) {
4216 args[iarg++] = "START";
4217
4218 sprintf(start_arg, "%d", run_number);
4219 args[iarg++] = start_arg;
4220 }
4221
4222 args[iarg++] = NULL;
4223
4224#if 0
4225 for (iarg = 0; args[iarg] != NULL; iarg++) {
4226 printf("arg[%d] [%s]\n", iarg, args[iarg]);
4227 }
4228#endif
4229
4230 status = ss_spawnv(P_DETACH, args[0], args);
4231
4232 if (status != SS_SUCCESS) {
4233 if (errstr != NULL) {
4234 sprintf(errstr, "Cannot execute mtransition, ss_spawnv() returned %d", status);
4235 }
4236 return CM_SET_ERROR;
4237 }
4238
4239 return CM_SUCCESS;
4240}
INT ss_spawnv(INT mode, const char *cmdname, const char *const argv[])
Definition system.cxx:1702
std::string rpc_get_mserver_hostname(void)
Definition midas.cxx:13038
char expt_name[NAME_LENGTH]
Definition mevb.cxx:44
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_watchdog_thread()

INT cm_watchdog_thread ( void *  unused)

Watchdog thread to maintain the watchdog timeout timestamps for this client

Definition at line 7403 of file midas.cxx.

7403 {
7405 //printf("cm_watchdog_thread started!\n");
7406 while (_watchdog_thread_run) {
7407 //printf("cm_watchdog_thread runs!\n");
7408 DWORD now = ss_millitime();
7411 int i;
7412 for (i = 0; i < 20; i++) {
7413 ss_sleep(100);
7415 break;
7416 }
7417 }
7418 //printf("cm_watchdog_thread stopped!\n");
7420 return 0;
7421}
static void bm_update_last_activity(DWORD millitime)
Definition midas.cxx:6189
INT db_update_last_activity(DWORD millitime)
Definition odb.cxx:3271
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_yield()

INT cm_yield ( INT  millisec)

Central yield functions for clients. This routine should be called in an infinite loop by a client in order to give the MIDAS system the opportunity to receive commands over RPC channels, update database records and receive events.

Parameters
millisecTimeout in millisec. If no message is received during the specified timeout, the routine returns. If millisec=-1, it only returns when receiving an RPC_SHUTDOWN message.
Returns
CM_SUCCESS, RPC_SHUTDOWN

Definition at line 5716 of file midas.cxx.

5716 {
5717 INT status;
5718 INT bMore;
5719 //static DWORD last_yield = 0;
5720 //static DWORD last_yield_time = 0;
5721 //DWORD start_yield = ss_millitime();
5722
5723 /* check for ctrl-c */
5724 if (_ctrlc_pressed)
5725 return RPC_SHUTDOWN;
5726
5727 /* flush the cm_msg buffer */
5729
5730 if (!rpc_is_remote()) {
5731 /* flush the ODB to its binary file */
5732 /* for remote clients, ODB is flushed by the mserver */
5733 HNDLE hDB;
5736 }
5737
5738 /* check for available events */
5739 if (rpc_is_remote()) {
5740 //printf("cm_yield() calling bm_poll_event()\n");
5742
5743 if (status == SS_ABORT) {
5744 return status;
5745 }
5746
5747 if (status == BM_SUCCESS) {
5748 /* one or more events received by bm_poll_event() */
5749 status = ss_suspend(0, 0);
5750 } else {
5751 status = ss_suspend(millisec, 0);
5752 }
5753
5754 return status;
5755 }
5756
5758
5759 if (status != CM_SUCCESS)
5760 return status;
5761
5762 //DWORD start_check = ss_millitime();
5763
5764 bMore = bm_check_buffers();
5765
5766 //DWORD end_check = ss_millitime();
5767 //printf("cm_yield: timeout %4d, yield period %4d, last yield time %4d, bm_check_buffers() elapsed %4d, returned %d\n", millisec, start_yield - last_yield, last_yield_time, end_check - start_check, bMore);
5768 //fflush(stdout);
5769
5770 if (bMore == BM_CORRUPTED) {
5771 status = SS_ABORT;
5772 } else if (bMore) {
5773 /* if events available, quickly check other IPC channels */
5774 status = ss_suspend(0, 0);
5775 } else {
5776 status = ss_suspend(millisec, 0);
5777 }
5778
5779 /* flush the cm_msg buffer */
5781
5782 //DWORD end_yield = ss_millitime();
5783 //last_yield_time = end_yield - start_yield;
5784 //last_yield = start_yield;
5785
5786 return status;
5787}
INT bm_poll_event()
Definition midas.cxx:11367
INT bm_check_buffers()
Definition midas.cxx:11195
INT cm_periodic_tasks()
Definition midas.cxx:5653
#define BM_CORRUPTED
Definition midas.h:623
INT ss_suspend(INT millisec, INT msg)
Definition system.cxx:4622
Here is the call graph for this function:
Here is the caller graph for this function:

◆ init_rpc_hosts()

static void init_rpc_hosts ( HNDLE  hDB)
static

Definition at line 3484 of file midas.cxx.

3484 {
3485 int status;
3486 char buf[256];
3487 int size, i;
3488 HNDLE hKey;
3489
3490 strcpy(buf, "localhost");
3491 size = sizeof(buf);
3492
3493 status = db_get_value(hDB, 0, "/Experiment/Security/RPC hosts/Allowed hosts[0]", buf, &size, TID_STRING, TRUE);
3494
3495 if (status != DB_SUCCESS) {
3496 cm_msg(MERROR, "init_rpc_hosts", "Cannot create the RPC hosts access control list, db_get_value() status %d",
3497 status);
3498 return;
3499 }
3500
3501 size = sizeof(i);
3502 i = 0;
3503 status = db_get_value(hDB, 0, "/Experiment/Security/Disable RPC hosts check", &i, &size, TID_BOOL, TRUE);
3504
3505 if (status != DB_SUCCESS) {
3506 cm_msg(MERROR, "init_rpc_hosts", "Cannot create \"Disable RPC hosts check\", db_get_value() status %d", status);
3507 return;
3508 }
3509
3510 if (i != 0) // RPC hosts check is disabled
3511 return;
3512
3513 status = db_find_key(hDB, 0, "/Experiment/Security/RPC hosts/Allowed hosts", &hKey);
3514
3515 if (status != DB_SUCCESS || hKey == 0) {
3516 cm_msg(MERROR, "init_rpc_hosts", "Cannot find the RPC hosts access control list, db_find_key() status %d",
3517 status);
3518 return;
3519 }
3520
3521 load_rpc_hosts(hDB, hKey, -99, NULL);
3522
3524
3525 if (status != DB_SUCCESS) {
3526 cm_msg(MERROR, "init_rpc_hosts", "Cannot watch the RPC hosts access control list, db_watch() status %d", status);
3527 return;
3528 }
3529}
static void load_rpc_hosts(HNDLE hDB, HNDLE hKey, int index, void *info)
Definition midas.cxx:3433
INT db_watch(HNDLE hDB, HNDLE hKey, void(*dispatcher)(INT, INT, INT, void *), void *info)
Definition odb.cxx:14406
Here is the call graph for this function:
Here is the caller graph for this function:

◆ load_rpc_hosts()

static void load_rpc_hosts ( HNDLE  hDB,
HNDLE  hKey,
int  index,
void *  info 
)
static

dox

Definition at line 3433 of file midas.cxx.

3433 {
3434 int status;
3435 int i, last;
3436 KEY key;
3437 int max_size;
3438 char *str;
3439
3440// if (index != -99)
3441// cm_msg(MINFO, "load_rpc_hosts", "Reloading RPC hosts access control list via hotlink callback");
3442
3444
3445 if (status != DB_SUCCESS)
3446 return;
3447
3448 //printf("clear rpc hosts!\n");
3450
3451 max_size = key.item_size;
3452 str = (char *) malloc(max_size);
3453
3454 last = 0;
3455 for (i = 0; i < key.num_values; i++) {
3456 int size = max_size;
3458 if (status != DB_SUCCESS)
3459 break;
3460
3461 if (strlen(str) < 1) // skip emties
3462 continue;
3463
3464 if (str[0] == '#') // skip commented-out entries
3465 continue;
3466
3467 //printf("add rpc hosts %d [%s]\n", i, str);
3469 last = i;
3470 }
3471
3472 if (key.num_values - last < 10) {
3473 int new_size = last + 10;
3474 status = db_set_num_values(hDB, hKey, new_size);
3475 if (status != DB_SUCCESS) {
3476 cm_msg(MERROR, "load_rpc_hosts",
3477 "Cannot resize the RPC hosts access control list, db_set_num_values(%d) status %d", new_size, status);
3478 }
3479 }
3480
3481 free(str);
3482}
INT db_set_num_values(HNDLE hDB, HNDLE hKey, INT num_values)
Definition odb.cxx:8018
INT rpc_add_allowed_host(const char *hostname)
Definition midas.cxx:16707
INT rpc_clear_allowed_hosts()
Definition midas.cxx:16682
Here is the call graph for this function:
Here is the caller graph for this function:

◆ rpc_client_shutdown()

static void rpc_client_shutdown ( )
static

Definition at line 12865 of file midas.cxx.

12866{
12867 /* close all open connections */
12868
12870
12871 for (unsigned i = 0; i < _client_connections.size(); i++) {
12873 if (c && c->connected) {
12874 int index = c->index;
12875 // must unlock the array, otherwise we hang -
12876 // rpc_client_disconnect() will do rpc_call_client()
12877 // which needs to lock the array to convert handle
12878 // to connection pointer. Ouch! K.O. Dec 2020.
12882 }
12883 }
12884
12885 for (unsigned i = 0; i < _client_connections.size(); i++) {
12887 //printf("client connection %d %p\n", i, c);
12888 if (c) {
12889 //printf("client connection %d %p connected %d\n", i, c, c->connected);
12890 if (!c->connected) {
12891 delete c;
12892 _client_connections[i] = NULL;
12893 }
12894 }
12895 }
12896
12898
12899 /* close server connection from other clients */
12900 for (unsigned i = 0; i < _server_acceptions.size(); i++) {
12901 if (_server_acceptions[i] && _server_acceptions[i]->recv_sock) {
12902 send(_server_acceptions[i]->recv_sock, "EXIT", 5, 0);
12903 _server_acceptions[i]->close();
12904 }
12905 }
12906}
static std::mutex _client_connections_mutex
Definition midas.cxx:11736
static std::vector< RPC_CLIENT_CONNECTION * > _client_connections
Definition midas.cxx:11737
static std::vector< RPC_SERVER_ACCEPTION * > _server_acceptions
Definition midas.cxx:11743
Here is the call graph for this function:
Here is the caller graph for this function:

◆ test_cm_expand_env1()

static bool test_cm_expand_env1 ( const char *  str,
const char *  expected 
)
static

Definition at line 7855 of file midas.cxx.

7855 {
7856 std::string s = cm_expand_env(str);
7857 printf("test_expand_env: [%s] -> [%s] expected [%s]",
7858 str,
7859 s.c_str(),
7860 expected);
7861 if (s != expected) {
7862 printf(", MISMATCH!\n");
7863 return false;
7864 }
7865
7866 printf("\n");
7867 return true;
7868}
std::string cm_expand_env(const char *str)
Definition midas.cxx:7823
Here is the call graph for this function:
Here is the caller graph for this function:

◆ tr_compare()

static bool tr_compare ( const std::unique_ptr< TrClient > &  arg1,
const std::unique_ptr< TrClient > &  arg2 
)
static

Definition at line 4056 of file midas.cxx.

4056 {
4057 return arg1->sequence_number < arg2->sequence_number;
4058}
Here is the caller graph for this function:

◆ tr_finish()

static int tr_finish ( HNDLE  hDB,
TrState tr,
int  transition,
int  status,
const char *  errorstr 
)
static

Definition at line 4076 of file midas.cxx.

4077{
4078 DWORD end_time = ss_millitime();
4079
4080 if (transition != TR_STARTABORT) {
4081 db_set_value(hDB, 0, "/System/Transition/end_time", &end_time, sizeof(DWORD), 1, TID_UINT32);
4082 db_set_value(hDB, 0, "/System/Transition/status", &status, sizeof(INT), 1, TID_INT32);
4083
4084 if (errorstr) {
4085 db_set_value(hDB, 0, "/System/Transition/error", errorstr, strlen(errorstr) + 1, 1, TID_STRING);
4086 } else if (status == CM_SUCCESS) {
4087 const char *buf = "Success";
4088 db_set_value(hDB, 0, "/System/Transition/error", buf, strlen(buf) + 1, 1, TID_STRING);
4089 } else {
4090 char buf[256];
4091 sprintf(buf, "status %d", status);
4092 db_set_value(hDB, 0, "/System/Transition/error", buf, strlen(buf) + 1, 1, TID_STRING);
4093 }
4094 }
4095
4096 tr->status = status;
4097 tr->end_time = end_time;
4098 if (errorstr) {
4099 tr->errorstr = errorstr;
4100 } else {
4101 tr->errorstr = "(null)";
4102 }
4103
4104 return status;
4105}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ tr_main_thread()

static INT tr_main_thread ( void *  param)
static

Definition at line 5328 of file midas.cxx.

5328 {
5329 INT status;
5330 TR_PARAM *trp;
5331
5332 trp = (TR_PARAM *) param;
5333 status = cm_transition1(trp->transition, trp->run_number, trp->errstr, trp->errstr_size, trp->async_flag, trp->debug_flag);
5334
5335 trp->status = status;
5336 trp->finished = TRUE;
5337
5338 return 0;
5339}
char param[10][256]
Definition mana.cxx:250
Here is the call graph for this function:
Here is the caller graph for this function:

◆ write_tr_client_to_odb()

static void write_tr_client_to_odb ( HNDLE  hDB,
const TrClient tr_client 
)
static

Definition at line 4109 of file midas.cxx.

4109 {
4110 //printf("Writing client [%s] to ODB\n", tr_client->client_name.c_str());
4111
4112 int status;
4113 HNDLE hKey;
4114
4115 if (tr_client->transition == TR_STARTABORT) {
4116 status = db_create_key(hDB, 0, "/System/Transition/TR_STARTABORT", TID_KEY);
4117 status = db_find_key(hDB, 0, "/System/Transition/TR_STARTABORT", &hKey);
4118 if (status != DB_SUCCESS)
4119 return;
4120 } else {
4121 status = db_create_key(hDB, 0, "/System/Transition/Clients", TID_KEY);
4122 status = db_find_key(hDB, 0, "/System/Transition/Clients", &hKey);
4123 if (status != DB_SUCCESS)
4124 return;
4125 }
4126
4127 // same client_name can exist with different sequence numbers!
4128 std::string keyname = msprintf("%s_%d", tr_client->client_name.c_str(), tr_client->sequence_number);
4129
4130 status = db_create_key(hDB, hKey, keyname.c_str(), TID_KEY);
4131 status = db_find_key(hDB, hKey, keyname.c_str(), &hKey);
4132 if (status != DB_SUCCESS)
4133 return;
4134
4135 DWORD now = ss_millitime();
4136
4137 //int transition;
4138 //int run_number;
4139 //int async_flag;
4140 //int debug_flag;
4141 status = db_set_value(hDB, hKey, "sequence_number", &tr_client->sequence_number, sizeof(INT), 1, TID_INT32);
4142 status = db_set_value(hDB, hKey, "client_name", tr_client->client_name.c_str(), tr_client->client_name.length() + 1, 1, TID_STRING);
4143 status = db_set_value(hDB, hKey, "host_name", tr_client->host_name.c_str(), tr_client->host_name.length() + 1, 1, TID_STRING);
4144 status = db_set_value(hDB, hKey, "port", &tr_client->port, sizeof(INT), 1, TID_INT32);
4145 status = db_set_value(hDB, hKey, "init_time", &tr_client->init_time, sizeof(DWORD), 1, TID_UINT32);
4146 status = db_set_value(hDB, hKey, "waiting_for_client", tr_client->waiting_for_client.c_str(), tr_client->waiting_for_client.length() + 1, 1, TID_STRING);
4147 status = db_set_value(hDB, hKey, "connect_timeout", &tr_client->connect_timeout, sizeof(DWORD), 1, TID_UINT32);
4148 status = db_set_value(hDB, hKey, "connect_start_time", &tr_client->connect_start_time, sizeof(DWORD), 1, TID_UINT32);
4149 status = db_set_value(hDB, hKey, "connect_end_time", &tr_client->connect_end_time, sizeof(DWORD), 1, TID_UINT32);
4150 status = db_set_value(hDB, hKey, "rpc_timeout", &tr_client->rpc_timeout, sizeof(DWORD), 1, TID_UINT32);
4151 status = db_set_value(hDB, hKey, "rpc_start_time", &tr_client->rpc_start_time, sizeof(DWORD), 1, TID_UINT32);
4152 status = db_set_value(hDB, hKey, "rpc_end_time", &tr_client->rpc_end_time, sizeof(DWORD), 1, TID_UINT32);
4153 status = db_set_value(hDB, hKey, "end_time", &tr_client->end_time, sizeof(DWORD), 1, TID_UINT32);
4154 status = db_set_value(hDB, hKey, "status", &tr_client->status, sizeof(INT), 1, TID_INT32);
4155 status = db_set_value(hDB, hKey, "error", tr_client->errorstr.c_str(), tr_client->errorstr.length() + 1, 1, TID_STRING);
4156 status = db_set_value(hDB, hKey, "last_updated", &now, sizeof(DWORD), 1, TID_UINT32);
4157}
INT db_create_key(HNDLE hDB, HNDLE hKey, const char *key_name, DWORD type)
Definition odb.cxx:3887
Here is the call graph for this function:
Here is the caller graph for this function:

◆ xbm_lock_buffer()

static int xbm_lock_buffer ( BUFFER pbuf)
static

Definition at line 8088 of file midas.cxx.

8089{
8090 int status;
8091
8092 // NB: locking order: 1st buffer mutex, 2nd buffer semaphore. Unlock in reverse order.
8093
8094 //if (pbuf->locked) {
8095 // fprintf(stderr, "double lock, abort!\n");
8096 // abort();
8097 //}
8098
8100
8101 if (status != BM_SUCCESS)
8102 return status;
8103
8104 status = ss_semaphore_wait_for(pbuf->semaphore, 1000);
8105
8106 if (status != SS_SUCCESS) {
8107 fprintf(stderr, "bm_lock_buffer: Lock buffer \"%s\" is taking longer than 1 second!\n", pbuf->buffer_name);
8108
8109 status = ss_semaphore_wait_for(pbuf->semaphore, 10000);
8110
8111 if (status != SS_SUCCESS) {
8112 fprintf(stderr, "bm_lock_buffer: Lock buffer \"%s\" is taking longer than 10 seconds, buffer semaphore is probably stuck, delete %s.SHM and try again!\n", pbuf->buffer_name, pbuf->buffer_name);
8113
8114 if (pbuf->buffer_header) {
8115 for (int i=0; i<MAX_CLIENTS; i++) {
8116 fprintf(stderr, "bm_lock_buffer: Buffer \"%s\" client %d \"%s\" pid %d\n", pbuf->buffer_name, i, pbuf->buffer_header->client[i].name, pbuf->buffer_header->client[i].pid);
8117 }
8118 }
8119
8121
8122 if (status != SS_SUCCESS) {
8123 fprintf(stderr, "bm_lock_buffer: Error: Cannot lock buffer \"%s\", ss_semaphore_wait_for() status %d, aborting...\n", pbuf->buffer_name, status);
8124 cm_msg(MERROR, "bm_lock_buffer", "Cannot lock buffer \"%s\", ss_semaphore_wait_for() status %d, aborting...", pbuf->buffer_name, status);
8125 abort();
8126 /* DOES NOT RETURN */
8127 }
8128 }
8129 }
8130
8131 // protect against double lock
8132 assert(!pbuf->locked);
8133 pbuf->locked = TRUE;
8134
8135#if 0
8136 int x = MAX_CLIENTS - 1;
8137 if (pbuf->buffer_header->client[x].unused1 != 0) {
8138 printf("lllock [%s] unused1 %d pid %d\n", pbuf->buffer_name, pbuf->buffer_header->client[x].unused1, getpid());
8139 }
8140 //assert(pbuf->buffer_header->client[x].unused1 == 0);
8141 pbuf->buffer_header->client[x].unused1 = getpid();
8142#endif
8143
8144 pbuf->count_lock++;
8145
8146 return BM_SUCCESS;
8147}
static int _bm_lock_timeout
Definition midas.cxx:5991
static int bm_lock_buffer_mutex(BUFFER *pbuf)
Definition midas.cxx:8059
INT ss_semaphore_wait_for(HNDLE semaphore_handle, DWORD timeout_millisec)
Definition system.cxx:2718
#define MAX_CLIENTS
Definition midas.h:274
INT unused1
Definition midas.h:945
HNDLE semaphore
Definition midas.h:1004
BOOL locked
Definition midas.h:1008
int count_lock
Definition midas.h:1012
Here is the call graph for this function:
Here is the caller graph for this function:

◆ xbm_unlock_buffer()

static void xbm_unlock_buffer ( BUFFER pbuf)
static

Definition at line 8150 of file midas.cxx.

8150 {
8151 // NB: locking order: 1st buffer mutex, 2nd buffer semaphore. Unlock in reverse order.
8152
8153#if 0
8154 int x = MAX_CLIENTS-1;
8155 if (pbuf->attached) {
8156 if (pbuf->buffer_header->client[x].unused1 != getpid()) {
8157 printf("unlock [%s] unused1 %d pid %d\n", pbuf->buffer_header->name, pbuf->buffer_header->client[x].unused1, getpid());
8158 }
8159 pbuf->buffer_header->client[x].unused1 = 0;
8160 } else {
8161 printf("unlock [??????] unused1 ????? pid %d\n", getpid());
8162 }
8163#endif
8164
8165 // protect against double unlock
8166 assert(pbuf->locked);
8167 pbuf->locked = FALSE;
8168
8170 pbuf->buffer_mutex.unlock();
8171}
INT ss_semaphore_release(HNDLE semaphore_handle)
Definition system.cxx:2860
Here is the call graph for this function:
Here is the caller graph for this function:

◆ xcm_watchdog_thread()

static void xcm_watchdog_thread ( )
static

Definition at line 7423 of file midas.cxx.

7423 {
7424 cm_watchdog_thread(NULL);
7425}
INT cm_watchdog_thread(void *unused)
Definition midas.cxx:7403
Here is the call graph for this function:
Here is the caller graph for this function:

Variable Documentation

◆ _ctrlc_pressed

BOOL _ctrlc_pressed = FALSE
static

Definition at line 5513 of file midas.cxx.

◆ _deferred_transition_mask

DWORD _deferred_transition_mask
static

Definition at line 3899 of file midas.cxx.

◆ _exptab

exptab_struct _exptab
static

Definition at line 1655 of file midas.cxx.

◆ _requested_transition

INT _requested_transition
static

dox

Definition at line 3898 of file midas.cxx.

◆ _watchdog_thread

std::atomic<std::thread*> _watchdog_thread {NULL}
static

Definition at line 7397 of file midas.cxx.

7397{NULL};

◆ _watchdog_thread_is_running

std::atomic<bool> _watchdog_thread_is_running {false}
static

Definition at line 7396 of file midas.cxx.

7396{false}; // set by watchdog thread

◆ _watchdog_thread_run

std::atomic<bool> _watchdog_thread_run {false}
static

Definition at line 7395 of file midas.cxx.

7395{false}; // set by main thread