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, char *client_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_exist (const char *name, BOOL bUnique)
 
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 6170 of file midas.cxx.

6171{
6172#ifdef LOCAL_ROUTINES
6173
6174 //printf("bm_cleanup: called by %s, actual_time %d, wrong_interval %d\n", who, actual_time, wrong_interval);
6175
6176 std::vector<BUFFER*> mybuffers;
6177
6178 gBuffersMutex.lock();
6179 mybuffers = gBuffers;
6180 gBuffersMutex.unlock();
6181
6182 /* check buffers */
6183 for (BUFFER* pbuf : mybuffers) {
6184 if (!pbuf)
6185 continue;
6186 if (pbuf->attached) {
6187 /* update the last_activity entry to show that we are alive */
6188
6189 bm_lock_buffer_guard pbuf_guard(pbuf);
6190
6191 if (!pbuf_guard.is_locked())
6192 continue;
6193
6194 BUFFER_CLIENT *pclient = bm_get_my_client_locked(pbuf_guard);
6195 pclient->last_activity = actual_time;
6196
6197 /* don't check other clients if interval is strange */
6198 if (!wrong_interval)
6200 }
6201 }
6202#endif // LOCAL_ROUTINES
6203}
static void bm_cleanup_buffer_locked(BUFFER *pbuf, const char *who, DWORD actual_time)
Definition midas.cxx:6084
static BUFFER_CLIENT * bm_get_my_client_locked(bm_lock_buffer_guard &pbuf_guard)
Definition midas.cxx:6017
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 11423 of file midas.cxx.

11449{
11450 INT i;
11451
11452 if ((uint16_t(pevent->event_id) & uint16_t(0xF000)) == uint16_t(EVENTID_FRAG1)) {
11453 /*---- start new event ----*/
11454
11455 //printf("First Frag detected : Ser#:%d ID=0x%x \n", pevent->serial_number, pevent->event_id);
11456
11457 /* check if fragments already stored */
11458 for (i = 0; i < MAX_DEFRAG_EVENTS; i++)
11459 if (defrag_buffer[i].event_id == (pevent->event_id & 0x0FFF))
11460 break;
11461
11462 if (i < MAX_DEFRAG_EVENTS) {
11463 free(defrag_buffer[i].pevent);
11464 defrag_buffer[i].pevent = NULL;
11465 memset(&defrag_buffer[i].event_id, 0, sizeof(EVENT_DEFRAG_BUFFER));
11466 cm_msg(MERROR, "bm_defragement_event",
11467 "Received new event with ID %d while old fragments were not completed",
11468 (pevent->event_id & 0x0FFF));
11469 }
11470
11471 /* search new slot */
11472 for (i = 0; i < MAX_DEFRAG_EVENTS; i++)
11473 if (defrag_buffer[i].event_id == 0)
11474 break;
11475
11476 if (i == MAX_DEFRAG_EVENTS) {
11477 cm_msg(MERROR, "bm_defragment_event",
11478 "Not enough defragment buffers, please increase MAX_DEFRAG_EVENTS and recompile");
11479 return;
11480 }
11481
11482 /* check event size */
11483 if (pevent->data_size != sizeof(DWORD)) {
11484 cm_msg(MERROR, "bm_defragment_event",
11485 "Received first event fragment with %d bytes instead of %d bytes, event ignored",
11486 pevent->data_size, (int) sizeof(DWORD));
11487 return;
11488 }
11489
11490 /* setup defragment buffer */
11491 defrag_buffer[i].event_id = (pevent->event_id & 0x0FFF);
11492 defrag_buffer[i].data_size = *(DWORD *) pdata;
11495
11496 if (defrag_buffer[i].pevent == NULL) {
11497 memset(&defrag_buffer[i].event_id, 0, sizeof(EVENT_DEFRAG_BUFFER));
11498 cm_msg(MERROR, "bm_defragement_event", "Not enough memory to allocate event defragment buffer");
11499 return;
11500 }
11501
11502 memcpy(defrag_buffer[i].pevent, pevent, sizeof(EVENT_HEADER));
11505
11506 // printf("First frag[%d] (ID %d) Ser#:%d sz:%d\n", i, defrag_buffer[i].event_id,
11507 // pevent->serial_number, defrag_buffer[i].data_size);
11508
11509 return;
11510 }
11511
11512 /* search buffer for that event */
11513 for (i = 0; i < MAX_DEFRAG_EVENTS; i++)
11514 if (defrag_buffer[i].event_id == (pevent->event_id & 0xFFF))
11515 break;
11516
11517 if (i == MAX_DEFRAG_EVENTS) {
11518 /* no buffer available -> no first fragment received */
11519 cm_msg(MERROR, "bm_defragement_event",
11520 "Received fragment without first fragment (ID %d) Ser#:%d",
11521 pevent->event_id & 0x0FFF, pevent->serial_number);
11522 return;
11523 }
11524
11525 /* add fragment to buffer */
11527 free(defrag_buffer[i].pevent);
11528 defrag_buffer[i].pevent = NULL;
11529 memset(&defrag_buffer[i].event_id, 0, sizeof(EVENT_DEFRAG_BUFFER));
11530 cm_msg(MERROR, "bm_defragement_event",
11531 "Received fragments with more data (%d) than event size (%d)",
11533 return;
11534 }
11535
11536 memcpy(((char *) defrag_buffer[i].pevent) + sizeof(EVENT_HEADER) +
11537 defrag_buffer[i].received, pdata, pevent->data_size);
11538
11539 defrag_buffer[i].received += pevent->data_size;
11540
11541 //printf("Other frag[%d][%d] (ID %d) Ser#:%d sz:%d\n", i, j++,
11542 // defrag_buffer[i].event_id, pevent->serial_number, pevent->data_size);
11543
11544 if (defrag_buffer[i].received == defrag_buffer[i].data_size) {
11545 /* event complete */
11546 dispatcher(buffer_handle, request_id, defrag_buffer[i].pevent, defrag_buffer[i].pevent + 1);
11547 free(defrag_buffer[i].pevent);
11548 defrag_buffer[i].pevent = NULL;
11549 memset(&defrag_buffer[i].event_id, 0, sizeof(EVENT_DEFRAG_BUFFER));
11550 }
11551}
#define MAX_DEFRAG_EVENTS
Definition midas.cxx:11411
static EVENT_DEFRAG_BUFFER defrag_buffer[MAX_DEFRAG_EVENTS]
Definition midas.cxx:11420
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:931
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:11417
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 6633 of file midas.cxx.

6634{
6635 size_t sbuffer_handle = buffer_handle;
6636
6637 size_t nbuf = 0;
6638 BUFFER* pbuf = NULL;
6639
6640 gBuffersMutex.lock();
6641
6642 nbuf = gBuffers.size();
6643 if (buffer_handle >=1 && sbuffer_handle <= nbuf) {
6644 pbuf = gBuffers[buffer_handle-1];
6645 }
6646
6647 gBuffersMutex.unlock();
6648
6649 if (sbuffer_handle > nbuf || buffer_handle <= 0) {
6650 if (who)
6651 cm_msg(MERROR, who, "invalid buffer handle %d: out of range [1..%d]", buffer_handle, (int)nbuf);
6652 if (pstatus)
6653 *pstatus = BM_INVALID_HANDLE;
6654 return NULL;
6655 }
6656
6657 if (!pbuf) {
6658 if (who)
6659 cm_msg(MERROR, who, "invalid buffer handle %d: empty slot", buffer_handle);
6660 if (pstatus)
6661 *pstatus = BM_INVALID_HANDLE;
6662 return NULL;
6663 }
6664
6665 if (!pbuf->attached) {
6666 if (who)
6667 cm_msg(MERROR, who, "invalid buffer handle %d: not attached", buffer_handle);
6668 if (pstatus)
6669 *pstatus = BM_INVALID_HANDLE;
6670 return NULL;
6671 }
6672
6673 if (pstatus)
6674 *pstatus = BM_SUCCESS;
6675
6676 return pbuf;
6677}
#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 6017 of file midas.cxx.

6017 {
6018 int my_client_index = bm_validate_client_index_locked(pbuf_guard);
6019 return pbuf_guard.get_pbuf()->buffer_header->client + my_client_index;
6020}
BUFFER * get_pbuf() const
Definition midas.cxx:3197
static int bm_validate_client_index_locked(bm_lock_buffer_guard &pbuf_guard)
Definition midas.cxx:5940
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 7957 of file midas.cxx.

7958{
7959 //printf("bm_lock_buffer_mutex %s!\n", pbuf->buffer_name);
7960
7961 bool locked = ss_timed_mutex_wait_for_sec(pbuf->buffer_mutex, "buffer mutex", _bm_mutex_timeout_sec);
7962
7963 if (!locked) {
7964 fprintf(stderr, "bm_lock_buffer_mutex: Error: Cannot lock buffer \"%s\", ss_timed_mutex_wait_for_sec() timeout, aborting...\n", pbuf->buffer_name);
7965 cm_msg(MERROR, "bm_lock_buffer_mutex", "Cannot lock buffer \"%s\", ss_timed_mutex_wait_for_sec() timeout, aborting...", pbuf->buffer_name);
7966 abort();
7967 /* DOES NOT RETURN */
7968 }
7969
7970 if (!pbuf->attached) {
7971 pbuf->buffer_mutex.unlock();
7972 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);
7973 return BM_INVALID_HANDLE;
7974 }
7975
7976 //static int counter = 0;
7977 //counter++;
7978 //printf("locked %d!\n", counter);
7979 //if (counter > 50)
7980 // ::sleep(3);
7981
7982 return BM_SUCCESS;
7983}
static double _bm_mutex_timeout_sec
Definition midas.cxx:5938
bool ss_timed_mutex_wait_for_sec(std::timed_mutex &mutex, const char *mutex_name, double timeout_sec)
Definition system.cxx:3337
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 7915 of file midas.cxx.

7916{
7917 bool locked = ss_timed_mutex_wait_for_sec(pbuf->read_cache_mutex, "buffer read cache", _bm_mutex_timeout_sec);
7918
7919 if (!locked) {
7920 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);
7921 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);
7922 abort();
7923 /* DOES NOT RETURN */
7924 }
7925
7926 if (!pbuf->attached) {
7927 pbuf->read_cache_mutex.unlock();
7928 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);
7929 return BM_INVALID_HANDLE;
7930 }
7931
7932 return BM_SUCCESS;
7933}
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 7936 of file midas.cxx.

7937{
7938 bool locked = ss_timed_mutex_wait_for_sec(pbuf->write_cache_mutex, "buffer write cache", _bm_mutex_timeout_sec);
7939
7940 if (!locked) {
7941 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);
7942 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);
7943 abort();
7944 /* DOES NOT RETURN */
7945 }
7946
7947 if (!pbuf->attached) {
7948 pbuf->write_cache_mutex.unlock();
7949 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);
7950 return BM_INVALID_HANDLE;
7951 }
7952
7953 return BM_SUCCESS;
7954}
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 11187 of file midas.cxx.

11207{
11208 static DWORD last_time = 0;
11209 DWORD now = ss_millitime();
11210
11211 //printf("bm_notify_client: buffer [%s], socket %d, time %d\n", buffer_name, client_socket, now - last_time);
11212
11213 BUFFER* fbuf = NULL;
11214
11215 gBuffersMutex.lock();
11216
11217 for (size_t i = 0; i < gBuffers.size(); i++) {
11218 BUFFER* pbuf = gBuffers[i];
11219 if (!pbuf || !pbuf->attached)
11220 continue;
11221 if (strcmp(buffer_name, pbuf->buffer_header->name) == 0) {
11222 fbuf = pbuf;
11223 break;
11224 }
11225 }
11226
11227 gBuffersMutex.unlock();
11228
11229 if (!fbuf)
11230 return BM_INVALID_HANDLE;
11231
11232 /* don't send notification if client has no callback defined
11233 to receive events -> client calls bm_receive_event manually */
11234 if (!fbuf->callback)
11235 return DB_SUCCESS;
11236
11237 int convert_flags = rpc_get_convert_flags();
11238
11239 /* only send notification once each 500ms */
11240 if (now - last_time < 500)
11241 return DB_SUCCESS;
11242
11243 last_time = now;
11244
11245 char buffer[32];
11246 NET_COMMAND *nc = (NET_COMMAND *) buffer;
11247
11248 nc->header.routine_id = MSG_BM;
11249 nc->header.param_size = 0;
11250
11251 if (convert_flags) {
11254 }
11255
11256 //printf("bm_notify_client: Sending MSG_BM! buffer [%s]\n", buffer_name);
11257
11258 /* send the update notification to the client */
11259 send_tcp(client_socket, (char *) buffer, sizeof(NET_COMMAND_HEADER), 0);
11260
11261 return BM_SUCCESS;
11262}
#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:3465
INT send_tcp(int sock, char *buffer, DWORD buffer_size, INT flags)
Definition system.cxx:5357
INT rpc_get_convert_flags(void)
Definition midas.cxx:13161
void rpc_convert_single(void *data, INT tid, INT flags, INT convert_flags)
Definition midas.cxx:11812
DWORD last_time
Definition mana.cxx:3070
char buffer_name[NAME_LENGTH]
Definition mevb.cxx:45
#define RPC_OUTGOING
Definition midas.h:1584
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 11057 of file midas.cxx.

11058{
11059 std::vector<BUFFER*> mybuffers;
11060
11061 gBuffersMutex.lock();
11062 mybuffers = gBuffers;
11063 gBuffersMutex.unlock();
11064
11065 for (size_t i = 0; i < mybuffers.size(); i++) {
11066 BUFFER *pbuf = mybuffers[i];
11067 if (!pbuf || !pbuf->attached)
11068 continue;
11069 // FIXME: unlocked read access to pbuf->buffer_name!
11070 if (strcmp(buffer_name, pbuf->buffer_name) == 0) {
11071 return bm_push_buffer(pbuf, i + 1);
11072 }
11073 }
11074
11075 return BM_INVALID_HANDLE;
11076}
static INT bm_push_buffer(BUFFER *pbuf, int buffer_handle)
Definition midas.cxx:11041
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 5474 of file midas.cxx.

5474 {
5476}
#define FALSE
Definition cfortran.h:309
static BOOL _ctrlc_pressed
Definition midas.cxx:5457
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 1428 of file midas.cxx.

1428 {
1429 /* if connected to server, get time from there */
1430 if (rpc_is_remote()) {
1431 char buf[256];
1432 int status = rpc_call(RPC_CM_ASCTIME, buf, sizeof(buf));
1433 if (status == CM_SUCCESS) {
1434 return buf;
1435 } else {
1436 return "";
1437 }
1438 }
1439
1440 /* return local time */
1441 return ss_asctime();
1442}
#define CM_SUCCESS
Definition midas.h:582
std::string ss_asctime()
Definition system.cxx:3621
#define RPC_CM_ASCTIME
Definition mrpc.h:28
bool rpc_is_remote(void)
Definition midas.cxx:12892
INT rpc_call(DWORD routine_id,...)
Definition midas.cxx:14115
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 1412 of file midas.cxx.

1412 {
1413 /* if connected to server, get time from there */
1414 if (rpc_is_remote())
1415 return rpc_call(RPC_CM_ASCTIME, str, buf_size);
1416
1417 /* return local time */
1418 mstrlcpy(str, ss_asctime().c_str(), buf_size);
1419
1420 return CM_SUCCESS;
1421}
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 1885 of file midas.cxx.

1885 {
1886 if (rpc_is_remote())
1887 return rpc_call(RPC_CM_CHECK_CLIENT, hDB, hKeyClient);
1888
1889#ifdef LOCAL_ROUTINES
1890 return db_check_client(hDB, hKeyClient);
1891#endif /*LOCAL_ROUTINES */
1892 return CM_SUCCESS;
1893}
INT db_check_client(HNDLE hDB, HNDLE hKeyClient)
Definition odb.cxx:3143
#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 2217 of file midas.cxx.

2217 {
2218 if (_hKeyClient) {
2219 cm_msg(MERROR, "cm_check_connect", "cm_disconnect_experiment not called at end of program");
2221 }
2222}
INT cm_msg_flush_buffer()
Definition midas.cxx:881
static HNDLE _hKeyClient
Definition midas.cxx:1472
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 3913 of file midas.cxx.

3913 {
3914 INT i, status;
3915 char str[256];
3916 static BOOL first;
3917
3918 if (_requested_transition == 0)
3919 first = TRUE;
3920
3922 for (i = 0; _deferred_trans_table[i].transition; i++)
3924 break;
3925
3927 if (((BOOL(*)(INT, BOOL)) _deferred_trans_table[i].func)(_requested_transition, first)) {
3929 if (status != CM_SUCCESS)
3930 cm_msg(MERROR, "cm_check_deferred_transition", "Cannot perform deferred transition: %s", str);
3931
3932 /* bypass hotlink and set _requested_transition directly to zero */
3934
3935 return status;
3936 }
3937 first = FALSE;
3938 }
3939 }
3940
3941 return SUCCESS;
3942}
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:5304
static DWORD _deferred_transition_mask
Definition midas.cxx:3843
static INT _requested_transition
Definition midas.cxx:3842
#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 7621 of file midas.cxx.

7621 {
7622 if (rpc_is_remote())
7623 return rpc_call(RPC_CM_CLEANUP, client_name);
7624
7625#ifdef LOCAL_ROUTINES
7626 {
7627 DWORD interval;
7628 DWORD now = ss_millitime();
7629
7630 std::vector<BUFFER*> mybuffers;
7631
7632 gBuffersMutex.lock();
7633 mybuffers = gBuffers;
7634 gBuffersMutex.unlock();
7635
7636 /* check buffers */
7637 for (BUFFER* pbuf : mybuffers) {
7638 if (!pbuf)
7639 continue;
7640 if (pbuf->attached) {
7641 std::string msg;
7642
7643 bm_lock_buffer_guard pbuf_guard(pbuf);
7644
7645 if (!pbuf_guard.is_locked())
7646 continue;
7647
7648 /* update the last_activity entry to show that we are alive */
7649 BUFFER_HEADER *pheader = pbuf->buffer_header;
7650 BUFFER_CLIENT *pclient = bm_get_my_client_locked(pbuf_guard);
7651 pclient->last_activity = ss_millitime();
7652
7653 /* now check other clients */
7654 for (int j = 0; j < pheader->max_client_index; j++) {
7655 BUFFER_CLIENT *pbclient = &pheader->client[j];
7656 if (j != pbuf->client_index && pbclient->pid &&
7657 (client_name == NULL || client_name[0] == 0
7658 || strncmp(pbclient->name, client_name, strlen(client_name)) == 0)) {
7659 if (ignore_timeout)
7660 interval = 2 * WATCHDOG_INTERVAL;
7661 else
7662 interval = pbclient->watchdog_timeout;
7663
7664 /* If client process has no activity, clear its buffer entry. */
7665 if (interval > 0
7666 && now > pbclient->last_activity && now - pbclient->last_activity > interval) {
7667
7668 /* now make again the check with the buffer locked */
7669 if (interval > 0
7670 && now > pbclient->last_activity && now - pbclient->last_activity > interval) {
7671 msg = msprintf(
7672 "Client \'%s\' on \'%s\' removed by cm_cleanup (idle %1.1lfs, timeout %1.0lfs)",
7673 pbclient->name, pheader->name,
7674 (ss_millitime() - pbclient->last_activity) / 1000.0,
7675 interval / 1000.0);
7676
7677 bm_remove_client_locked(pheader, j);
7678 }
7679
7680 /* go again through whole list */
7681 j = 0;
7682 }
7683 }
7684 }
7685
7686 // unlock buffer before calling cm_msg(), if we are SYSMSG, we will deadlock.
7687 pbuf_guard.unlock();
7688
7689 /* display info message after unlocking buffer */
7690 if (!msg.empty())
7691 cm_msg(MINFO, "cm_cleanup", "%s", msg.c_str());
7692 }
7693 }
7694
7695 db_cleanup2(client_name, ignore_timeout, now, "cm_cleanup");
7696 }
7697#endif /* LOCAL_ROUTINES */
7698
7699 return CM_SUCCESS;
7700}
void bm_remove_client_locked(BUFFER_HEADER *pheader, int j)
Definition midas.cxx:6053
#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:2981
#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 2782 of file midas.cxx.

2782 {
2783 HNDLE hDB, hKeyRoot, hSubkey, hKey;
2784 INT status, i, length, port;
2786
2787 /* find client entry in ODB */
2789
2790 status = db_find_key(hDB, 0, "System/Clients", &hKeyRoot);
2791 if (status != DB_SUCCESS)
2792 return status;
2793
2794 i = 0;
2795 do {
2796 /* search for client with specific name */
2797 status = db_enum_key(hDB, hKeyRoot, i++, &hSubkey);
2799 return CM_NO_CLIENT;
2800
2801 status = db_find_key(hDB, hSubkey, "Name", &hKey);
2802 if (status != DB_SUCCESS)
2803 return status;
2804
2805 length = NAME_LENGTH;
2806 status = db_get_data(hDB, hKey, name, &length, TID_STRING);
2807 if (status != DB_SUCCESS)
2808 return status;
2809
2810 if (equal_ustring(name, client_name)) {
2811 status = db_find_key(hDB, hSubkey, "Server Port", &hKey);
2812 if (status != DB_SUCCESS)
2813 return status;
2814
2815 length = sizeof(INT);
2816 status = db_get_data(hDB, hKey, &port, &length, TID_INT32);
2817 if (status != DB_SUCCESS)
2818 return status;
2819
2820 status = db_find_key(hDB, hSubkey, "Host", &hKey);
2821 if (status != DB_SUCCESS)
2822 return status;
2823
2824 length = sizeof(host_name);
2826 if (status != DB_SUCCESS)
2827 return status;
2828
2829 /* client found -> connect to its server port */
2830 return rpc_client_connect(host_name, port, client_name, hConn);
2831 }
2832
2833
2834 } while (TRUE);
2835}
INT cm_get_experiment_database(HNDLE *hDB, HNDLE *hKeyClient)
Definition midas.cxx:3027
#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:3285
INT db_get_data(HNDLE hDB, HNDLE hKey, void *data, INT *buf_size, DWORD type)
Definition odb.cxx:6563
INT db_find_key(HNDLE hDB, HNDLE hKey, const char *key_name, HNDLE *subhKey)
Definition odb.cxx:4256
INT db_enum_key(HNDLE hDB, HNDLE hKey, INT idx, HNDLE *subkey_handle)
Definition odb.cxx:5357
INT rpc_client_connect(const char *host_name, INT port, const char *client_name, HNDLE *hConnection)
Definition midas.cxx:12143
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:2294
INT cm_disconnect_experiment(void)
Definition midas.cxx:2862
INT cm_get_environment(char *host_name, int host_name_size, char *exp_name, int exp_name_size)
Definition midas.cxx:2150
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 2294 of file midas.cxx.

2294 {
2295 INT status;
2296
2299 if (status != CM_SUCCESS) {
2300 std::string s = cm_get_error(status);
2301 puts(s.c_str());
2302 }
2303
2304 return status;
2305}
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:2313
std::string cm_get_error(INT code)
Definition midas.cxx:469
#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 2313 of file midas.cxx.

2314 {
2315 INT status, size;
2316 char client_name1[NAME_LENGTH];
2317 char password[NAME_LENGTH], str[256];
2318 HNDLE hDB = 0, hKeyClient = 0;
2319 BOOL call_watchdog;
2320
2321 ss_tzset(); // required for localtime_r()
2322
2323 if (_hKeyClient)
2325
2327
2328 //cm_msg(MERROR, "cm_connect_experiment", "test cm_msg before connecting to experiment");
2329 //cm_msg_flush_buffer();
2330
2331 rpc_set_name(client_name);
2332
2333 /* check for local host */
2334 if (equal_ustring(host_name, "local"))
2335 host_name = NULL;
2336
2337#ifdef OS_WINNT
2338 {
2339 WSADATA WSAData;
2340
2341 /* Start windows sockets */
2342 if (WSAStartup(MAKEWORD(1, 1), &WSAData) != 0)
2343 return RPC_NET_ERROR;
2344 }
2345#endif
2346
2347 std::string default_exp_name1;
2348 if (default_exp_name)
2349 default_exp_name1 = default_exp_name;
2350
2351 /* connect to MIDAS server */
2352 if (host_name && host_name[0]) {
2353 if (default_exp_name1.length() == 0) {
2354 status = cm_select_experiment_remote(host_name, &default_exp_name1);
2355 if (status != CM_SUCCESS)
2356 return status;
2357 }
2358
2359 cm_set_experiment_name(default_exp_name1.c_str());
2360
2361 status = rpc_server_connect(host_name, default_exp_name1.c_str());
2362 if (status != RPC_SUCCESS)
2363 return status;
2364
2365 /* register MIDAS library functions */
2367 if (status != RPC_SUCCESS)
2368 return status;
2369 } else {
2370 /* lookup path for *SHM files and save it */
2371
2372#ifdef LOCAL_ROUTINES
2373 status = cm_set_experiment_local(default_exp_name1.c_str());
2374 if (status != CM_SUCCESS)
2375 return status;
2376
2377 default_exp_name1 = cm_get_experiment_name();
2378
2380
2381 INT semaphore_elog, semaphore_alarm, semaphore_history, semaphore_msg;
2382
2383 /* create alarm and elog semaphores */
2384 status = ss_semaphore_create("ALARM", &semaphore_alarm);
2385 if (status != SS_CREATED && status != SS_SUCCESS) {
2386 cm_msg(MERROR, "cm_connect_experiment", "Cannot create alarm semaphore");
2387 return status;
2388 }
2389 status = ss_semaphore_create("ELOG", &semaphore_elog);
2390 if (status != SS_CREATED && status != SS_SUCCESS) {
2391 cm_msg(MERROR, "cm_connect_experiment", "Cannot create elog semaphore");
2392 return status;
2393 }
2394 status = ss_semaphore_create("HISTORY", &semaphore_history);
2395 if (status != SS_CREATED && status != SS_SUCCESS) {
2396 cm_msg(MERROR, "cm_connect_experiment", "Cannot create history semaphore");
2397 return status;
2398 }
2399 status = ss_semaphore_create("MSG", &semaphore_msg);
2400 if (status != SS_CREATED && status != SS_SUCCESS) {
2401 cm_msg(MERROR, "cm_connect_experiment", "Cannot create message semaphore");
2402 return status;
2403 }
2404
2405 cm_set_experiment_semaphore(semaphore_alarm, semaphore_elog, semaphore_history, semaphore_msg);
2406#else
2407 return CM_UNDEF_EXP;
2408#endif
2409 }
2410
2411 //cm_msg(MERROR, "cm_connect_experiment", "test cm_msg before open ODB");
2412 //cm_msg_flush_buffer();
2413
2414 /* open ODB */
2415 if (odb_size == 0)
2417
2418 status = db_open_database("ODB", odb_size, &hDB, client_name);
2419 if (status != DB_SUCCESS && status != DB_CREATED) {
2420 cm_msg(MERROR, "cm_connect_experiment1", "cannot open database, db_open_database() status %d", status);
2421 return status;
2422 }
2423
2424 //cm_msg(MERROR, "cm_connect_experiment", "test cm_msg after open ODB");
2425 //cm_msg_flush_buffer();
2426
2427 int odb_timeout = db_set_lock_timeout(hDB, 0);
2428 size = sizeof(odb_timeout);
2429 status = db_get_value(hDB, 0, "/Experiment/ODB timeout", &odb_timeout, &size, TID_INT32, TRUE);
2430 if (status != DB_SUCCESS) {
2431 cm_msg(MERROR, "cm_connect_experiment1", "cannot get ODB /Experiment/ODB timeout, status %d", status);
2432 }
2433
2434 if (odb_timeout > 0) {
2435 db_set_lock_timeout(hDB, odb_timeout);
2436 }
2437
2438 BOOL protect_odb = FALSE;
2439 size = sizeof(protect_odb);
2440 status = db_get_value(hDB, 0, "/Experiment/Protect ODB", &protect_odb, &size, TID_BOOL, TRUE);
2441 if (status != DB_SUCCESS) {
2442 cm_msg(MERROR, "cm_connect_experiment1", "cannot get ODB /Experiment/Protect ODB, status %d", status);
2443 }
2444
2445 if (protect_odb) {
2447 }
2448
2449 BOOL enable_core_dumps = FALSE;
2450 size = sizeof(enable_core_dumps);
2451 status = db_get_value(hDB, 0, "/Experiment/Enable core dumps", &enable_core_dumps, &size, TID_BOOL, TRUE);
2452 if (status != DB_SUCCESS) {
2453 cm_msg(MERROR, "cm_connect_experiment1", "cannot get ODB /Experiment/Enable core dumps, status %d", status);
2454 }
2455
2456 if (enable_core_dumps) {
2457#ifdef RLIMIT_CORE
2458 struct rlimit limit;
2459 limit.rlim_cur = RLIM_INFINITY;
2460 limit.rlim_max = RLIM_INFINITY;
2461 status = setrlimit(RLIMIT_CORE, &limit);
2462 if (status != 0) {
2463 cm_msg(MERROR, "cm_connect_experiment", "Cannot setrlimit(RLIMIT_CORE, RLIM_INFINITY), errno %d (%s)", errno,
2464 strerror(errno));
2465 }
2466#else
2467#warning setrlimit(RLIMIT_CORE) is not available
2468#endif
2469 }
2470
2471 size = sizeof(disable_bind_rpc_to_localhost);
2472 status = db_get_value(hDB, 0, "/Experiment/Security/Enable non-localhost RPC", &disable_bind_rpc_to_localhost, &size,
2473 TID_BOOL, TRUE);
2474 if (status != DB_SUCCESS) {
2475 cm_msg(MERROR, "cm_connect_experiment1",
2476 "cannot get ODB /Experiment/Security/Enable non-localhost RPC, status %d", status);
2477 }
2478
2479 std::string local_host_name;
2480
2481 /* now setup client info */
2483 local_host_name = "localhost";
2484 else
2485 local_host_name = ss_gethostname();
2486
2487 /* check watchdog timeout */
2488 if (watchdog_timeout == 0)
2489 watchdog_timeout = DEFAULT_WATCHDOG_TIMEOUT;
2490
2491 strcpy(client_name1, client_name);
2492 password[0] = 0;
2493 status = cm_set_client_info(hDB, &hKeyClient, local_host_name.c_str(), client_name1, rpc_get_hw_type(), password, watchdog_timeout);
2494
2495 if (status == CM_WRONG_PASSWORD) {
2496 if (func == NULL)
2497 strcpy(str, ss_getpass("Password: "));
2498 else
2499 func(str);
2500
2501 strcpy(password, ss_crypt(str, "mi"));
2502 status = cm_set_client_info(hDB, &hKeyClient, local_host_name.c_str(), client_name1, rpc_get_hw_type(), password, watchdog_timeout);
2503 if (status != CM_SUCCESS) {
2504 /* disconnect */
2505 if (rpc_is_remote())
2508
2509 return status;
2510 }
2511 }
2512
2513 //cm_msg(MERROR, "cm_connect_experiment", "test cm_msg after set client info");
2514 //cm_msg_flush_buffer();
2515
2516 /* tell the rest of MIDAS that ODB is open for business */
2517
2518 cm_set_experiment_database(hDB, hKeyClient);
2519
2520 //cm_msg(MERROR, "cm_connect_experiment", "test cm_msg after set experiment database");
2521 //cm_msg_flush_buffer();
2522
2523 /* cm_msg_open_buffer() calls bm_open_buffer() calls ODB function
2524 * to get event buffer size, etc */
2525
2527 if (status != CM_SUCCESS) {
2528 cm_msg(MERROR, "cm_connect_experiment1", "cannot open message buffer, cm_msg_open_buffer() status %d", status);
2529 return status;
2530 }
2531
2532 //cm_msg(MERROR, "cm_connect_experiment", "test cm_msg after message system is ready");
2533 //cm_msg_flush_buffer();
2534
2535 /* set experiment name in ODB if not present */
2536 std::string current_name;
2537 db_get_value_string(hDB, 0, "/Experiment/Name", 0, &current_name, TRUE);
2538 if (current_name.length() == 0 || current_name == "Default") {
2539 db_set_value_string(hDB, 0, "/Experiment/Name", &default_exp_name1);
2540 }
2541
2542 if (!rpc_is_remote()) {
2543 /* experiment path is only set for local connections */
2544 /* set data dir in ODB */
2545 std::string path = cm_get_path();
2546 db_get_value_string(hDB, 0, "/Logger/Data dir", 0, &path, TRUE);
2547 }
2548
2549 /* register server to be able to be called by other clients */
2551 if (status != CM_SUCCESS) {
2552 cm_msg(MERROR, "cm_connect_experiment", "Cannot register RPC server, cm_register_server() status %d", status);
2553 if (!equal_ustring(client_name, "odbedit")) {
2554 return status;
2555 }
2556 }
2557
2558 /* set watchdog timeout */
2559 cm_get_watchdog_params(&call_watchdog, &watchdog_timeout);
2560 size = sizeof(watchdog_timeout);
2561 sprintf(str, "/Programs/%s/Watchdog Timeout", client_name);
2562 db_get_value(hDB, 0, str, &watchdog_timeout, &size, TID_INT32, TRUE);
2563 cm_set_watchdog_params(call_watchdog, watchdog_timeout);
2564
2565 /* set command line */
2566 std::string cmdline = ss_get_cmdline();
2567 std::string path = "/Programs/" + std::string(client_name);
2568 midas::odb prog(path);
2569 if (!midas::odb::exists(path + "/Start command") ||
2570 prog["Start command"] == std::string(""))
2571 prog["Start command"].set_string_size(cmdline, 256);
2572
2573 /* get final client name */
2574 std::string xclient_name = rpc_get_name();
2575
2576 /* startup message is not displayed */
2577 cm_msg(MLOG, "cm_connect_experiment", "Program %s on host %s started", xclient_name.c_str(), local_host_name.c_str());
2578
2579 /* enable system and user messages to stdout as default */
2581
2582 /* call cm_check_connect when exiting */
2583 atexit((void (*)(void)) cm_check_connect);
2584
2585 /* register ctrl-c handler */
2587
2588 //cm_msg(MERROR, "cm_connect_experiment", "test cm_msg after connect to experiment is complete");
2589 //cm_msg_flush_buffer();
2590
2591 return CM_SUCCESS;
2592}
static bool exists(const std::string &name)
Definition odbxx.cxx:75
INT cm_get_watchdog_params(BOOL *call_watchdog, DWORD *timeout)
Definition midas.cxx:3341
INT cm_select_experiment_remote(const char *host_name, std::string *exp_name)
Definition midas.cxx:2735
INT cm_register_server(void)
Definition midas.cxx:3476
void cm_check_connect(void)
Definition midas.cxx:2217
INT cm_set_client_info(HNDLE hDB, HNDLE *hKeyClient, const char *host_name, char *client_name, INT hw_type, const char *password, DWORD watchdog_timeout)
Definition midas.cxx:1909
std::string cm_get_path()
Definition midas.cxx:1553
int cm_set_experiment_local(const char *exp_name)
Definition midas.cxx:2182
std::string cm_get_experiment_name()
Definition midas.cxx:1596
INT cm_set_experiment_database(HNDLE hDB, HNDLE hKeyClient)
Definition midas.cxx:2955
void cm_ctrlc_handler(int sig)
Definition midas.cxx:5459
INT cm_set_watchdog_params(BOOL call_watchdog, DWORD timeout)
Definition midas.cxx:3299
INT cm_set_experiment_semaphore(INT semaphore_alarm, INT semaphore_elog, INT semaphore_history, INT semaphore_msg)
Definition midas.cxx:2974
INT cm_set_experiment_name(const char *name)
Definition midas.cxx:1574
#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:5784
INT ss_suspend_init_odb_port()
Definition system.cxx:4377
INT ss_semaphore_create(const char *name, HNDLE *semaphore_handle)
Definition system.cxx:2532
char * ss_getpass(const char *prompt)
Definition system.cxx:7518
void ss_tzset()
Definition system.cxx:3427
std::string ss_get_cmdline(void)
Definition system.cxx:1519
char * ss_crypt(const char *buf, const char *salt)
Definition system.cxx:7969
void * ss_ctrlc_handler(void(*func)(int))
Definition system.cxx:3971
int cm_msg_early_init(void)
Definition midas.cxx:481
int cm_msg_open_buffer(void)
Definition midas.cxx:488
INT cm_set_msg_print(INT system_mask, INT user_mask, int(*func)(const char *))
Definition midas.cxx:661
INT db_get_value(HNDLE hDB, HNDLE hKeyRoot, const char *key_name, void *data, INT *buf_size, DWORD type, BOOL create)
Definition odb.cxx:5185
INT db_open_database(const char *xdatabase_name, INT database_size, HNDLE *hDB, const char *client_name)
Definition odb.cxx:1820
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:13967
INT EXPRT db_set_value_string(HNDLE hDB, HNDLE hKeyRoot, const char *key_name, const std::string *s)
Definition odb.cxx:14038
INT db_set_lock_timeout(HNDLE hDB, int timeout_millisec)
Definition odb.cxx:2748
INT db_protect_database(HNDLE hDB)
Definition odb.cxx:3251
INT rpc_register_functions(const RPC_LIST *new_list, RPC_HANDLER func)
Definition midas.cxx:11958
INT rpc_server_connect(const char *host_name, const char *exp_name)
Definition midas.cxx:12512
std::string rpc_get_name()
Definition midas.cxx:13215
INT rpc_get_hw_type()
Definition midas.cxx:12965
INT rpc_server_disconnect()
Definition midas.cxx:12836
INT rpc_set_name(const char *name)
Definition midas.cxx:13239
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 5459 of file midas.cxx.

5459 {
5460 if (_ctrlc_pressed) {
5461 printf("Received 2nd Ctrl-C, hard abort\n");
5462 exit(0);
5463 }
5464 printf("Received Ctrl-C, aborting...\n");
5466
5468}
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 1868 of file midas.cxx.

1868 {
1869 /* only do it if local */
1870 if (!rpc_is_remote()) {
1872 }
1873 return CM_SUCCESS;
1874}
int db_delete_client_info(HNDLE hDB, int pid)
Definition odb.cxx:2876
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 3693 of file midas.cxx.

3693 {
3694 INT status;
3695 HNDLE hDB, hKey, hKeyTrans;
3696 char str[256];
3697
3698 /* check for valid transition */
3700 cm_msg(MERROR, "cm_deregister_transition", "Invalid transition request \"%d\"", transition);
3701 return CM_INVALID_TRANSITION;
3702 }
3703
3705
3706 {
3707 std::lock_guard<std::mutex> guard(_trans_table_mutex);
3708
3709 /* remove existing transition request */
3710 for (size_t i = 0; i < _trans_table.size(); i++) {
3712 _trans_table[i].transition = 0;
3713 _trans_table[i].sequence_number = 0;
3714 _trans_table[i].func = NULL;
3715 }
3716 }
3717
3718 // implicit unlock
3719 }
3720
3721 sprintf(str, "Transition %s", cm_transition_name(transition).c_str());
3722
3723 /* unlock database */
3725
3726 /* set value */
3727 status = db_find_key(hDB, hKey, str, &hKeyTrans);
3728 if (hKeyTrans) {
3729 status = db_delete_key(hDB, hKeyTrans);
3730 if (status != DB_SUCCESS)
3731 return status;
3732 }
3733
3734 /* re-lock database */
3736
3737 return CM_SUCCESS;
3738}
#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:3933
INT db_set_mode(HNDLE hDB, HNDLE hKey, WORD mode, BOOL recurse)
Definition odb.cxx:8040
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 2849 of file midas.cxx.

2849 {
2850 return rpc_client_disconnect(hConn, bShutdown);
2851}
INT rpc_client_disconnect(HNDLE hConn, BOOL bShutdown)
Definition midas.cxx:12807
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 2862 of file midas.cxx.

2862 {
2863 HNDLE hDB, hKey;
2864
2865 //cm_msg(MERROR, "cm_disconnect_experiment", "test cm_msg before disconnect from experiment");
2866 //cm_msg_flush_buffer();
2867
2868 /* wait on any transition thread */
2869 if (_trp.transition && !_trp.finished) {
2870 printf("Waiting for transition to finish...\n");
2871 do {
2872 ss_sleep(10);
2873 } while (!_trp.finished);
2874 }
2875
2876 /* stop the watchdog thread */
2878
2879 /* send shutdown notification */
2880 std::string client_name = rpc_get_name();
2881
2882 std::string local_host_name;
2883
2885 local_host_name = "localhost";
2886 else {
2887 local_host_name = ss_gethostname();
2888 //if (strchr(local_host_name, '.'))
2889 // *strchr(local_host_name, '.') = 0;
2890 }
2891
2892 /* disconnect message not displayed */
2893 cm_msg(MLOG, "cm_disconnect_experiment", "Program %s on host %s stopped", client_name.c_str(), local_host_name.c_str());
2895
2896 if (rpc_is_remote()) {
2897 if (rpc_is_connected()) {
2898 /* close open records */
2900
2902 }
2903
2906
2908 } else {
2910
2911 /* delete client info */
2913
2914 if (hDB)
2916
2917 //cm_msg(MERROR, "cm_disconnect_experiment", "test cm_msg before close all buffers, close all databases");
2918 //cm_msg_flush_buffer();
2919
2923
2925
2926 //cm_msg(MERROR, "cm_disconnect_experiment", "test cm_msg after close all buffers, close all databases");
2927 //cm_msg_flush_buffer();
2928 }
2929
2930 if (!rpc_is_mserver())
2932
2933 /* free RPC list */
2935
2936 //cm_msg(MERROR, "cm_disconnect_experiment", "test cm_msg before deleting the message ring buffer");
2937 //cm_msg_flush_buffer();
2938
2939 /* last flush before we delete the message ring buffer */
2941
2942 //cm_msg(MERROR, "cm_disconnect_experiment", "test cm_msg after disconnect is completed");
2943 //cm_msg_flush_buffer();
2944
2945 return CM_SUCCESS;
2946}
INT bm_close_all_buffers(void)
Definition midas.cxx:7254
INT cm_stop_watchdog_thread()
Definition midas.cxx:7381
static void rpc_client_shutdown()
Definition midas.cxx:12763
INT cm_delete_client_info(HNDLE hDB, INT pid)
Definition midas.cxx:1868
INT ss_sleep(INT millisec)
Definition system.cxx:3700
int cm_msg_close_buffer(void)
Definition midas.cxx:501
INT db_close_all_records()
Definition odb.cxx:13546
INT db_close_all_databases(void)
Definition odb.cxx:2398
INT rpc_deregister_functions()
Definition midas.cxx:12001
bool rpc_is_connected(void)
Definition midas.cxx:12914
INT rpc_server_shutdown(void)
Definition midas.cxx:17572
bool rpc_is_mserver(void)
Definition midas.cxx:12949
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 5403 of file midas.cxx.

5422{
5423 if (message[0] == 'O') {
5424 HNDLE hDB, hKey, hKeyRoot;
5425 INT index;
5426 index = 0;
5427 sscanf(message + 2, "%d %d %d %d", &hDB, &hKeyRoot, &hKey, &index);
5428 if (client_socket) {
5429 return db_update_record_mserver(hDB, hKeyRoot, hKey, index, client_socket);
5430 } else {
5431 return db_update_record_local(hDB, hKeyRoot, hKey, index);
5432 }
5433 }
5434
5435 /* message == "B" means "resume event sender" */
5436 if (message[0] == 'B' && message[2] != ' ') {
5437 char str[NAME_LENGTH];
5438
5439 //printf("cm_dispatch_ipc: message [%s], s=%d\n", message, s);
5440
5441 mstrlcpy(str, message + 2, sizeof(str));
5442 if (strchr(str, ' '))
5443 *strchr(str, ' ') = 0;
5444
5445 if (client_socket)
5446 return bm_notify_client(str, client_socket);
5447 else
5448 return bm_push_event(str);
5449 }
5450
5451 //printf("cm_dispatch_ipc: message [%s] ignored\n", message);
5452
5453 return CM_SUCCESS;
5454}
static INT bm_push_event(const char *buffer_name)
Definition midas.cxx:11057
static INT bm_notify_client(const char *buffer_name, int s)
Definition midas.cxx:11187
INT db_update_record_local(INT hDB, INT hKeyRoot, INT hKey, int index)
Definition odb.cxx:13584
INT db_update_record_mserver(INT hDB, INT hKeyRoot, INT hKey, int index, int client_socket)
Definition odb.cxx:13631
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 5479 of file midas.cxx.

5507{
5508 HNDLE hDB, hkey;
5509 KEY key;
5510 int status;
5511
5513 if (status != DB_SUCCESS)
5514 return status;
5515
5516 status = db_find_key(hDB, 0, odb_path_to_script, &hkey);
5517 if (status != DB_SUCCESS)
5518 return status;
5519
5520 status = db_get_key(hDB, hkey, &key);
5521 if (status != DB_SUCCESS)
5522 return status;
5523
5524 std::string command;
5525
5526 if (key.type == TID_STRING) {
5527 int status = db_get_value_string(hDB, 0, odb_path_to_script, 0, &command, FALSE);
5528 if (status != DB_SUCCESS) {
5529 cm_msg(MERROR, "cm_exec_script", "Script ODB \"%s\" of type TID_STRING, db_get_value_string() error %d",
5530 odb_path_to_script, status);
5531 return status;
5532 }
5533 } else if (key.type == TID_KEY) {
5534 for (int i = 0;; i++) {
5535 HNDLE hsubkey;
5536 KEY subkey;
5537 db_enum_key(hDB, hkey, i, &hsubkey);
5538 if (!hsubkey)
5539 break;
5540 db_get_key(hDB, hsubkey, &subkey);
5541
5542 if (i > 0)
5543 command += " ";
5544
5545 if (subkey.type == TID_KEY) {
5546 cm_msg(MERROR, "cm_exec_script", "Script ODB \"%s/%s\" should not be TID_KEY", odb_path_to_script,
5547 subkey.name);
5548 return DB_TYPE_MISMATCH;
5549 } else {
5550 int size = subkey.item_size;
5551 char *buf = (char *) malloc(size);
5552 assert(buf != NULL);
5553 int status = db_get_data(hDB, hsubkey, buf, &size, subkey.type);
5554 if (status != DB_SUCCESS) {
5555 cm_msg(MERROR, "cm_exec_script", "Script ODB \"%s/%s\" of type %d, db_get_data() error %d",
5556 odb_path_to_script, subkey.name, subkey.type, status);
5557 free(buf);
5558 return status;
5559 }
5560 if (subkey.type == TID_STRING) {
5561 command += buf;
5562 } else {
5563 command += db_sprintf(buf, subkey.item_size, 0, subkey.type);
5564 }
5565 free(buf);
5566 }
5567 }
5568 } else {
5569 cm_msg(MERROR, "cm_exec_script", "Script ODB \"%s\" has invalid type %d, should be TID_STRING or TID_KEY",
5570 odb_path_to_script, key.type);
5571 return DB_TYPE_MISMATCH;
5572 }
5573
5574 // printf("exec_script: %s\n", command.c_str());
5575
5576 if (command.length() > 0) {
5577 cm_msg(MINFO, "cm_exec_script", "Executing script \"%s\" from ODB \"%s\"", command.c_str(), odb_path_to_script);
5578 ss_system(command.c_str());
5579 }
5580
5581 return SUCCESS;
5582}
#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:6043
INT db_sprintf(char *string, const void *data, INT data_size, INT idx, DWORD type)
Definition odb.cxx:10865
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 5741 of file midas.cxx.

5741 {
5742 char str[256];
5743 INT n;
5744 int fh;
5745 int status = 0;
5746 static int check_cm_execute = 1;
5747 static int enable_cm_execute = 0;
5748
5749 if (rpc_is_remote())
5750 return rpc_call(RPC_CM_EXECUTE, command, result, bufsize);
5751
5752 if (check_cm_execute) {
5753 int status;
5754 int size;
5755 HNDLE hDB;
5756 check_cm_execute = 0;
5757
5759 assert(status == DB_SUCCESS);
5760
5761 size = sizeof(enable_cm_execute);
5762 status = db_get_value(hDB, 0, "/Experiment/Enable cm_execute", &enable_cm_execute, &size, TID_BOOL, TRUE);
5763 assert(status == DB_SUCCESS);
5764
5765 //printf("enable_cm_execute %d\n", enable_cm_execute);
5766 }
5767
5768 if (!enable_cm_execute) {
5769 char buf[32];
5770 mstrlcpy(buf, command, sizeof(buf));
5771 cm_msg(MERROR, "cm_execute", "cm_execute(%s...) is disabled by ODB \"/Experiment/Enable cm_execute\"", buf);
5772 return CM_WRONG_PASSWORD;
5773 }
5774
5775 if (bufsize > 0) {
5776 strcpy(str, command);
5777 sprintf(str, "%s > %d.tmp", command, ss_getpid());
5778
5779 status = system(str);
5780
5781 sprintf(str, "%d.tmp", ss_getpid());
5782 fh = open(str, O_RDONLY, 0644);
5783 result[0] = 0;
5784 if (fh) {
5785 n = read(fh, result, bufsize - 1);
5786 result[MAX(0, n)] = 0;
5787 close(fh);
5788 }
5789 remove(str);
5790 } else {
5791 status = system(command);
5792 }
5793
5794 if (status < 0) {
5795 cm_msg(MERROR, "cm_execute", "cm_execute(%s) error %d", command, status);
5796 return CM_SET_ERROR;
5797 }
5798
5799 return CM_SUCCESS;
5800}
#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  bUnique 
)

Check if a MIDAS client exists in current experiment

Parameters
nameClient name
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

Definition at line 7531 of file midas.cxx.

7531 {
7532 INT status, i, size;
7533 HNDLE hDB, hKeyClient, hKey, hSubkey;
7534 char client_name[NAME_LENGTH];
7535
7536 if (rpc_is_remote())
7537 return rpc_call(RPC_CM_EXIST, name, bUnique);
7538
7539 cm_get_experiment_database(&hDB, &hKeyClient);
7540
7541 status = db_find_key(hDB, 0, "System/Clients", &hKey);
7542 if (status != DB_SUCCESS)
7543 return DB_NO_KEY;
7544
7546
7547 /* loop over all clients */
7548 for (i = 0;; i++) {
7551 break;
7552
7553 if (hSubkey == hKeyClient)
7554 continue;
7555
7556 if (status == DB_SUCCESS) {
7557 /* get client name */
7558 size = sizeof(client_name);
7559 status = db_get_value(hDB, hSubkey, "Name", client_name, &size, TID_STRING, FALSE);
7560
7561 if (status != DB_SUCCESS) {
7562 //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);
7563 continue;
7564 }
7565
7566 if (equal_ustring(client_name, name)) {
7568 return CM_SUCCESS;
7569 }
7570
7571 if (!bUnique) {
7572 client_name[strlen(name)] = 0; /* strip number */
7573 if (equal_ustring(client_name, name)) {
7575 return CM_SUCCESS;
7576 }
7577 }
7578 }
7579 }
7580
7582
7583 return CM_NO_CLIENT;
7584}
#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:2508
static void db_unlock_database(DATABASE *pdb, const char *caller)
Definition odb.cxx:2670
#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 7721 of file midas.cxx.

7721 {
7722 const char *s = str;
7723 std::string r;
7724 for (; *s;) {
7725 if (*s == '$') {
7726 s++;
7727 std::string envname;
7728 for (; *s;) {
7729 if (*s == DIR_SEPARATOR)
7730 break;
7731 envname += *s;
7732 s++;
7733 }
7734 const char *e = getenv(envname.c_str());
7735 //printf("expanding [%s] at [%s] envname [%s] value [%s]\n", filename, s, envname.c_str(), e);
7736 if (!e) {
7737 //cm_msg(MERROR, "expand_env", "Env.variable \"%s\" cannot be expanded in \"%s\"", envname.c_str(), filename);
7738 r += '$';
7739 r += envname;
7740 } else {
7741 r += e;
7742 //if (r[r.length()-1] != DIR_SEPARATOR)
7743 //r += DIR_SEPARATOR_STR;
7744 }
7745 } else {
7746 r += *s;
7747 s++;
7748 }
7749 }
7750 return r;
7751}
#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 2075 of file midas.cxx.

2076{
2077 INT status;
2078 HNDLE hDB, hKey;
2079
2080 /* get root key of client */
2082 if (!hDB) {
2083 return "unknown";
2084 }
2085
2086 std::string name;
2087
2088 status = db_get_value_string(hDB, hKey, "Name", 0, &name);
2089 if (status != DB_SUCCESS) {
2090 return "unknown";
2091 }
2092
2093 //printf("get client name: [%s]\n", name.c_str());
2094
2095 return name;
2096}
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 2150 of file midas.cxx.

2150 {
2151 if (host_name)
2152 host_name[0] = 0;
2153 if (exp_name)
2154 exp_name[0] = 0;
2155
2156 if (host_name && getenv("MIDAS_SERVER_HOST"))
2157 mstrlcpy(host_name, getenv("MIDAS_SERVER_HOST"), host_name_size);
2158
2159 if (exp_name && getenv("MIDAS_EXPT_NAME"))
2160 mstrlcpy(exp_name, getenv("MIDAS_EXPT_NAME"), exp_name_size);
2161
2162 return CM_SUCCESS;
2163}
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 2165 of file midas.cxx.

2165 {
2166 if (host_name)
2167 *host_name = "";
2168 if (exp_name)
2169 *exp_name = "";
2170
2171 if (host_name && getenv("MIDAS_SERVER_HOST"))
2172 *host_name = getenv("MIDAS_SERVER_HOST");
2173
2174 if (exp_name && getenv("MIDAS_EXPT_NAME"))
2175 *exp_name = getenv("MIDAS_EXPT_NAME");
2176
2177 return CM_SUCCESS;
2178}

◆ 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 3027 of file midas.cxx.

3027 {
3028 if (_hDB) {
3029 //printf("cm_get_experiment_database %d %d\n", _hDB, _hKeyClient);
3030 if (hDB != NULL)
3031 *hDB = _hDB;
3032 if (hKeyClient != NULL)
3033 *hKeyClient = _hKeyClient;
3034 return CM_SUCCESS;
3035 } else {
3036 //printf("cm_get_experiment_database no init\n");
3037 if (hDB != NULL)
3038 *hDB = 0;
3039 if (hKeyClient != NULL)
3040 *hKeyClient = 0;
3041 return CM_DB_ERROR;
3042 }
3043}
#define CM_DB_ERROR
Definition midas.h:585
static HNDLE _hDB
Definition midas.cxx:1473

◆ cm_get_experiment_name() [1/2]

std::string cm_get_experiment_name ( )

Return the experiment name

Returns
experiment name

Definition at line 1596 of file midas.cxx.

1596 {
1597 return _experiment_name;
1598}
static std::string _experiment_name
Definition midas.cxx:1474
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 1586 of file midas.cxx.

1586 {
1587 mstrlcpy(name, _experiment_name.c_str(), name_length);
1588 return CM_SUCCESS;
1589}

◆ 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 3049 of file midas.cxx.

3069{
3070 if (semaphore_alarm)
3071 *semaphore_alarm = _semaphore_alarm;
3072 if (semaphore_elog)
3073 *semaphore_elog = _semaphore_elog;
3074 if (semaphore_history)
3075 *semaphore_history = _semaphore_history;
3076 //if (semaphore_msg)
3077 // *semaphore_msg = _semaphore_msg;
3078 if (semaphore_msg)
3079 *semaphore_msg = -1;
3080
3081 return CM_SUCCESS;
3082}
INT _semaphore_alarm
Definition midas.cxx:1478
INT _semaphore_elog
Definition midas.cxx:1479
INT _semaphore_history
Definition midas.cxx:1480
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 1846 of file midas.cxx.

1846 {
1847 std::string sdir, suser;
1848 int status = cm_get_exptab(expname, &sdir, &suser);
1849 if (status == CM_SUCCESS) {
1850 if (dir)
1851 mstrlcpy(dir, sdir.c_str(), dir_size);
1852 if (user)
1853 mstrlcpy(user, suser.c_str(), user_size);
1854 return CM_SUCCESS;
1855 }
1856 return CM_UNDEF_EXP;
1857}
int cm_get_exptab(const char *expname, std::string *dir, std::string *user)
Definition midas.cxx:1815
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 1815 of file midas.cxx.

1815 {
1816
1817 if (_exptab.exptab.size() == 0) {
1819 if (status != CM_SUCCESS)
1820 return status;
1821 }
1822
1823 for (unsigned i = 0; i < _exptab.exptab.size(); i++) {
1824 if (_exptab.exptab[i].name == expname) {
1825 if (dir)
1826 *dir = _exptab.exptab[i].directory;
1827 if (user)
1828 *user = _exptab.exptab[i].user;
1829 return CM_SUCCESS;
1830 }
1831 }
1832 if (dir)
1833 *dir = "";
1834 if (user)
1835 *user = "";
1836 return CM_UNDEF_EXP;
1837}
static exptab_struct _exptab
Definition midas.cxx:1621
INT cm_read_exptab(exptab_struct *exptab)
Definition midas.cxx:1630
std::vector< exptab_entry > exptab
Definition midas.cxx:1618
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 1804 of file midas.cxx.

1804 {
1805 return _exptab.filename;
1806}
std::string filename
Definition midas.cxx:1617
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 1799 of file midas.cxx.

1799 {
1800 mstrlcpy(s, _exptab.filename.c_str(), size);
1801 return CM_SUCCESS;
1802}

◆ cm_get_history_path()

std::string cm_get_history_path ( const char *  history_channel)

dox

Definition at line 5861 of file midas.cxx.

5862{
5863 int status;
5864 HNDLE hDB;
5865 std::string path;
5866
5868
5869 if (history_channel && (strlen(history_channel) > 0)) {
5870 std::string p;
5871 p += "/Logger/History/";
5872 p += history_channel;
5873 p += "/History dir";
5874
5875 // NB: be careful to avoid creating odb entries under /logger
5876 // for whatever values of "history_channel" we get called with!
5877 status = db_get_value_string(hDB, 0, p.c_str(), 0, &path, FALSE);
5878 if (status == DB_SUCCESS && path.length() > 0) {
5879 // if not absolute path, prepend with experiment directory
5880 if (path[0] != DIR_SEPARATOR)
5881 path = cm_get_path() + path;
5882 // append directory separator
5883 if (path.back() != DIR_SEPARATOR)
5884 path += DIR_SEPARATOR_STR;
5885 //printf("for [%s] returning [%s] from [%s]\n", history_channel, path.c_str(), p.c_str());
5886 return path;
5887 }
5888 }
5889
5890 status = db_get_value_string(hDB, 0, "/Logger/History dir", 0, &path, TRUE);
5891 if (status == DB_SUCCESS && path.length() > 0) {
5892 // if not absolute path, prepend with experiment directory
5893 if (path[0] != DIR_SEPARATOR)
5894 path = cm_get_path() + path;
5895 // append directory separator
5896 if (path.back() != DIR_SEPARATOR)
5897 path += DIR_SEPARATOR_STR;
5898 //printf("for [%s] returning /Logger/History dir [%s]\n", history_channel, path.c_str());
5899 return path;
5900 }
5901
5902 status = db_get_value_string(hDB, 0, "/Logger/Data dir", 0, &path, FALSE);
5903 if (status == DB_SUCCESS && path.length() > 0) {
5904 // if not absolute path, prepend with experiment directory
5905 if (path[0] != DIR_SEPARATOR)
5906 path = cm_get_path() + path;
5907 // append directory separator
5908 if (path.back() != DIR_SEPARATOR)
5909 path += DIR_SEPARATOR_STR;
5910 //printf("for [%s] returning /Logger/Data dir [%s]\n", history_channel, path.c_str());
5911 return path;
5912 }
5913
5914 //printf("for [%s] returning experiment dir [%s]\n", history_channel, cm_get_path().c_str());
5915 return cm_get_path();
5916}
#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 1553 of file midas.cxx.

1553 {
1554 assert(_path_name.length() > 0);
1555 return _path_name;
1556}
static std::string _path_name
Definition midas.cxx:1476
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 1534 of file midas.cxx.

1534 {
1535 // check that we were not accidentally called
1536 // with the size of the pointer to a string
1537 // instead of the size of the string buffer
1538 assert(path_size != sizeof(char *));
1539 assert(path);
1540 assert(_path_name.length() > 0);
1541
1542 mstrlcpy(path, _path_name.c_str(), path_size);
1543
1544 return CM_SUCCESS;
1545}

◆ cm_get_path_string()

INT EXPRT cm_get_path_string ( std::string *  path)

Definition at line 1561 of file midas.cxx.

1561 {
1562 assert(path != NULL);
1563 assert(_path_name.length() > 0);
1564 *path = _path_name;
1565 return CM_SUCCESS;
1566}

◆ 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 1500 of file midas.cxx.

1500 {
1501 return GIT_REVISION;
1502}
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 1492 of file midas.cxx.

1492 {
1493 return MIDAS_VERSION;
1494}
#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 3360 of file midas.cxx.

3360 {
3361 if (rpc_is_remote())
3362 return rpc_call(RPC_CM_GET_WATCHDOG_INFO, hDB, client_name, timeout, last);
3363
3364#ifdef LOCAL_ROUTINES
3365 return db_get_watchdog_info(hDB, client_name, timeout, last);
3366#else /* LOCAL_ROUTINES */
3367 return CM_SUCCESS;
3368#endif /* LOCAL_ROUTINES */
3369}
INT db_get_watchdog_info(HNDLE hDB, const char *client_name, DWORD *timeout, DWORD *last)
Definition odb.cxx:3098
#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 3341 of file midas.cxx.

3341 {
3342 if (call_watchdog)
3343 *call_watchdog = FALSE;
3344 if (timeout)
3345 *timeout = _watchdog_timeout;
3346
3347 return CM_SUCCESS;
3348}
static INT _watchdog_timeout
Definition midas.cxx:1477
Here is the caller graph for this function:

◆ cm_is_ctrlc_pressed()

BOOL cm_is_ctrlc_pressed ( void  )

Definition at line 5470 of file midas.cxx.

5470 {
5471 return _ctrlc_pressed;
5472}
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 2602 of file midas.cxx.

2602 {
2603 assert(exp_names != NULL);
2604 exp_names->clear();
2605
2606 if (_exptab.exptab.size() == 0) {
2608 if (status != CM_SUCCESS)
2609 return status;
2610 }
2611
2612 for (unsigned i=0; i<_exptab.exptab.size(); i++) {
2613 exp_names->push_back(_exptab.exptab[i].name);
2614 }
2615
2616 return CM_SUCCESS;
2617}
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 2628 of file midas.cxx.

2628 {
2629 INT status;
2630 INT sock;
2631 int port = MIDAS_TCP_PORT;
2632 char hname[256];
2633 char *s;
2634
2635 assert(exp_names != NULL);
2636 exp_names->clear();
2637
2638 /* extract port number from host_name */
2639 mstrlcpy(hname, host_name, sizeof(hname));
2640 s = strchr(hname, ':');
2641 if (s) {
2642 *s = 0;
2643 port = strtoul(s + 1, NULL, 0);
2644 }
2645
2646 std::string errmsg;
2647
2648 status = ss_socket_connect_tcp(hname, port, &sock, &errmsg);
2649
2650 if (status != SS_SUCCESS) {
2651 cm_msg(MERROR, "cm_list_experiments_remote", "Cannot connect to \"%s\" port %d: %s", hname, port, errmsg.c_str());
2652 return RPC_NET_ERROR;
2653 }
2654
2655 /* request experiment list */
2656 send(sock, "I", 2, 0);
2657
2658 while (1) {
2659 char str[256];
2660
2661 status = recv_string(sock, str, sizeof(str), _rpc_connect_timeout);
2662
2663 if (status < 0)
2664 return RPC_NET_ERROR;
2665
2666 if (status == 0)
2667 break;
2668
2669 exp_names->push_back(str);
2670 }
2671
2672 ss_socket_close(&sock);
2673
2674 return CM_SUCCESS;
2675}
INT recv_string(int sock, char *buffer, DWORD buffer_size, INT millisec)
Definition system.cxx:5471
INT ss_socket_connect_tcp(const char *hostname, int tcp_port, int *sockp, std::string *error_msg_p)
Definition system.cxx:5039
INT ss_socket_close(int *sockp)
Definition system.cxx:5303
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 5597 of file midas.cxx.

5597 {
5598 static DWORD alarm_last_checked_sec = 0;
5599 DWORD now_sec = ss_time();
5600
5601 DWORD now_millitime = ss_millitime();
5602 static DWORD last_millitime = 0;
5603 DWORD tdiff_millitime = now_millitime - last_millitime;
5604 const DWORD kPeriod = 1000;
5605 if (last_millitime == 0) {
5606 last_millitime = now_millitime;
5607 tdiff_millitime = kPeriod; // make sure first time we come here we do something.
5608 }
5609
5610 //printf("cm_periodic_tasks! tdiff_millitime %d\n", (int)tdiff_millitime);
5611
5612 //if (now_millitime < last_millitime) {
5613 // printf("millitime wraparound 0x%08x -> 0x%08x\n", last_millitime, now_millitime);
5614 //}
5615
5616 /* check alarms once every 10 seconds */
5617 if (now_sec - alarm_last_checked_sec > 10) {
5618 al_check();
5619 alarm_last_checked_sec = now_sec;
5620 }
5621
5622 /* run periodic checks previously done by cm_watchdog */
5623
5624 if (tdiff_millitime >= kPeriod) {
5625 BOOL wrong_interval = FALSE;
5626 if (tdiff_millitime > 60000)
5627 wrong_interval = TRUE;
5628
5629 //printf("millitime %u, diff %u, wrong_interval %d\n", now_millitime, tdiff_millitime, wrong_interval);
5630
5631 bm_cleanup("cm_periodic_tasks", now_millitime, wrong_interval);
5632 db_cleanup("cm_periodic_tasks", now_millitime, wrong_interval);
5633
5635
5636 last_millitime = now_millitime;
5637 }
5638
5639 /* reap transition thread */
5640
5642
5643 return CM_SUCCESS;
5644}
INT al_check()
Definition alarm.cxx:631
INT bm_write_statistics_to_odb(void)
Definition midas.cxx:7291
static void bm_cleanup(const char *who, DWORD actual_time, BOOL wrong_interval)
Definition midas.cxx:6170
INT cm_transition_cleanup()
Definition midas.cxx:5285
DWORD ss_time()
Definition system.cxx:3534
void db_cleanup(const char *who, DWORD actual_time, BOOL wrong_interval)
Definition odb.cxx:2911
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 1630 of file midas.cxx.

1631{
1632 exptab->exptab.clear();
1633
1634 /* MIDAS_DIR overrides exptab */
1635 if (getenv("MIDAS_DIR")) {
1636 exptab->filename = "MIDAS_DIR";
1637
1639
1640 if (getenv("MIDAS_EXPT_NAME")) {
1641 e.name = getenv("MIDAS_EXPT_NAME");
1642 } else {
1643 e.name = "Default";
1644 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());
1645 }
1646
1647 e.directory = getenv("MIDAS_DIR");
1648 e.user = "";
1649
1650 exptab->exptab.push_back(e);
1651
1652 return CM_SUCCESS;
1653 }
1654
1655 /* default directory for different OSes */
1656#if defined (OS_WINNT)
1657 std::string str;
1658 if (getenv("SystemRoot"))
1659 str = getenv("SystemRoot");
1660 else if (getenv("windir"))
1661 str = getenv("windir");
1662 else
1663 str = "";
1664
1665 std::string alt_str = str;
1666 str += "\\system32\\exptab";
1667 alt_str += "\\system\\exptab";
1668#elif defined (OS_UNIX)
1669 std::string str = "/etc/exptab";
1670 std::string alt_str = "/exptab";
1671#else
1672 std::strint str = "exptab";
1673 std::string alt_str = "exptab";
1674#endif
1675
1676 /* MIDAS_EXPTAB overrides default directory */
1677 if (getenv("MIDAS_EXPTAB")) {
1678 str = getenv("MIDAS_EXPTAB");
1679 alt_str = getenv("MIDAS_EXPTAB");
1680 }
1681
1682 exptab->filename = str;
1683
1684 /* read list of available experiments */
1685 FILE* f = fopen(str.c_str(), "r");
1686 if (f == NULL) {
1687 f = fopen(alt_str.c_str(), "r");
1688 if (f == NULL)
1689 return CM_UNDEF_ENVIRON;
1690 exptab->filename = alt_str;
1691 }
1692
1693 if (f != NULL) {
1694 do {
1695 char buf[256];
1696 memset(buf, 0, sizeof(buf));
1697 char* str = fgets(buf, sizeof(buf)-1, f);
1698 if (str == NULL)
1699 break;
1700 if (str[0] == 0) continue; // empty line
1701 if (str[0] == '#') continue; // comment line
1702
1704
1705 // following code emulates the function of this sprintf():
1706 //sscanf(str, "%s %s %s", exptab[i].name, exptab[i].directory, exptab[i].user);
1707
1708 // skip leading spaces
1709 while (*str && isspace(*str))
1710 str++;
1711
1712 char* p1 = str;
1713 char* p2 = str;
1714
1715 while (*p2 && !isspace(*p2))
1716 p2++;
1717
1718 ssize_t len = p2-p1;
1719
1720 if (len<1)
1721 continue;
1722
1723 //printf("str %d [%s] p1 [%s] p2 %d [%s] len %d\n", *str, str, p1, *p2, p2, (int)len);
1724
1725 e.name = std::string(p1, len);
1726
1727 if (*p2 == 0)
1728 continue;
1729
1730 str = p2;
1731
1732 // skip leading spaces
1733 while (*str && isspace(*str))
1734 str++;
1735
1736 p1 = str;
1737 p2 = str;
1738
1739 while (*p2 && !isspace(*p2))
1740 p2++;
1741
1742 len = p2-p1;
1743
1744 if (len<1)
1745 continue;
1746
1747 //printf("str %d [%s] p1 [%s] p2 %d [%s] len %d\n", *str, str, p1, *p2, p2, (int)len);
1748
1749 e.directory = std::string(p1, len);
1750
1751 if (*p2 == 0)
1752 continue;
1753
1754 str = p2;
1755
1756 // skip leading spaces
1757 while (*str && isspace(*str))
1758 str++;
1759
1760 p1 = str;
1761 p2 = str;
1762
1763 while (*p2 && !isspace(*p2))
1764 p2++;
1765
1766 len = p2-p1;
1767
1768 //printf("str %d [%s] p1 [%s] p2 %d [%s] len %d\n", *str, str, p1, *p2, p2, (int)len);
1769
1770 e.user = std::string(p1, len);
1771
1772 /* check for trailing directory separator */
1773 if (!ends_with_char(e.directory, DIR_SEPARATOR)) {
1774 e.directory += DIR_SEPARATOR_STR;
1775 }
1776
1777 exptab->exptab.push_back(e);
1778 } while (!feof(f));
1779 fclose(f);
1780 }
1781
1782#if 0
1783 cm_msg(MINFO, "cm_read_exptab", "Read exptab \"%s\":", exptab->filename.c_str());
1784 for (unsigned j=0; j<exptab->exptab.size(); j++) {
1785 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());
1786 }
1787#endif
1788
1789 return CM_SUCCESS;
1790}
#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:1610
std::string name
Definition midas.cxx:1611
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 3861 of file midas.cxx.

3861 {
3862 INT status, size;
3863 char tr_key_name[256];
3864 HNDLE hDB, hKey;
3865
3867
3868 for (int i = 0; _deferred_trans_table[i].transition; i++)
3870 _deferred_trans_table[i].func = (int (*)(int, char *)) func;
3871
3872 /* set new transition mask */
3874
3875 sprintf(tr_key_name, "Transition %s DEFERRED", cm_transition_name(transition).c_str());
3876
3877 /* unlock database */
3879
3880 /* set value */
3881 int i = 0;
3882 status = db_set_value(hDB, hKey, tr_key_name, &i, sizeof(INT), 1, TID_INT32);
3883 if (status != DB_SUCCESS)
3884 return status;
3885
3886 /* re-lock database */
3888
3889 /* hot link requested transition */
3890 size = sizeof(_requested_transition);
3891 db_get_value(hDB, 0, "/Runinfo/Requested Transition", &_requested_transition, &size, TID_INT32, TRUE);
3892 db_find_key(hDB, 0, "/Runinfo/Requested Transition", &hKey);
3893 status = db_open_record(hDB, hKey, &_requested_transition, sizeof(INT), MODE_READ, NULL, NULL);
3894 if (status != DB_SUCCESS) {
3895 cm_msg(MERROR, "cm_register_deferred_transition", "Cannot hotlink /Runinfo/Requested Transition");
3896 return status;
3897 }
3898
3899 return CM_SUCCESS;
3900}
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:13322
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:5028
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 5808 of file midas.cxx.

5828{
5829 HNDLE hDB, hKey;
5830 INT status;
5831 char str[80];
5832
5833 status = rpc_register_function(id, func);
5834 if (status != RPC_SUCCESS)
5835 return status;
5836
5838
5839 /* create new key for this id */
5840 status = 1;
5841 sprintf(str, "RPC/%d", id);
5842
5844 status = db_set_value(hDB, hKey, str, &status, sizeof(BOOL), 1, TID_BOOL);
5846
5847 if (status != DB_SUCCESS)
5848 return status;
5849
5850 return CM_SUCCESS;
5851}
INT rpc_register_function(INT id, INT(*func)(INT, void **))
Definition midas.cxx:12028
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 3476 of file midas.cxx.

3494{
3495 if (!_rpc_registered) {
3496 INT status;
3497 int size;
3498 HNDLE hDB, hKey;
3499 char name[NAME_LENGTH];
3500 char str[256];
3501 int port = 0;
3502
3504
3505 size = sizeof(name);
3506 status = db_get_value(hDB, hKey, "Name", &name, &size, TID_STRING, FALSE);
3507
3508 if (status != DB_SUCCESS) {
3509 cm_msg(MERROR, "cm_register_server", "cannot get client name, db_get_value() status %d", status);
3510 return status;
3511 }
3512
3513 mstrlcpy(str, "/Experiment/Security/RPC ports/", sizeof(str));
3514 mstrlcat(str, name, sizeof(str));
3515
3516 size = sizeof(port);
3517 status = db_get_value(hDB, 0, str, &port, &size, TID_UINT32, TRUE);
3518
3519 if (status != DB_SUCCESS) {
3520 cm_msg(MERROR, "cm_register_server", "cannot get RPC port number, db_get_value(%s) status %d", str, status);
3521 return status;
3522 }
3523
3524 int lport = 0; // actual port number assigned to us by the OS
3525
3527 if (status != RPC_SUCCESS) {
3528 cm_msg(MERROR, "cm_register_server", "error, rpc_register_server(port=%d) status %d", port, status);
3529 return status;
3530 }
3531
3533
3534 /* register MIDAS library functions */
3536
3537 /* store port number in ODB */
3538
3539 status = db_find_key(hDB, hKey, "Server Port", &hKey);
3540 if (status != DB_SUCCESS) {
3541 cm_msg(MERROR, "cm_register_server", "error, db_find_key(\"Server Port\") status %d", status);
3542 return status;
3543 }
3544
3545 /* unlock database */
3547
3548 /* set value */
3549 status = db_set_data(hDB, hKey, &lport, sizeof(INT), 1, TID_INT32);
3550 if (status != DB_SUCCESS) {
3551 cm_msg(MERROR, "cm_register_server", "error, db_set_data(\"Server Port\"=%d) status %d", port, status);
3552 return status;
3553 }
3554
3555 /* lock database */
3557
3559 }
3560
3561 return CM_SUCCESS;
3562}
static void init_rpc_hosts(HNDLE hDB)
Definition midas.cxx:3428
INT db_set_data(HNDLE hDB, HNDLE hKey, const void *data, INT buf_size, INT num_values, DWORD type)
Definition odb.cxx:7239
INT rpc_register_server(int port, int *plsock, int *pport)
Definition midas.cxx:14984
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:3617
INT cm_yield(INT millisec)
Definition midas.cxx:5660
#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 3617 of file midas.cxx.

3617 {
3618 INT status;
3619 HNDLE hDB, hKey, hKeyTrans;
3620 KEY key;
3621 char str[256];
3622
3623 /* check for valid transition */
3625 cm_msg(MERROR, "cm_register_transition", "Invalid transition request \"%d\"", transition);
3626 return CM_INVALID_TRANSITION;
3627 }
3628
3630
3632
3633 /* register new transition request */
3634
3635 {
3636 std::lock_guard<std::mutex> guard(_trans_table_mutex);
3637
3638 for (size_t i = 0; i < _trans_table.size(); i++) {
3639 if (_trans_table[i].transition == transition && _trans_table[i].sequence_number == sequence_number) {
3640 cm_msg(MERROR, "cm_register_transition", "transition %s with sequence number %d is already registered", cm_transition_name(transition).c_str(), sequence_number);
3641 return CM_INVALID_TRANSITION;
3642 }
3643 }
3644
3645 bool found = false;
3646 for (size_t i = 0; i < _trans_table.size(); i++) {
3647 if (!_trans_table[i].transition) {
3648 _trans_table[i].transition = transition;
3649 _trans_table[i].sequence_number = sequence_number;
3650 _trans_table[i].func = func;
3651 found = true;
3652 break;
3653 }
3654 }
3655
3656 if (!found) {
3657 TRANS_TABLE tt;
3659 tt.sequence_number = sequence_number;
3660 tt.func = func;
3661 _trans_table.push_back(tt);
3662 }
3663
3664 // implicit unlock
3665 }
3666
3667 sprintf(str, "Transition %s", cm_transition_name(transition).c_str());
3668
3669 /* unlock database */
3671
3672 /* set value */
3673 status = db_find_key(hDB, hKey, str, &hKeyTrans);
3674 if (!hKeyTrans) {
3675 status = db_set_value(hDB, hKey, str, &sequence_number, sizeof(INT), 1, TID_INT32);
3676 if (status != DB_SUCCESS)
3677 return status;
3678 } else {
3679 status = db_get_key(hDB, hKeyTrans, &key);
3680 if (status != DB_SUCCESS)
3681 return status;
3682 status = db_set_data_index(hDB, hKeyTrans, &sequence_number, sizeof(INT), key.num_values, TID_INT32);
3683 if (status != DB_SUCCESS)
3684 return status;
3685 }
3686
3687 /* re-lock database */
3689
3690 return CM_SUCCESS;
3691}
INT db_set_data_index(HNDLE hDB, HNDLE hKey, const void *data, INT data_size, INT idx, DWORD type)
Definition odb.cxx:7668
#define RPC_RC_TRANSITION
Definition mrpc.h:117
static INT rpc_transition_dispatch(INT idx, void *prpc_param[])
Definition midas.cxx:14504
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 2686 of file midas.cxx.

2686 {
2687 INT status;
2688 STRING_LIST expts;
2689
2690 assert(exp_name != NULL);
2691
2692 /* retrieve list of experiments and make selection */
2694 if (status != CM_SUCCESS)
2695 return status;
2696
2697 if (expts.size() == 1) {
2698 *exp_name = expts[0];
2699 } else if (expts.size() > 1) {
2700 printf("Available experiments on local computer:\n");
2701
2702 for (unsigned i = 0; i < expts.size(); i++) {
2703 printf("%d : %s\n", i, expts[i].c_str());
2704 }
2705
2706 while (1) {
2707 printf("Select number from 0 to %d: ", ((int)expts.size())-1);
2708 char str[32];
2709 ss_gets(str, 32);
2710 int isel = atoi(str);
2711 if (isel < 0)
2712 continue;
2713 if (isel >= (int)expts.size())
2714 continue;
2715 *exp_name = expts[isel];
2716 break;
2717 }
2718 } else {
2719 return CM_UNDEF_EXP;
2720 }
2721
2722 return CM_SUCCESS;
2723}
INT cm_list_experiments_local(STRING_LIST *exp_names)
Definition midas.cxx:2602
char * ss_gets(char *string, int size)
Definition system.cxx:7848
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 2735 of file midas.cxx.

2735 {
2736 INT status;
2737 STRING_LIST expts;
2738
2739 assert(exp_name != NULL);
2740
2741 /* retrieve list of experiments and make selection */
2743 if (status != CM_SUCCESS)
2744 return status;
2745
2746 if (expts.size() > 1) {
2747 printf("Available experiments on server %s:\n", host_name);
2748
2749 for (unsigned i = 0; i < expts.size(); i++) {
2750 printf("%d : %s\n", i, expts[i].c_str());
2751 }
2752
2753 while (1) {
2754 printf("Select number from 0 to %d: ", ((int)expts.size())-1);
2755 char str[32];
2756 ss_gets(str, 32);
2757 int isel = atoi(str);
2758 if (isel < 0)
2759 continue;
2760 if (isel >= (int)expts.size())
2761 continue;
2762 *exp_name = expts[isel];
2763 break;
2764 }
2765 } else {
2766 *exp_name = expts[0];
2767 }
2768
2769 return CM_SUCCESS;
2770}
INT cm_list_experiments_remote(const char *host_name, STRING_LIST *exp_names)
Definition midas.cxx:2628
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,
char *  client_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 1909 of file midas.cxx.

1910 {
1911 if (rpc_is_remote())
1912 return rpc_call(RPC_CM_SET_CLIENT_INFO, hDB, hKeyClient,
1913 host_name, client_name, hw_type, password, watchdog_timeout);
1914
1915#ifdef LOCAL_ROUTINES
1916 {
1917 INT status, pid, data, i, idx, size;
1919 char str[256], name[NAME_LENGTH], orig_name[NAME_LENGTH], pwd[NAME_LENGTH];
1920 BOOL call_watchdog, allow;
1921 PROGRAM_INFO_STR(program_info_str);
1922
1923 /* check security if password is present */
1924 status = db_find_key(hDB, 0, "/Experiment/Security/Password", &hKey);
1925 if (hKey) {
1926 /* get password */
1927 size = sizeof(pwd);
1928 db_get_data(hDB, hKey, pwd, &size, TID_STRING);
1929
1930 /* first check allowed hosts list */
1931 allow = FALSE;
1932 db_find_key(hDB, 0, "/Experiment/Security/Allowed hosts", &hKey);
1934 allow = TRUE;
1935
1936 /* check allowed programs list */
1937 db_find_key(hDB, 0, "/Experiment/Security/Allowed programs", &hKey);
1938 if (hKey && db_find_key(hDB, hKey, client_name, &hKey) == DB_SUCCESS)
1939 allow = TRUE;
1940
1941 /* now check password */
1942 if (!allow && strcmp(password, pwd) != 0) {
1943 if (password[0])
1944 cm_msg(MINFO, "cm_set_client_info", "Wrong password for host %s", host_name);
1945 return CM_WRONG_PASSWORD;
1946 }
1947 }
1948
1949 /* make following operation atomic by locking database */
1951
1952 /* check if entry with this pid exists already */
1953 pid = ss_getpid();
1954
1955 sprintf(str, "System/Clients/%0d", pid);
1956 status = db_find_key(hDB, 0, str, &hKey);
1957 if (status == DB_SUCCESS) {
1960 }
1961
1962 if (strlen(client_name) >= NAME_LENGTH)
1963 client_name[NAME_LENGTH] = 0;
1964
1965 strcpy(name, client_name);
1966 strcpy(orig_name, client_name);
1967
1968 /* check if client name already exists */
1969 status = db_find_key(hDB, 0, "System/Clients", &hKey);
1970
1971 for (idx = 1; status != DB_NO_MORE_SUBKEYS; idx++) {
1972 for (i = 0;; i++) {
1975 break;
1976
1977 if (status == DB_SUCCESS) {
1978 size = sizeof(str);
1979 status = db_get_value(hDB, hSubkey, "Name", str, &size, TID_STRING, FALSE);
1980 if (status != DB_SUCCESS)
1981 continue;
1982 }
1983
1984 /* check if client is living */
1986 continue;
1987
1988 if (equal_ustring(str, name)) {
1989 sprintf(name, "%s%d", client_name, idx);
1990 break;
1991 }
1992 }
1993 }
1994
1995 /* set name */
1996 sprintf(str, "System/Clients/%0d/Name", pid);
1998 if (status != DB_SUCCESS) {
2000 cm_msg(MERROR, "cm_set_client_info", "cannot set client name, db_set_value(%s) status %d", str, status);
2001 return status;
2002 }
2003
2004 /* copy new client name */
2005 strcpy(client_name, name);
2006 db_set_client_name(hDB, client_name);
2007
2008 /* set also as rpc name */
2009 rpc_set_name(client_name);
2010
2011 /* use /system/clients/PID as root */
2012 sprintf(str, "System/Clients/%0d", pid);
2013 db_find_key(hDB, 0, str, &hKey);
2014
2015 /* set host name */
2017 if (status != DB_SUCCESS) {
2019 return status;
2020 }
2021
2022 /* set computer id */
2023 status = db_set_value(hDB, hKey, "Hardware type", &hw_type, sizeof(hw_type), 1, TID_INT32);
2024 if (status != DB_SUCCESS) {
2026 return status;
2027 }
2028
2029 /* set server port */
2030 data = 0;
2031 status = db_set_value(hDB, hKey, "Server Port", &data, sizeof(INT), 1, TID_INT32);
2032 if (status != DB_SUCCESS) {
2034 return status;
2035 }
2036
2037 /* lock client entry */
2039
2040 /* get (set) default watchdog timeout */
2041 size = sizeof(watchdog_timeout);
2042 sprintf(str, "/Programs/%s/Watchdog Timeout", orig_name);
2043 db_get_value(hDB, 0, str, &watchdog_timeout, &size, TID_INT32, TRUE);
2044
2045 /* define /programs entry */
2046 sprintf(str, "/Programs/%s", orig_name);
2047 db_create_record(hDB, 0, str, strcomb1(program_info_str).c_str());
2048
2049 /* save handle for ODB and client */
2051
2052 /* save watchdog timeout */
2053 cm_get_watchdog_params(&call_watchdog, NULL);
2054 cm_set_watchdog_params(call_watchdog, watchdog_timeout);
2055
2056 /* end of atomic operations */
2058
2059 /* touch notify key to inform others */
2060 data = 0;
2061 db_set_value(hDB, 0, "/System/Client Notify", &data, sizeof(data), 1, TID_INT32);
2062
2063 *hKeyClient = hKey;
2064 }
2065#endif /* LOCAL_ROUTINES */
2066
2067 return CM_SUCCESS;
2068}
INT cm_check_client(HNDLE hDB, HNDLE hKeyClient)
Definition midas.cxx:1885
std::string strcomb1(const char **list)
Definition odb.cxx:668
INT db_set_client_name(HNDLE hDB, const char *client_name)
Definition odb.cxx:2440
INT db_create_record(HNDLE hDB, HNDLE hKey, const char *orig_key_name, const char *init_str)
Definition odb.cxx:12831
#define RPC_CM_SET_CLIENT_INFO
Definition mrpc.h:21
void * data
Definition mana.cxx:268
#define PROGRAM_INFO_STR(_name)
Definition midas.h:1447
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 3807 of file midas.cxx.

3807 {
3808 INT status;
3809 HNDLE hDB, hKey;
3810 KEY key;
3811
3813
3814 /* check that hKey is still valid */
3816
3817 if (status != DB_SUCCESS) {
3818 cm_msg(MERROR, "cm_set_client_run_state",
3819 "Cannot set client run state, client hKey %d into /System/Clients is not valid, maybe this client was removed by a watchdog timeout",
3820 hKey);
3821 return status;
3822 }
3823
3824 /* unlock database */
3826
3827 /* set value */
3828 status = db_set_value(hDB, hKey, "Run state", &state, sizeof(INT), 1, TID_INT32);
3829 if (status != DB_SUCCESS)
3830 return status;
3831
3832 /* re-lock database */
3834
3835 return CM_SUCCESS;
3836
3837}
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 2955 of file midas.cxx.

2955 {
2956 //printf("cm_set_experiment_database: hDB %d, hKeyClient %d\n", hDB, hKeyClient);
2957
2958 _hDB = hDB;
2959 _hKeyClient = hKeyClient;
2960
2961 //if (hDB == 0) {
2962 // rpc_set_server_option(RPC_ODB_HANDLE, 0);
2963 //}
2964
2965 return CM_SUCCESS;
2966}
Here is the caller graph for this function:

◆ cm_set_experiment_local()

int cm_set_experiment_local ( const char *  exp_name)

Definition at line 2182 of file midas.cxx.

2183{
2184 std::string exp_name1;
2185
2186 if ((exp_name != NULL) && (strlen(exp_name) > 0)) {
2187 exp_name1 = exp_name;
2188 } else {
2189 int status = cm_select_experiment_local(&exp_name1);
2190 if (status != CM_SUCCESS)
2191 return status;
2192 }
2193
2194 std::string expdir, expuser;
2195
2196 int status = cm_get_exptab(exp_name1.c_str(), &expdir, &expuser);
2197
2198 if (status != CM_SUCCESS) {
2199 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());
2200 return CM_UNDEF_EXP;
2201 }
2202
2203 if (!ss_dir_exist(expdir.c_str())) {
2204 cm_msg(MERROR, "cm_set_experiment_local", "Experiment \"%s\" directory \"%s\" does not exist", exp_name1.c_str(), expdir.c_str());
2205 return CM_UNDEF_EXP;
2206 }
2207
2208 cm_set_experiment_name(exp_name1.c_str());
2209 cm_set_path(expdir.c_str());
2210
2211 return CM_SUCCESS;
2212}
INT cm_set_path(const char *path)
Definition midas.cxx:1513
INT cm_select_experiment_local(std::string *exp_name)
Definition midas.cxx:2686
std::string cm_get_exptab_filename()
Definition midas.cxx:1804
int ss_dir_exist(const char *path)
Definition system.cxx:7264
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 1574 of file midas.cxx.

1574 {
1576 return CM_SUCCESS;
1577}
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 2974 of file midas.cxx.

2994{
2995 _semaphore_alarm = semaphore_alarm;
2996 _semaphore_elog = semaphore_elog;
2997 _semaphore_history = semaphore_history;
2998 //_semaphore_msg = semaphore_msg;
2999
3000 return CM_SUCCESS;
3001}
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 1513 of file midas.cxx.

1513 {
1514 assert(path);
1515 assert(path[0] != 0);
1516
1517 _path_name = path;
1518
1519 if (_path_name.back() != DIR_SEPARATOR) {
1521 }
1522
1523 //printf("cm_set_path [%s]\n", _path_name.c_str());
1524
1525 return CM_SUCCESS;
1526}
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 3747 of file midas.cxx.

3747 {
3748 INT status;
3749 HNDLE hDB, hKey;
3750 char str[256];
3751
3752 /* check for valid transition */
3754 cm_msg(MERROR, "cm_set_transition_sequence", "Invalid transition request \"%d\"", transition);
3755 return CM_INVALID_TRANSITION;
3756 }
3757
3758 {
3759 std::lock_guard<std::mutex> guard(_trans_table_mutex);
3760
3761 int count = 0;
3762 for (size_t i = 0; i < _trans_table.size(); i++) {
3764 _trans_table[i].sequence_number = sequence_number;
3765 count++;
3766 }
3767 }
3768
3769 if (count == 0) {
3770 cm_msg(MERROR, "cm_set_transition_sequence", "transition %s is not registered", cm_transition_name(transition).c_str());
3771 return CM_INVALID_TRANSITION;
3772 } else if (count > 1) {
3773 cm_msg(MERROR, "cm_set_transition_sequence", "cannot change sequence number, transition %s is registered %d times", cm_transition_name(transition).c_str(), count);
3774 return CM_INVALID_TRANSITION;
3775 }
3776
3777 /* Change local sequence number for this transition type */
3778
3779 for (size_t i = 0; i < _trans_table.size(); i++) {
3781 _trans_table[i].sequence_number = sequence_number;
3782 }
3783 }
3784
3785 // implicit unlock
3786 }
3787
3789
3790 /* unlock database */
3792
3793 sprintf(str, "Transition %s", cm_transition_name(transition).c_str());
3794
3795 /* set value */
3796 status = db_set_value(hDB, hKey, str, &sequence_number, sizeof(INT), 1, TID_INT32);
3797 if (status != DB_SUCCESS)
3798 return status;
3799
3800 /* re-lock database */
3802
3803 return CM_SUCCESS;
3804
3805}
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 3299 of file midas.cxx.

3300{
3301 /* set also local timeout to requested value (needed by cm_enable_watchdog()) */
3302 _watchdog_timeout = timeout;
3303
3304 if (rpc_is_remote()) { // we are connected remotely
3305
3306 return rpc_call(RPC_CM_SET_WATCHDOG_PARAMS, call_watchdog, timeout);
3307
3308 } else if (rpc_is_mserver()) { // we are the mserver
3309
3311 if (sa)
3312 sa->watchdog_timeout = timeout;
3313
3314 /* write timeout value to client entry in ODB */
3315 HNDLE hDB, hKey;
3317
3318 if (hDB) {
3320 db_set_value(hDB, hKey, "Link timeout", &timeout, sizeof(timeout), 1, TID_INT32);
3322 }
3323
3324 /* set the watchdog for the local mserver program */
3325 return cm_set_watchdog_params_local(call_watchdog, timeout);
3326
3327 } else { // only running locally
3328
3329 return cm_set_watchdog_params_local(call_watchdog, timeout);
3330
3331 }
3332}
INT cm_set_watchdog_params_local(BOOL call_watchdog, DWORD timeout)
Definition midas.cxx:3260
RPC_SERVER_ACCEPTION * rpc_get_mserver_acception()
Definition midas.cxx:11644
#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 3260 of file midas.cxx.

3261{
3262#ifdef LOCAL_ROUTINES
3263 _watchdog_timeout = timeout;
3264
3265 std::vector<BUFFER*> mybuffers;
3266
3267 gBuffersMutex.lock();
3268 mybuffers = gBuffers;
3269 gBuffersMutex.unlock();
3270
3271 /* set watchdog timeout of all open buffers */
3272 for (BUFFER* pbuf : mybuffers) {
3273
3274 if (!pbuf || !pbuf->attached)
3275 continue;
3276
3277 bm_lock_buffer_guard pbuf_guard(pbuf);
3278
3279 if (!pbuf_guard.is_locked())
3280 continue;
3281
3282 BUFFER_CLIENT *pclient = bm_get_my_client_locked(pbuf_guard);
3283
3284 /* clear entry from client structure in buffer header */
3285 pclient->watchdog_timeout = timeout;
3286
3287 /* show activity */
3288 pclient->last_activity = ss_millitime();
3289 }
3290
3291 /* set watchdog timeout for ODB */
3292 db_set_watchdog_params(timeout);
3293
3294#endif /* LOCAL_ROUTINES */
3295
3296 return CM_SUCCESS;
3297}
void db_set_watchdog_params(DWORD timeout)
Definition odb.cxx:3060
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_shutdown()

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 7411 of file midas.cxx.

7411 {
7412 INT status, return_status, i, size;
7413 HNDLE hDB, hKeyClient, hKey, hSubkey, hKeyTmp, hConn;
7414 KEY key;
7415 char client_name[NAME_LENGTH], remote_host[HOST_NAME_LENGTH];
7416 INT port;
7417 DWORD start_time;
7418 DWORD timeout;
7419 DWORD last;
7420
7421 cm_get_experiment_database(&hDB, &hKeyClient);
7422
7423 status = db_find_key(hDB, 0, "System/Clients", &hKey);
7424 if (status != DB_SUCCESS)
7425 return DB_NO_KEY;
7426
7427 return_status = CM_NO_CLIENT;
7428
7429 /* loop over all clients */
7430 for (i = 0;; i++) {
7433 break;
7434
7435 /* don't shutdown ourselves */
7436 if (hSubkey == hKeyClient)
7437 continue;
7438
7439 if (status == DB_SUCCESS) {
7441
7442 /* contact client */
7443 size = sizeof(client_name);
7444 status = db_get_value(hDB, hSubkey, "Name", client_name, &size, TID_STRING, FALSE);
7445 if (status != DB_SUCCESS)
7446 continue;
7447
7448 if (!bUnique)
7449 client_name[strlen(name)] = 0; /* strip number */
7450
7451 /* check if individual client */
7452 if (!equal_ustring("all", name) && !equal_ustring(client_name, name))
7453 continue;
7454
7455 size = sizeof(port);
7456 db_get_value(hDB, hSubkey, "Server Port", &port, &size, TID_INT32, TRUE);
7457
7458 size = sizeof(remote_host);
7459 db_get_value(hDB, hSubkey, "Host", remote_host, &size, TID_STRING, TRUE);
7460
7461 cm_get_watchdog_info(hDB, name, &timeout, &last);
7462 if (timeout == 0)
7463 timeout = 5000;
7464
7465 /* client found -> connect to its server port */
7466 status = rpc_client_connect(remote_host, port, client_name, &hConn);
7467 if (status != RPC_SUCCESS) {
7468 int client_pid = atoi(key.name);
7469 return_status = CM_NO_CLIENT;
7470 cm_msg(MERROR, "cm_shutdown", "Cannot connect to client \'%s\' on host \'%s\', port %d",
7471 client_name, remote_host, port);
7472#ifdef SIGKILL
7473 cm_msg(MERROR, "cm_shutdown", "Killing and Deleting client \'%s\' pid %d", client_name,
7474 client_pid);
7475 kill(client_pid, SIGKILL);
7476 return_status = CM_SUCCESS;
7477 status = cm_delete_client_info(hDB, client_pid);
7478 if (status != CM_SUCCESS)
7479 cm_msg(MERROR, "cm_shutdown", "Cannot delete client info for client \'%s\', pid %d, status %d",
7480 name, client_pid, status);
7481#endif
7482 } else {
7483 /* call disconnect with shutdown=TRUE */
7485
7486 /* wait until client has shut down */
7487 start_time = ss_millitime();
7488 do {
7489 ss_sleep(100);
7490 status = db_find_key(hDB, hKey, key.name, &hKeyTmp);
7491 } while (status == DB_SUCCESS && (ss_millitime() - start_time < timeout));
7492
7493 if (status == DB_SUCCESS) {
7494 int client_pid = atoi(key.name);
7495 return_status = CM_NO_CLIENT;
7496 cm_msg(MERROR, "cm_shutdown", "Client \'%s\' not responding to shutdown command", client_name);
7497#ifdef SIGKILL
7498 cm_msg(MERROR, "cm_shutdown", "Killing and Deleting client \'%s\' pid %d", client_name,
7499 client_pid);
7500 kill(client_pid, SIGKILL);
7501 status = cm_delete_client_info(hDB, client_pid);
7502 if (status != CM_SUCCESS)
7503 cm_msg(MERROR, "cm_shutdown",
7504 "Cannot delete client info for client \'%s\', pid %d, status %d", name, client_pid,
7505 status);
7506#endif
7507 return_status = CM_NO_CLIENT;
7508 } else {
7509 return_status = CM_SUCCESS;
7510 i--;
7511 }
7512 }
7513 }
7514
7515 /* display any message created during each shutdown */
7517 }
7518
7519 return return_status;
7520}
INT cm_get_watchdog_info(HNDLE hDB, const char *client_name, DWORD *timeout, DWORD *last)
Definition midas.cxx:3360
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 7366 of file midas.cxx.

7366 {
7367 /* watchdog does not run inside remote clients.
7368 * watchdog timeout timers are maintained by the mserver */
7369 if (rpc_is_remote())
7370 return CM_SUCCESS;
7371#ifdef LOCAL_ROUTINES
7372 /* only start once */
7373 if (_watchdog_thread)
7374 return CM_SUCCESS;
7375 _watchdog_thread_run = true;
7376 _watchdog_thread.store(new std::thread(xcm_watchdog_thread));
7377#endif
7378 return CM_SUCCESS;
7379}
static std::atomic< std::thread * > _watchdog_thread
Definition midas.cxx:7334
static void xcm_watchdog_thread()
Definition midas.cxx:7360
static std::atomic< bool > _watchdog_thread_run
Definition midas.cxx:7332
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 7381 of file midas.cxx.

7381 {
7382 /* watchdog does not run inside remote clients.
7383 * watchdog timeout timers are maintained by the mserver */
7384 if (rpc_is_remote())
7385 return CM_SUCCESS;
7386#ifdef LOCAL_ROUTINES
7387 _watchdog_thread_run = false;
7389 //printf("waiting for watchdog thread to shut down\n");
7390 ss_sleep(10);
7391 }
7392 if (_watchdog_thread != NULL) {
7393 _watchdog_thread.load()->join();
7394 delete static_cast<std::thread *>(_watchdog_thread);
7395 _watchdog_thread = NULL;
7396 }
7397#endif
7398 return CM_SUCCESS;
7399}
static std::atomic< bool > _watchdog_thread_is_running
Definition midas.cxx:7333
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 1385 of file midas.cxx.

1385 {
1386 INT sec, status;
1387
1388 /* if connected to server, get time from there */
1389 if (rpc_is_remote()) {
1391
1392 /* set local time */
1393 if (status == CM_SUCCESS)
1394 ss_settime(sec);
1395 }
1396
1397 /* return time to caller */
1398 if (seconds != NULL) {
1399 *seconds = ss_time();
1400 }
1401
1402 return CM_SUCCESS;
1403}
DWORD ss_settime(DWORD seconds)
Definition system.cxx:3547
#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 7768 of file midas.cxx.

7768 {
7769 printf("Test expand_end()\n");
7770 setenv("FOO", "foo", 1);
7771 setenv("BAR", "bar", 1);
7772 setenv("EMPTY", "", 1);
7773 unsetenv("UNDEF");
7774
7775 bool ok = true;
7776
7777 ok &= test_cm_expand_env1("aaa", "aaa");
7778 ok &= test_cm_expand_env1("$FOO", "foo");
7779 ok &= test_cm_expand_env1("/$FOO", "/foo");
7780 ok &= test_cm_expand_env1("/$FOO/", "/foo/");
7781 ok &= test_cm_expand_env1("$FOO/$BAR", "foo/bar");
7782 ok &= test_cm_expand_env1("$FOO1", "$FOO1");
7783 ok &= test_cm_expand_env1("1$FOO", "1foo");
7784 ok &= test_cm_expand_env1("$UNDEF", "$UNDEF");
7785 ok &= test_cm_expand_env1("/$UNDEF/", "/$UNDEF/");
7786
7787 if (ok) {
7788 printf("test_expand_env: all tests passed!\n");
7789 } else {
7790 printf("test_expand_env: test FAILED!\n");
7791 }
7792}
static bool test_cm_expand_env1(const char *str, const char *expected)
Definition midas.cxx:7753
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 1450 of file midas.cxx.

1450 {
1451 /* if connected to server, get time from there */
1452 if (rpc_is_remote())
1453 return rpc_call(RPC_CM_TIME, t);
1454
1455 /* return local time */
1456 *t = ss_time();
1457
1458 return CM_SUCCESS;
1459}
#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 5304 of file midas.cxx.

5304 {
5305 int mflag = async_flag & TR_MTHREAD;
5306 int sflag = async_flag & TR_SYNC;
5307
5309
5310 if (status != CM_SUCCESS) {
5311 cm_msg(MERROR, "cm_transition", "previous transition did not finish yet");
5313 }
5314
5315 /* get key of local client */
5316 HNDLE hDB;
5318
5319 bool deferred = (transition & TR_DEFERRED) > 0;
5320 INT trans_raw = (transition & ~TR_DEFERRED);
5321
5322 /* check for valid transition */
5323 if (trans_raw != TR_START && trans_raw != TR_STOP && trans_raw != TR_PAUSE && trans_raw != TR_RESUME && trans_raw != TR_STARTABORT) {
5324 cm_msg(MERROR, "cm_transition", "Invalid transition request \"%d\"", transition);
5325 if (errstr) {
5326 mstrlcpy(errstr, "Invalid transition request", errstr_size);
5327 }
5328 return CM_INVALID_TRANSITION;
5329 }
5330
5331 /* check if transition in progress */
5332 if (!deferred) {
5333 int i = 0;
5334 int size = sizeof(i);
5335 db_get_value(hDB, 0, "/Runinfo/Transition in progress", &i, &size, TID_INT32, TRUE);
5336 if (i == 1) {
5337 if (errstr) {
5338 sprintf(errstr, "Start/Stop transition %d already in progress, please try again later\n", i);
5339 mstrlcat(errstr, "or set \"/Runinfo/Transition in progress\" manually to zero.\n", errstr_size);
5340 }
5341 cm_msg(MERROR, "cm_transition", "another transition is already in progress");
5343 }
5344 }
5345
5346 if (mflag) {
5349 if (sflag) {
5350 /* in MTHREAD|SYNC mode, we wait until the main thread finishes and it is safe for it to write into errstr */
5351 _trp.errstr = errstr;
5352 _trp.errstr_size = errstr_size;
5353 } else {
5354 /* in normal MTHREAD mode, we return right away and
5355 * if errstr is a local variable in the caller and they return too,
5356 * errstr becomes a stale reference and writing into it will corrupt the stack
5357 * in the mlogger, errstr is a local variable in "start_the_run", "stop_the_run"
5358 * and we definitely corrupt mlogger memory with out this: */
5359 _trp.errstr = NULL;
5360 _trp.errstr_size = 0;
5361 }
5362 _trp.async_flag = async_flag;
5363 _trp.debug_flag = debug_flag;
5364 _trp.status = 0;
5366
5367 if (errstr)
5368 *errstr = 0; // null error string
5369
5370 //ss_thread_create(tr_main_thread, &_trp);
5371
5372 std::thread* t = _trp.thread.exchange(new std::thread(tr_main_thread, &_trp));
5373
5374 assert(t==NULL); // previous thread should have been reaped by cm_transition_cleanup()
5375
5376 if (sflag) {
5377
5378 /* wait until main thread has finished */
5379 do {
5380 ss_sleep(10);
5381 } while (!_trp.finished);
5382
5383 std::thread* t = _trp.thread.exchange(NULL);
5384
5385 if (t) {
5386 t->join();
5387 delete t;
5388 t = NULL;
5389 }
5390
5391 return _trp.status;
5392 }
5393 } else
5394 return cm_transition1(transition, run_number, errstr, errstr_size, async_flag, debug_flag);
5395
5396 return CM_SUCCESS;
5397}
static INT cm_transition1(INT transition, INT run_number, char *errstr, INT errstr_size, INT async_flag, INT debug_flag)
Definition midas.cxx:5256
static INT tr_main_thread(void *param)
Definition midas.cxx:5272
#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 5256 of file midas.cxx.

5256 {
5257 int status;
5258
5259 status = cm_transition2(transition, run_number, errstr, errstr_size, async_flag, debug_flag);
5260
5261 if (transition == TR_START && status != CM_SUCCESS) {
5262 cm_msg(MERROR, "cm_transition", "Could not start a run: cm_transition() status %d, message \'%s\'", status,
5263 errstr);
5264 cm_transition2(TR_STARTABORT, run_number, NULL, 0, async_flag, debug_flag);
5265 }
5266
5267 return status;
5268}
static INT cm_transition2(INT transition, INT run_number, char *errstr, INT errstr_size, INT async_flag, INT debug_flag)
Definition midas.cxx:4547
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 4547 of file midas.cxx.

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

4189 {
4190 INT old_timeout, status, i, t1, t0, size;
4191 HNDLE hDB;
4192 HNDLE hConn = -1;
4193 int connect_timeout = 10000;
4194 int timeout = 120000;
4195
4197 assert(hDB);
4198
4199 TrClient *tr_client = s->clients[idx].get();
4200
4201 tr_client->errorstr = "";
4202 //tr_client->init_time = ss_millitime();
4203 tr_client->waiting_for_client = "";
4204 tr_client->connect_timeout = 0;
4205 tr_client->connect_start_time = 0;
4206 tr_client->connect_end_time = 0;
4207 tr_client->rpc_timeout = 0;
4208 tr_client->rpc_start_time = 0;
4209 tr_client->rpc_end_time = 0;
4210 tr_client->end_time = 0;
4211
4212 write_tr_client_to_odb(hDB, tr_client);
4213
4214 /* wait for predecessor if set */
4215 if (tr_client->async_flag & TR_MTHREAD && !tr_client->wait_for_index.empty()) {
4216 while (1) {
4217 TrClient* wait_for = NULL;
4218
4219 for (size_t i = 0; i < tr_client->wait_for_index.size(); i++) {
4220 int wait_for_index = tr_client->wait_for_index[i];
4221
4222 assert(wait_for_index >= 0);
4223 assert(wait_for_index < (int)s->clients.size());
4224
4225 TrClient *t = s->clients[wait_for_index].get();
4226
4227 if (!t)
4228 continue;
4229
4230 if (t->status == 0) {
4231 wait_for = t;
4232 break;
4233 }
4234
4235 if (t->status != SUCCESS && tr_client->transition != TR_STOP) {
4236 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));
4237 tr_client->status = -1;
4238 tr_client->errorstr = msprintf("Aborted by failure of client \"%s\"", t->client_name.c_str());
4239 tr_client->end_time = ss_millitime();
4240 write_tr_client_to_odb(hDB, tr_client);
4241 return CM_SUCCESS;
4242 }
4243 }
4244
4245 if (wait_for == NULL)
4246 break;
4247
4248 tr_client->waiting_for_client = wait_for->client_name;
4249 write_tr_client_to_odb(hDB, tr_client);
4250
4251 if (tr_client->debug_flag == 1)
4252 printf("Client \"%s\" waits for client \"%s\"\n", tr_client->client_name.c_str(), wait_for->client_name.c_str());
4253
4254 i = 0;
4255 size = sizeof(i);
4256 status = db_get_value(hDB, 0, "/Runinfo/Transition in progress", &i, &size, TID_INT32, FALSE);
4257
4258 if (status == DB_SUCCESS && i == 0) {
4259 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());
4260 tr_client->status = -1;
4261 tr_client->errorstr = "Canceled";
4262 tr_client->end_time = ss_millitime();
4263 write_tr_client_to_odb(hDB, tr_client);
4264 return CM_SUCCESS;
4265 }
4266
4267 ss_sleep(100);
4268 };
4269 }
4270
4271 tr_client->waiting_for_client[0] = 0;
4272
4273 /* contact client if transition mask set */
4274 if (tr_client->debug_flag == 1)
4275 printf("Connecting to client \"%s\" on host %s...\n", tr_client->client_name.c_str(), tr_client->host_name.c_str());
4276 if (tr_client->debug_flag == 2)
4277 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());
4278
4279 /* get transition timeout for rpc connect */
4280 size = sizeof(timeout);
4281 db_get_value(hDB, 0, "/Experiment/Transition connect timeout", &connect_timeout, &size, TID_INT32, TRUE);
4282
4283 if (connect_timeout < 1000)
4284 connect_timeout = 1000;
4285
4286 /* get transition timeout */
4287 size = sizeof(timeout);
4288 db_get_value(hDB, 0, "/Experiment/Transition timeout", &timeout, &size, TID_INT32, TRUE);
4289
4290 if (timeout < 1000)
4291 timeout = 1000;
4292
4293 /* set our timeout for rpc_client_connect() */
4294 //old_timeout = rpc_get_timeout(RPC_HNDLE_CONNECT);
4295 rpc_set_timeout(RPC_HNDLE_CONNECT, connect_timeout, &old_timeout);
4296
4297 tr_client->connect_timeout = connect_timeout;
4298 tr_client->connect_start_time = ss_millitime();
4299
4300 write_tr_client_to_odb(hDB, tr_client);
4301
4302 /* client found -> connect to its server port */
4303 status = rpc_client_connect(tr_client->host_name.c_str(), tr_client->port, tr_client->client_name.c_str(), &hConn);
4304
4305 rpc_set_timeout(RPC_HNDLE_CONNECT, old_timeout);
4306
4307 tr_client->connect_end_time = ss_millitime();
4308 write_tr_client_to_odb(hDB, tr_client);
4309
4310 if (status != RPC_SUCCESS) {
4311 cm_msg(MERROR, "cm_transition_call",
4312 "cannot connect to client \"%s\" on host %s, port %d, status %d",
4313 tr_client->client_name.c_str(), tr_client->host_name.c_str(), tr_client->port, status);
4314 tr_client->errorstr = msprintf("Cannot connect to client \"%s\"", tr_client->client_name.c_str());
4315
4316 /* clients that do not respond to transitions are dead or defective, get rid of them. K.O. */
4317 cm_shutdown(tr_client->client_name.c_str(), TRUE);
4318 cm_cleanup(tr_client->client_name.c_str(), TRUE);
4319
4320 if (tr_client->transition != TR_STOP) {
4321 /* indicate abort */
4322 i = 1;
4323 db_set_value(hDB, 0, "/Runinfo/Start abort", &i, sizeof(INT), 1, TID_INT32);
4324 i = 0;
4325 db_set_value(hDB, 0, "/Runinfo/Transition in progress", &i, sizeof(INT), 1, TID_INT32);
4326 }
4327
4328 tr_client->status = status;
4329 tr_client->end_time = ss_millitime();
4330
4331 write_tr_client_to_odb(hDB, tr_client);
4332 return status;
4333 }
4334
4335 if (tr_client->debug_flag == 1)
4336 printf("Connection established to client \"%s\" on host %s\n", tr_client->client_name.c_str(), tr_client->host_name.c_str());
4337 if (tr_client->debug_flag == 2)
4338 cm_msg(MINFO, "cm_transition_call",
4339 "cm_transition: Connection established to client \"%s\" on host %s",
4340 tr_client->client_name.c_str(), tr_client->host_name.c_str());
4341
4342 /* call RC_TRANSITION on remote client with increased timeout */
4343 //old_timeout = rpc_get_timeout(hConn);
4344 rpc_set_timeout(hConn, timeout, &old_timeout);
4345
4346 tr_client->rpc_timeout = timeout;
4347 tr_client->rpc_start_time = ss_millitime();
4348 write_tr_client_to_odb(hDB, tr_client);
4349
4350 if (tr_client->debug_flag == 1)
4351 printf("Executing RPC transition client \"%s\" on host %s...\n",
4352 tr_client->client_name.c_str(), tr_client->host_name.c_str());
4353 if (tr_client->debug_flag == 2)
4354 cm_msg(MINFO, "cm_transition_call",
4355 "cm_transition: Executing RPC transition client \"%s\" on host %s...",
4356 tr_client->client_name.c_str(), tr_client->host_name.c_str());
4357
4358 t0 = ss_millitime();
4359
4360 char errorstr[TRANSITION_ERROR_STRING_LENGTH];
4361 errorstr[0] = 0;
4362
4363 status = rpc_client_call(hConn, RPC_RC_TRANSITION, tr_client->transition, tr_client->run_number, errorstr, sizeof(errorstr), tr_client->sequence_number);
4364
4365 tr_client->errorstr = errorstr;
4366
4367 t1 = ss_millitime();
4368
4369 tr_client->rpc_end_time = ss_millitime();
4370
4371 write_tr_client_to_odb(hDB, tr_client);
4372
4373 /* fix for clients returning 0 as error code */
4374 if (status == 0)
4375 status = FE_ERR_HW;
4376
4377 /* reset timeout */
4378 rpc_set_timeout(hConn, old_timeout);
4379
4380 //DWORD t2 = ss_millitime();
4381
4382 if (tr_client->debug_flag == 1)
4383 printf("RPC transition finished client \"%s\" on host \"%s\" in %d ms with status %d\n",
4384 tr_client->client_name.c_str(), tr_client->host_name.c_str(), t1 - t0, status);
4385 if (tr_client->debug_flag == 2)
4386 cm_msg(MINFO, "cm_transition_call",
4387 "cm_transition: RPC transition finished client \"%s\" on host \"%s\" in %d ms with status %d",
4388 tr_client->client_name.c_str(), tr_client->host_name.c_str(), t1 - t0, status);
4389
4390 if (status == RPC_NET_ERROR || status == RPC_TIMEOUT) {
4391 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());
4392 /* clients that do not respond to transitions are dead or defective, get rid of them. K.O. */
4393 cm_shutdown(tr_client->client_name.c_str(), TRUE);
4394 cm_cleanup(tr_client->client_name.c_str(), TRUE);
4395 } else if (status != CM_SUCCESS && tr_client->errorstr.empty()) {
4396 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());
4397 }
4398
4399 tr_client->status = status;
4400 tr_client->end_time = ss_millitime();
4401
4402 // write updated status and end_time to ODB
4403
4404 write_tr_client_to_odb(hDB, tr_client);
4405
4406#if 0
4407 printf("hconn %d cm_transition_call(%s) finished init %d connect %d end %d rpc %d end %d xxx %d end %d\n",
4408 hConn,
4409 tr_client->client_name.c_str(),
4410 tr_client->init_time - tr_client->init_time,
4411 tr_client->connect_start_time - tr_client->init_time,
4412 tr_client->connect_end_time - tr_client->init_time,
4413 tr_client->rpc_start_time - tr_client->init_time,
4414 tr_client->rpc_end_time - tr_client->init_time,
4415 t2 - tr_client->init_time,
4416 tr_client->end_time - tr_client->init_time);
4417#endif
4418
4419 return CM_SUCCESS;
4420}
INT cm_cleanup(const char *client_name, BOOL ignore_timeout)
Definition midas.cxx:7621
#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:13926
INT rpc_set_timeout(HNDLE hConn, int timeout_msec, int *old_timeout_msec)
Definition midas.cxx:13129
DWORD connect_timeout
Definition midas.cxx:3969
int transition
Definition midas.cxx:3954
DWORD connect_end_time
Definition midas.cxx:3971
std::atomic_int status
Definition midas.cxx:3964
std::vector< int > wait_for_index
Definition midas.cxx:3959
DWORD rpc_end_time
Definition midas.cxx:3974
std::string waiting_for_client
Definition midas.cxx:3968
DWORD rpc_timeout
Definition midas.cxx:3972
int async_flag
Definition midas.cxx:3956
DWORD rpc_start_time
Definition midas.cxx:3973
int debug_flag
Definition midas.cxx:3957
int run_number
Definition midas.cxx:3955
DWORD end_time
Definition midas.cxx:3975
DWORD connect_start_time
Definition midas.cxx:3970
std::string errorstr
Definition midas.cxx:3966
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 4424 of file midas.cxx.

4425{
4426 HNDLE hDB;
4427
4429
4430 DWORD now = ss_millitime();
4431
4432 tr_client->errorstr = "";
4433 //tr_client->init_time = now;
4434 tr_client->waiting_for_client = "";
4435 tr_client->connect_timeout = 0;
4436 tr_client->connect_start_time = now;
4437 tr_client->connect_end_time = now;
4438 tr_client->rpc_timeout = 0;
4439 tr_client->rpc_start_time = 0;
4440 tr_client->rpc_end_time = 0;
4441 tr_client->end_time = 0;
4442
4443 write_tr_client_to_odb(hDB, tr_client);
4444
4445 // find registered handler
4446 // NB: this code should match same code in rpc_transition_dispatch()
4447 // NB: only use the first handler, this is how MIDAS always worked
4448 // NB: we could run all handlers, but we can return the status and error string of only one of them.
4449
4450 _trans_table_mutex.lock();
4451 size_t n = _trans_table.size();
4452 _trans_table_mutex.unlock();
4453
4454 for (size_t i = 0; i < n; i++) {
4455 _trans_table_mutex.lock();
4457 _trans_table_mutex.unlock();
4458 if (tt.transition == tr_client->transition && tt.sequence_number == tr_client->sequence_number) {
4459 /* call registered function */
4460 if (tt.func) {
4461 if (tr_client->debug_flag == 1)
4462 printf("Calling local transition callback\n");
4463 if (tr_client->debug_flag == 2)
4464 cm_msg(MINFO, "cm_transition_call_direct", "cm_transition: Calling local transition callback");
4465
4466 tr_client->rpc_start_time = ss_millitime();
4467
4468 write_tr_client_to_odb(hDB, tr_client);
4469
4470 char errorstr[TRANSITION_ERROR_STRING_LENGTH];
4471 errorstr[0] = 0;
4472
4473 tr_client->status = tt.func(tr_client->run_number, errorstr);
4474
4475 tr_client->errorstr = errorstr;
4476
4477 tr_client->rpc_end_time = ss_millitime();
4478
4479 if (tr_client->debug_flag == 1)
4480 printf("Local transition callback finished, status %d\n", int(tr_client->status));
4481 if (tr_client->debug_flag == 2)
4482 cm_msg(MINFO, "cm_transition_call_direct", "cm_transition: Local transition callback finished, status %d", int(tr_client->status));
4483
4484 tr_client->end_time = ss_millitime();
4485
4486 // write status and end_time to ODB
4487
4488 write_tr_client_to_odb(hDB, tr_client);
4489
4490 return tr_client->status;
4491 }
4492 }
4493 }
4494
4495 cm_msg(MERROR, "cm_transition_call_direct", "no handler for transition %d with sequence number %d", tr_client->transition, tr_client->sequence_number);
4496
4497 tr_client->status = CM_SUCCESS;
4498 tr_client->end_time = ss_millitime();
4499
4500 // write status and end_time to ODB
4501
4502 write_tr_client_to_odb(hDB, tr_client);
4503
4504 return CM_SUCCESS;
4505}
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 5285 of file midas.cxx.

5286{
5287 if (_trp.thread && !_trp.finished) {
5288 //printf("main transition thread did not finish yet!\n");
5290 }
5291
5292 std::thread* t = _trp.thread.exchange(NULL);
5293
5294 if (t) {
5295 t->join();
5296 delete t;
5297 t = NULL;
5298 }
5299
5300 return CM_SUCCESS;
5301}
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 4106 of file midas.cxx.

4106 {
4107 HNDLE hDB;
4108 int status;
4109 const char *args[100];
4110 std::string path;
4111 char debug_arg[256];
4112 char start_arg[256];
4113 std::string expt_name;
4114 std::string mserver_hostname;
4115
4116 int iarg = 0;
4117
4119
4120 const char *midassys = getenv("MIDASSYS");
4121 if (midassys) {
4122 path += midassys;
4123 path += DIR_SEPARATOR_STR;
4124 path += "bin";
4125 path += DIR_SEPARATOR_STR;
4126 }
4127 path += "mtransition";
4128
4129 args[iarg++] = path.c_str();
4130
4131 if (rpc_is_remote()) {
4132 /* if connected to mserver, pass connection info to mtransition */
4133 mserver_hostname = rpc_get_mserver_hostname();
4134 args[iarg++] = "-h";
4135 args[iarg++] = mserver_hostname.c_str();
4136 }
4137
4138 /* get experiment name from ODB */
4139 db_get_value_string(hDB, 0, "/Experiment/Name", 0, &expt_name, FALSE);
4140
4141 if (expt_name.length() > 0) {
4142 args[iarg++] = "-e";
4143 args[iarg++] = expt_name.c_str();
4144 }
4145
4146 if (debug_flag) {
4147 args[iarg++] = "-d";
4148
4149 sprintf(debug_arg, "%d", debug_flag);
4150 args[iarg++] = debug_arg;
4151 }
4152
4153 if (transition == TR_STOP)
4154 args[iarg++] = "STOP";
4155 else if (transition == TR_PAUSE)
4156 args[iarg++] = "PAUSE";
4157 else if (transition == TR_RESUME)
4158 args[iarg++] = "RESUME";
4159 else if (transition == TR_START) {
4160 args[iarg++] = "START";
4161
4162 sprintf(start_arg, "%d", run_number);
4163 args[iarg++] = start_arg;
4164 }
4165
4166 args[iarg++] = NULL;
4167
4168#if 0
4169 for (iarg = 0; args[iarg] != NULL; iarg++) {
4170 printf("arg[%d] [%s]\n", iarg, args[iarg]);
4171 }
4172#endif
4173
4174 status = ss_spawnv(P_DETACH, args[0], args);
4175
4176 if (status != SS_SUCCESS) {
4177 if (errstr != NULL) {
4178 sprintf(errstr, "Cannot execute mtransition, ss_spawnv() returned %d", status);
4179 }
4180 return CM_SET_ERROR;
4181 }
4182
4183 return CM_SUCCESS;
4184}
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:12936
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 7340 of file midas.cxx.

7340 {
7342 //printf("cm_watchdog_thread started!\n");
7343 while (_watchdog_thread_run) {
7344 //printf("cm_watchdog_thread runs!\n");
7345 DWORD now = ss_millitime();
7348 int i;
7349 for (i = 0; i < 20; i++) {
7350 ss_sleep(100);
7352 break;
7353 }
7354 }
7355 //printf("cm_watchdog_thread stopped!\n");
7357 return 0;
7358}
static void bm_update_last_activity(DWORD millitime)
Definition midas.cxx:6135
INT db_update_last_activity(DWORD millitime)
Definition odb.cxx:2776
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 5660 of file midas.cxx.

5660 {
5661 INT status;
5662 INT bMore;
5663 //static DWORD last_yield = 0;
5664 //static DWORD last_yield_time = 0;
5665 //DWORD start_yield = ss_millitime();
5666
5667 /* check for ctrl-c */
5668 if (_ctrlc_pressed)
5669 return RPC_SHUTDOWN;
5670
5671 /* flush the cm_msg buffer */
5673
5674 if (!rpc_is_remote()) {
5675 /* flush the ODB to its binary file */
5676 /* for remote clients, ODB is flushed by the mserver */
5677 HNDLE hDB;
5680 }
5681
5682 /* check for available events */
5683 if (rpc_is_remote()) {
5684 //printf("cm_yield() calling bm_poll_event()\n");
5686
5687 if (status == SS_ABORT) {
5688 return status;
5689 }
5690
5691 if (status == BM_SUCCESS) {
5692 /* one or more events received by bm_poll_event() */
5693 status = ss_suspend(0, 0);
5694 } else {
5695 status = ss_suspend(millisec, 0);
5696 }
5697
5698 return status;
5699 }
5700
5702
5703 if (status != CM_SUCCESS)
5704 return status;
5705
5706 //DWORD start_check = ss_millitime();
5707
5708 bMore = bm_check_buffers();
5709
5710 //DWORD end_check = ss_millitime();
5711 //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);
5712 //fflush(stdout);
5713
5714 if (bMore == BM_CORRUPTED) {
5715 status = SS_ABORT;
5716 } else if (bMore) {
5717 /* if events available, quickly check other IPC channels */
5718 status = ss_suspend(0, 0);
5719 } else {
5720 status = ss_suspend(millisec, 0);
5721 }
5722
5723 /* flush the cm_msg buffer */
5725
5726 //DWORD end_yield = ss_millitime();
5727 //last_yield_time = end_yield - start_yield;
5728 //last_yield = start_yield;
5729
5730 return status;
5731}
INT bm_poll_event()
Definition midas.cxx:11265
INT bm_check_buffers()
Definition midas.cxx:11093
INT cm_periodic_tasks()
Definition midas.cxx:5597
#define BM_CORRUPTED
Definition midas.h:623
INT ss_suspend(INT millisec, INT msg)
Definition system.cxx:4615
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 3428 of file midas.cxx.

3428 {
3429 int status;
3430 char buf[256];
3431 int size, i;
3432 HNDLE hKey;
3433
3434 strcpy(buf, "localhost");
3435 size = sizeof(buf);
3436
3437 status = db_get_value(hDB, 0, "/Experiment/Security/RPC hosts/Allowed hosts[0]", buf, &size, TID_STRING, TRUE);
3438
3439 if (status != DB_SUCCESS) {
3440 cm_msg(MERROR, "init_rpc_hosts", "Cannot create the RPC hosts access control list, db_get_value() status %d",
3441 status);
3442 return;
3443 }
3444
3445 size = sizeof(i);
3446 i = 0;
3447 status = db_get_value(hDB, 0, "/Experiment/Security/Disable RPC hosts check", &i, &size, TID_BOOL, TRUE);
3448
3449 if (status != DB_SUCCESS) {
3450 cm_msg(MERROR, "init_rpc_hosts", "Cannot create \"Disable RPC hosts check\", db_get_value() status %d", status);
3451 return;
3452 }
3453
3454 if (i != 0) // RPC hosts check is disabled
3455 return;
3456
3457 status = db_find_key(hDB, 0, "/Experiment/Security/RPC hosts/Allowed hosts", &hKey);
3458
3459 if (status != DB_SUCCESS || hKey == 0) {
3460 cm_msg(MERROR, "init_rpc_hosts", "Cannot find the RPC hosts access control list, db_find_key() status %d",
3461 status);
3462 return;
3463 }
3464
3465 load_rpc_hosts(hDB, hKey, -99, NULL);
3466
3468
3469 if (status != DB_SUCCESS) {
3470 cm_msg(MERROR, "init_rpc_hosts", "Cannot watch the RPC hosts access control list, db_watch() status %d", status);
3471 return;
3472 }
3473}
static void load_rpc_hosts(HNDLE hDB, HNDLE hKey, int index, void *info)
Definition midas.cxx:3377
INT db_watch(HNDLE hDB, HNDLE hKey, void(*dispatcher)(INT, INT, INT, void *), void *info)
Definition odb.cxx:13845
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 3377 of file midas.cxx.

3377 {
3378 int status;
3379 int i, last;
3380 KEY key;
3381 int max_size;
3382 char *str;
3383
3384// if (index != -99)
3385// cm_msg(MINFO, "load_rpc_hosts", "Reloading RPC hosts access control list via hotlink callback");
3386
3388
3389 if (status != DB_SUCCESS)
3390 return;
3391
3392 //printf("clear rpc hosts!\n");
3394
3395 max_size = key.item_size;
3396 str = (char *) malloc(max_size);
3397
3398 last = 0;
3399 for (i = 0; i < key.num_values; i++) {
3400 int size = max_size;
3402 if (status != DB_SUCCESS)
3403 break;
3404
3405 if (strlen(str) < 1) // skip emties
3406 continue;
3407
3408 if (str[0] == '#') // skip commented-out entries
3409 continue;
3410
3411 //printf("add rpc hosts %d [%s]\n", i, str);
3413 last = i;
3414 }
3415
3416 if (key.num_values - last < 10) {
3417 int new_size = last + 10;
3418 status = db_set_num_values(hDB, hKey, new_size);
3419 if (status != DB_SUCCESS) {
3420 cm_msg(MERROR, "load_rpc_hosts",
3421 "Cannot resize the RPC hosts access control list, db_set_num_values(%d) status %d", new_size, status);
3422 }
3423 }
3424
3425 free(str);
3426}
INT db_set_num_values(HNDLE hDB, HNDLE hKey, INT num_values)
Definition odb.cxx:7523
INT rpc_add_allowed_host(const char *hostname)
Definition midas.cxx:16594
INT rpc_clear_allowed_hosts()
Definition midas.cxx:16569
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 12763 of file midas.cxx.

12764{
12765 /* close all open connections */
12766
12768
12769 for (unsigned i = 0; i < _client_connections.size(); i++) {
12771 if (c && c->connected) {
12772 int index = c->index;
12773 // must unlock the array, otherwise we hang -
12774 // rpc_client_disconnect() will do rpc_call_client()
12775 // which needs to lock the array to convert handle
12776 // to connection pointer. Ouch! K.O. Dec 2020.
12780 }
12781 }
12782
12783 for (unsigned i = 0; i < _client_connections.size(); i++) {
12785 //printf("client connection %d %p\n", i, c);
12786 if (c) {
12787 //printf("client connection %d %p connected %d\n", i, c, c->connected);
12788 if (!c->connected) {
12789 delete c;
12790 _client_connections[i] = NULL;
12791 }
12792 }
12793 }
12794
12796
12797 /* close server connection from other clients */
12798 for (unsigned i = 0; i < _server_acceptions.size(); i++) {
12799 if (_server_acceptions[i] && _server_acceptions[i]->recv_sock) {
12800 send(_server_acceptions[i]->recv_sock, "EXIT", 5, 0);
12801 _server_acceptions[i]->close();
12802 }
12803 }
12804}
static std::mutex _client_connections_mutex
Definition midas.cxx:11634
static std::vector< RPC_CLIENT_CONNECTION * > _client_connections
Definition midas.cxx:11635
static std::vector< RPC_SERVER_ACCEPTION * > _server_acceptions
Definition midas.cxx:11641
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 7753 of file midas.cxx.

7753 {
7754 std::string s = cm_expand_env(str);
7755 printf("test_expand_env: [%s] -> [%s] expected [%s]",
7756 str,
7757 s.c_str(),
7758 expected);
7759 if (s != expected) {
7760 printf(", MISMATCH!\n");
7761 return false;
7762 }
7763
7764 printf("\n");
7765 return true;
7766}
std::string cm_expand_env(const char *str)
Definition midas.cxx:7721
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 4000 of file midas.cxx.

4000 {
4001 return arg1->sequence_number < arg2->sequence_number;
4002}
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 4020 of file midas.cxx.

4021{
4022 DWORD end_time = ss_millitime();
4023
4024 if (transition != TR_STARTABORT) {
4025 db_set_value(hDB, 0, "/System/Transition/end_time", &end_time, sizeof(DWORD), 1, TID_UINT32);
4026 db_set_value(hDB, 0, "/System/Transition/status", &status, sizeof(INT), 1, TID_INT32);
4027
4028 if (errorstr) {
4029 db_set_value(hDB, 0, "/System/Transition/error", errorstr, strlen(errorstr) + 1, 1, TID_STRING);
4030 } else if (status == CM_SUCCESS) {
4031 const char *buf = "Success";
4032 db_set_value(hDB, 0, "/System/Transition/error", buf, strlen(buf) + 1, 1, TID_STRING);
4033 } else {
4034 char buf[256];
4035 sprintf(buf, "status %d", status);
4036 db_set_value(hDB, 0, "/System/Transition/error", buf, strlen(buf) + 1, 1, TID_STRING);
4037 }
4038 }
4039
4040 tr->status = status;
4041 tr->end_time = end_time;
4042 if (errorstr) {
4043 tr->errorstr = errorstr;
4044 } else {
4045 tr->errorstr = "(null)";
4046 }
4047
4048 return status;
4049}
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 5272 of file midas.cxx.

5272 {
5273 INT status;
5274 TR_PARAM *trp;
5275
5276 trp = (TR_PARAM *) param;
5277 status = cm_transition1(trp->transition, trp->run_number, trp->errstr, trp->errstr_size, trp->async_flag, trp->debug_flag);
5278
5279 trp->status = status;
5280 trp->finished = TRUE;
5281
5282 return 0;
5283}
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 4053 of file midas.cxx.

4053 {
4054 //printf("Writing client [%s] to ODB\n", tr_client->client_name.c_str());
4055
4056 int status;
4057 HNDLE hKey;
4058
4059 if (tr_client->transition == TR_STARTABORT) {
4060 status = db_create_key(hDB, 0, "/System/Transition/TR_STARTABORT", TID_KEY);
4061 status = db_find_key(hDB, 0, "/System/Transition/TR_STARTABORT", &hKey);
4062 if (status != DB_SUCCESS)
4063 return;
4064 } else {
4065 status = db_create_key(hDB, 0, "/System/Transition/Clients", TID_KEY);
4066 status = db_find_key(hDB, 0, "/System/Transition/Clients", &hKey);
4067 if (status != DB_SUCCESS)
4068 return;
4069 }
4070
4071 // same client_name can exist with different sequence numbers!
4072 std::string keyname = msprintf("%s_%d", tr_client->client_name.c_str(), tr_client->sequence_number);
4073
4074 status = db_create_key(hDB, hKey, keyname.c_str(), TID_KEY);
4075 status = db_find_key(hDB, hKey, keyname.c_str(), &hKey);
4076 if (status != DB_SUCCESS)
4077 return;
4078
4079 DWORD now = ss_millitime();
4080
4081 //int transition;
4082 //int run_number;
4083 //int async_flag;
4084 //int debug_flag;
4085 status = db_set_value(hDB, hKey, "sequence_number", &tr_client->sequence_number, sizeof(INT), 1, TID_INT32);
4086 status = db_set_value(hDB, hKey, "client_name", tr_client->client_name.c_str(), tr_client->client_name.length() + 1, 1, TID_STRING);
4087 status = db_set_value(hDB, hKey, "host_name", tr_client->host_name.c_str(), tr_client->host_name.length() + 1, 1, TID_STRING);
4088 status = db_set_value(hDB, hKey, "port", &tr_client->port, sizeof(INT), 1, TID_INT32);
4089 status = db_set_value(hDB, hKey, "init_time", &tr_client->init_time, sizeof(DWORD), 1, TID_UINT32);
4090 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);
4091 status = db_set_value(hDB, hKey, "connect_timeout", &tr_client->connect_timeout, sizeof(DWORD), 1, TID_UINT32);
4092 status = db_set_value(hDB, hKey, "connect_start_time", &tr_client->connect_start_time, sizeof(DWORD), 1, TID_UINT32);
4093 status = db_set_value(hDB, hKey, "connect_end_time", &tr_client->connect_end_time, sizeof(DWORD), 1, TID_UINT32);
4094 status = db_set_value(hDB, hKey, "rpc_timeout", &tr_client->rpc_timeout, sizeof(DWORD), 1, TID_UINT32);
4095 status = db_set_value(hDB, hKey, "rpc_start_time", &tr_client->rpc_start_time, sizeof(DWORD), 1, TID_UINT32);
4096 status = db_set_value(hDB, hKey, "rpc_end_time", &tr_client->rpc_end_time, sizeof(DWORD), 1, TID_UINT32);
4097 status = db_set_value(hDB, hKey, "end_time", &tr_client->end_time, sizeof(DWORD), 1, TID_UINT32);
4098 status = db_set_value(hDB, hKey, "status", &tr_client->status, sizeof(INT), 1, TID_INT32);
4099 status = db_set_value(hDB, hKey, "error", tr_client->errorstr.c_str(), tr_client->errorstr.length() + 1, 1, TID_STRING);
4100 status = db_set_value(hDB, hKey, "last_updated", &now, sizeof(DWORD), 1, TID_UINT32);
4101}
INT db_create_key(HNDLE hDB, HNDLE hKey, const char *key_name, DWORD type)
Definition odb.cxx:3392
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 7986 of file midas.cxx.

7987{
7988 int status;
7989
7990 // NB: locking order: 1st buffer mutex, 2nd buffer semaphore. Unlock in reverse order.
7991
7992 //if (pbuf->locked) {
7993 // fprintf(stderr, "double lock, abort!\n");
7994 // abort();
7995 //}
7996
7998
7999 if (status != BM_SUCCESS)
8000 return status;
8001
8002 status = ss_semaphore_wait_for(pbuf->semaphore, 1000);
8003
8004 if (status != SS_SUCCESS) {
8005 fprintf(stderr, "bm_lock_buffer: Lock buffer \"%s\" is taking longer than 1 second!\n", pbuf->buffer_name);
8006
8007 status = ss_semaphore_wait_for(pbuf->semaphore, 10000);
8008
8009 if (status != SS_SUCCESS) {
8010 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);
8011
8012 if (pbuf->buffer_header) {
8013 for (int i=0; i<MAX_CLIENTS; i++) {
8014 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);
8015 }
8016 }
8017
8019
8020 if (status != SS_SUCCESS) {
8021 fprintf(stderr, "bm_lock_buffer: Error: Cannot lock buffer \"%s\", ss_semaphore_wait_for() status %d, aborting...\n", pbuf->buffer_name, status);
8022 cm_msg(MERROR, "bm_lock_buffer", "Cannot lock buffer \"%s\", ss_semaphore_wait_for() status %d, aborting...", pbuf->buffer_name, status);
8023 abort();
8024 /* DOES NOT RETURN */
8025 }
8026 }
8027 }
8028
8029 // protect against double lock
8030 assert(!pbuf->locked);
8031 pbuf->locked = TRUE;
8032
8033#if 0
8034 int x = MAX_CLIENTS - 1;
8035 if (pbuf->buffer_header->client[x].unused1 != 0) {
8036 printf("lllock [%s] unused1 %d pid %d\n", pbuf->buffer_name, pbuf->buffer_header->client[x].unused1, getpid());
8037 }
8038 //assert(pbuf->buffer_header->client[x].unused1 == 0);
8039 pbuf->buffer_header->client[x].unused1 = getpid();
8040#endif
8041
8042 pbuf->count_lock++;
8043
8044 return BM_SUCCESS;
8045}
static int _bm_lock_timeout
Definition midas.cxx:5937
static int bm_lock_buffer_mutex(BUFFER *pbuf)
Definition midas.cxx:7957
INT ss_semaphore_wait_for(HNDLE semaphore_handle, DWORD timeout_millisec)
Definition system.cxx:2711
#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 8048 of file midas.cxx.

8048 {
8049 // NB: locking order: 1st buffer mutex, 2nd buffer semaphore. Unlock in reverse order.
8050
8051#if 0
8052 int x = MAX_CLIENTS-1;
8053 if (pbuf->attached) {
8054 if (pbuf->buffer_header->client[x].unused1 != getpid()) {
8055 printf("unlock [%s] unused1 %d pid %d\n", pbuf->buffer_header->name, pbuf->buffer_header->client[x].unused1, getpid());
8056 }
8057 pbuf->buffer_header->client[x].unused1 = 0;
8058 } else {
8059 printf("unlock [??????] unused1 ????? pid %d\n", getpid());
8060 }
8061#endif
8062
8063 // protect against double unlock
8064 assert(pbuf->locked);
8065 pbuf->locked = FALSE;
8066
8068 pbuf->buffer_mutex.unlock();
8069}
INT ss_semaphore_release(HNDLE semaphore_handle)
Definition system.cxx:2853
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 7360 of file midas.cxx.

7360 {
7361 cm_watchdog_thread(NULL);
7362}
INT cm_watchdog_thread(void *unused)
Definition midas.cxx:7340
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 5457 of file midas.cxx.

◆ _deferred_transition_mask

DWORD _deferred_transition_mask
static

Definition at line 3843 of file midas.cxx.

◆ _exptab

exptab_struct _exptab
static

Definition at line 1621 of file midas.cxx.

◆ _requested_transition

INT _requested_transition
static

dox

Definition at line 3842 of file midas.cxx.

◆ _watchdog_thread

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

Definition at line 7334 of file midas.cxx.

7334{NULL};

◆ _watchdog_thread_is_running

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

Definition at line 7333 of file midas.cxx.

7333{false}; // set by watchdog thread

◆ _watchdog_thread_run

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

Definition at line 7332 of file midas.cxx.

7332{false}; // set by main thread