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 charcm_get_version ()
 
const charcm_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 6174 of file midas.cxx.

6175{
6176#ifdef LOCAL_ROUTINES
6177
6178 //printf("bm_cleanup: called by %s, actual_time %d, wrong_interval %d\n", who, actual_time, wrong_interval);
6179
6180 std::vector<BUFFER*> mybuffers;
6181
6182 gBuffersMutex.lock();
6184 gBuffersMutex.unlock();
6185
6186 /* check buffers */
6187 for (BUFFER* pbuf : mybuffers) {
6188 if (!pbuf)
6189 continue;
6190 if (pbuf->attached) {
6191 /* update the last_activity entry to show that we are alive */
6192
6194
6195 if (!pbuf_guard.is_locked())
6196 continue;
6197
6199 pclient->last_activity = actual_time;
6200
6201 /* don't check other clients if interval is strange */
6202 if (!wrong_interval)
6204 }
6205 }
6206#endif // LOCAL_ROUTINES
6207}
static void bm_cleanup_buffer_locked(BUFFER *pbuf, const char *who, DWORD actual_time)
Definition midas.cxx:6088
static BUFFER_CLIENT * bm_get_my_client_locked(bm_lock_buffer_guard &pbuf_guard)
Definition midas.cxx:6021
DWORD actual_time
Definition mfe.cxx:37
static std::mutex gBuffersMutex
Definition midas.cxx:195
static std::vector< BUFFER * > gBuffers
Definition midas.cxx:196
TH1X EXPRT * h1_book(const char *name, const char *title, int bins, double min, double max)
Definition rmidas.h:24
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 11306 of file midas.cxx.

11332{
11333 INT i;
11334
11335 if ((uint16_t(pevent->event_id) & uint16_t(0xF000)) == uint16_t(EVENTID_FRAG1)) {
11336 /*---- start new event ----*/
11337
11338 //printf("First Frag detected : Ser#:%d ID=0x%x \n", pevent->serial_number, pevent->event_id);
11339
11340 /* check if fragments already stored */
11341 for (i = 0; i < MAX_DEFRAG_EVENTS; i++)
11342 if (defrag_buffer[i].event_id == (pevent->event_id & 0x0FFF))
11343 break;
11344
11345 if (i < MAX_DEFRAG_EVENTS) {
11346 free(defrag_buffer[i].pevent);
11349 cm_msg(MERROR, "bm_defragement_event",
11350 "Received new event with ID %d while old fragments were not completed",
11351 (pevent->event_id & 0x0FFF));
11352 }
11353
11354 /* search new slot */
11355 for (i = 0; i < MAX_DEFRAG_EVENTS; i++)
11356 if (defrag_buffer[i].event_id == 0)
11357 break;
11358
11359 if (i == MAX_DEFRAG_EVENTS) {
11360 cm_msg(MERROR, "bm_defragment_event",
11361 "Not enough defragment buffers, please increase MAX_DEFRAG_EVENTS and recompile");
11362 return;
11363 }
11364
11365 /* check event size */
11366 if (pevent->data_size != sizeof(DWORD)) {
11367 cm_msg(MERROR, "bm_defragment_event",
11368 "Received first event fragment with %d bytes instead of %d bytes, event ignored",
11369 pevent->data_size, (int) sizeof(DWORD));
11370 return;
11371 }
11372
11373 /* setup defragment buffer */
11374 defrag_buffer[i].event_id = (pevent->event_id & 0x0FFF);
11378
11379 if (defrag_buffer[i].pevent == NULL) {
11381 cm_msg(MERROR, "bm_defragement_event", "Not enough memory to allocate event defragment buffer");
11382 return;
11383 }
11384
11385 memcpy(defrag_buffer[i].pevent, pevent, sizeof(EVENT_HEADER));
11388
11389 // printf("First frag[%d] (ID %d) Ser#:%d sz:%d\n", i, defrag_buffer[i].event_id,
11390 // pevent->serial_number, defrag_buffer[i].data_size);
11391
11392 return;
11393 }
11394
11395 /* search buffer for that event */
11396 for (i = 0; i < MAX_DEFRAG_EVENTS; i++)
11397 if (defrag_buffer[i].event_id == (pevent->event_id & 0xFFF))
11398 break;
11399
11400 if (i == MAX_DEFRAG_EVENTS) {
11401 /* no buffer available -> no first fragment received */
11402 cm_msg(MERROR, "bm_defragement_event",
11403 "Received fragment without first fragment (ID %d) Ser#:%d",
11404 pevent->event_id & 0x0FFF, pevent->serial_number);
11405 return;
11406 }
11407
11408 /* add fragment to buffer */
11410 free(defrag_buffer[i].pevent);
11413 cm_msg(MERROR, "bm_defragement_event",
11414 "Received fragments with more data (%d) than event size (%d)",
11416 return;
11417 }
11418
11419 memcpy(((char *) defrag_buffer[i].pevent) + sizeof(EVENT_HEADER) +
11420 defrag_buffer[i].received, pdata, pevent->data_size);
11421
11422 defrag_buffer[i].received += pevent->data_size;
11423
11424 //printf("Other frag[%d][%d] (ID %d) Ser#:%d sz:%d\n", i, j++,
11425 // defrag_buffer[i].event_id, pevent->serial_number, pevent->data_size);
11426
11427 if (defrag_buffer[i].received == defrag_buffer[i].data_size) {
11428 /* event complete */
11429 dispatcher(buffer_handle, request_id, defrag_buffer[i].pevent, defrag_buffer[i].pevent + 1);
11430 free(defrag_buffer[i].pevent);
11433 }
11434}
#define MAX_DEFRAG_EVENTS
Definition midas.cxx:11294
static EVENT_DEFRAG_BUFFER defrag_buffer[MAX_DEFRAG_EVENTS]
Definition midas.cxx:11303
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:929
INT i
Definition mdump.cxx:32
int INT
Definition midas.h:129
#define EVENTID_FRAG1
Definition midas.h:906
#define event_id
EVENT_HEADER * pevent
Definition midas.cxx:11300
short int event_id
Definition midas.h:852
DWORD data_size
Definition midas.h:856
DWORD serial_number
Definition midas.h:854
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 6644 of file midas.cxx.

6645{
6646 size_t sbuffer_handle = buffer_handle;
6647
6648 size_t nbuf = 0;
6649 BUFFER* pbuf = NULL;
6650
6651 gBuffersMutex.lock();
6652
6653 nbuf = gBuffers.size();
6654 if (buffer_handle >=1 && sbuffer_handle <= nbuf) {
6655 pbuf = gBuffers[buffer_handle-1];
6656 }
6657
6658 gBuffersMutex.unlock();
6659
6660 if (sbuffer_handle > nbuf || buffer_handle <= 0) {
6661 if (who)
6662 cm_msg(MERROR, who, "invalid buffer handle %d: out of range [1..%d]", buffer_handle, (int)nbuf);
6663 if (pstatus)
6665 return NULL;
6666 }
6667
6668 if (!pbuf) {
6669 if (who)
6670 cm_msg(MERROR, who, "invalid buffer handle %d: empty slot", buffer_handle);
6671 if (pstatus)
6673 return NULL;
6674 }
6675
6676 if (!pbuf->attached) {
6677 if (who)
6678 cm_msg(MERROR, who, "invalid buffer handle %d: not attached", buffer_handle);
6679 if (pstatus)
6681 return NULL;
6682 }
6683
6684 if (pstatus)
6686
6687 return pbuf;
6688}
#define BM_INVALID_HANDLE
Definition midas.h:609
#define BM_SUCCESS
Definition midas.h:605
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 6021 of file midas.cxx.

6021 {
6023 return pbuf_guard.get_pbuf()->buffer_header->client + my_client_index;
6024}
static int bm_validate_client_index_locked(bm_lock_buffer_guard &pbuf_guard)
Definition midas.cxx:5944
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 7968 of file midas.cxx.

7969{
7970 //printf("bm_lock_buffer_mutex %s!\n", pbuf->buffer_name);
7971
7972 bool locked = ss_timed_mutex_wait_for_sec(pbuf->buffer_mutex, "buffer mutex", _bm_mutex_timeout_sec);
7973
7974 if (!locked) {
7975 fprintf(stderr, "bm_lock_buffer_mutex: Error: Cannot lock buffer \"%s\", ss_timed_mutex_wait_for_sec() timeout, aborting...\n", pbuf->buffer_name);
7976 cm_msg(MERROR, "bm_lock_buffer_mutex", "Cannot lock buffer \"%s\", ss_timed_mutex_wait_for_sec() timeout, aborting...", pbuf->buffer_name);
7977 abort();
7978 /* DOES NOT RETURN */
7979 }
7980
7981 if (!pbuf->attached) {
7982 pbuf->buffer_mutex.unlock();
7983 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);
7984 return BM_INVALID_HANDLE;
7985 }
7986
7987 //static int counter = 0;
7988 //counter++;
7989 //printf("locked %d!\n", counter);
7990 //if (counter > 50)
7991 // ::sleep(3);
7992
7993 return BM_SUCCESS;
7994}
static double _bm_mutex_timeout_sec
Definition midas.cxx:5942
bool ss_timed_mutex_wait_for_sec(std::timed_mutex &mutex, const char *mutex_name, double timeout_sec)
Definition system.cxx:3337
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 7926 of file midas.cxx.

7927{
7928 bool locked = ss_timed_mutex_wait_for_sec(pbuf->read_cache_mutex, "buffer read cache", _bm_mutex_timeout_sec);
7929
7930 if (!locked) {
7931 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);
7932 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);
7933 abort();
7934 /* DOES NOT RETURN */
7935 }
7936
7937 if (!pbuf->attached) {
7938 pbuf->read_cache_mutex.unlock();
7939 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);
7940 return BM_INVALID_HANDLE;
7941 }
7942
7943 return BM_SUCCESS;
7944}
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 7947 of file midas.cxx.

7948{
7949 bool locked = ss_timed_mutex_wait_for_sec(pbuf->write_cache_mutex, "buffer write cache", _bm_mutex_timeout_sec);
7950
7951 if (!locked) {
7952 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);
7953 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);
7954 abort();
7955 /* DOES NOT RETURN */
7956 }
7957
7958 if (!pbuf->attached) {
7959 pbuf->write_cache_mutex.unlock();
7960 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);
7961 return BM_INVALID_HANDLE;
7962 }
7963
7964 return BM_SUCCESS;
7965}
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 11070 of file midas.cxx.

11090{
11091 static DWORD last_time = 0;
11093
11094 //printf("bm_notify_client: buffer [%s], socket %d, time %d\n", buffer_name, client_socket, now - last_time);
11095
11096 BUFFER* fbuf = NULL;
11097
11098 gBuffersMutex.lock();
11099
11100 for (size_t i = 0; i < gBuffers.size(); i++) {
11101 BUFFER* pbuf = gBuffers[i];
11102 if (!pbuf || !pbuf->attached)
11103 continue;
11104 if (strcmp(buffer_name, pbuf->buffer_header->name) == 0) {
11105 fbuf = pbuf;
11106 break;
11107 }
11108 }
11109
11110 gBuffersMutex.unlock();
11111
11112 if (!fbuf)
11113 return BM_INVALID_HANDLE;
11114
11115 /* don't send notification if client has no callback defined
11116 to receive events -> client calls bm_receive_event manually */
11117 if (!fbuf->callback)
11118 return DB_SUCCESS;
11119
11120 int convert_flags = rpc_get_convert_flags();
11121
11122 /* only send notification once each 500ms */
11123 if (now - last_time < 500)
11124 return DB_SUCCESS;
11125
11126 last_time = now;
11127
11128 char buffer[32];
11129 NET_COMMAND *nc = (NET_COMMAND *) buffer;
11130
11131 nc->header.routine_id = MSG_BM;
11132 nc->header.param_size = 0;
11133
11134 if (convert_flags) {
11137 }
11138
11139 //printf("bm_notify_client: Sending MSG_BM! buffer [%s]\n", buffer_name);
11140
11141 /* send the update notification to the client */
11142 send_tcp(client_socket, (char *) buffer, sizeof(NET_COMMAND_HEADER), 0);
11143
11144 return BM_SUCCESS;
11145}
#define DB_SUCCESS
Definition midas.h:631
#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:13052
void rpc_convert_single(void *data, INT tid, INT flags, INT convert_flags)
Definition midas.cxx:11703
DWORD last_time
Definition mana.cxx:3070
char buffer_name[NAME_LENGTH]
Definition mevb.cxx:45
#define RPC_OUTGOING
Definition midas.h:1583
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 10940 of file midas.cxx.

10941{
10942 std::vector<BUFFER*> mybuffers;
10943
10944 gBuffersMutex.lock();
10946 gBuffersMutex.unlock();
10947
10948 for (size_t i = 0; i < mybuffers.size(); i++) {
10949 BUFFER *pbuf = mybuffers[i];
10950 if (!pbuf || !pbuf->attached)
10951 continue;
10952 // FIXME: unlocked read access to pbuf->buffer_name!
10953 if (strcmp(buffer_name, pbuf->buffer_name) == 0) {
10954 return bm_push_buffer(pbuf, i + 1);
10955 }
10956 }
10957
10958 return BM_INVALID_HANDLE;
10959}
static INT bm_push_buffer(BUFFER *pbuf, int buffer_handle)
Definition midas.cxx:10924
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 5478 of file midas.cxx.

5478 {
5480}
#define FALSE
Definition cfortran.h:309
static BOOL _ctrlc_pressed
Definition midas.cxx:5461
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 1426 of file midas.cxx.

1426 {
1427 /* if connected to server, get time from there */
1428 if (rpc_is_remote()) {
1429 char buf[256];
1430 int status = rpc_call(RPC_CM_ASCTIME, buf, sizeof(buf));
1431 if (status == CM_SUCCESS) {
1432 return buf;
1433 } else {
1434 return "";
1435 }
1436 }
1437
1438 /* return local time */
1439 return ss_asctime();
1440}
#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:12783
INT rpc_call(DWORD routine_id,...)
Definition midas.cxx:13685
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 1410 of file midas.cxx.

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

1883 {
1884 if (rpc_is_remote())
1886
1887#ifdef LOCAL_ROUTINES
1889#endif /*LOCAL_ROUTINES */
1890 return CM_SUCCESS;
1891}
INT db_check_client(HNDLE hDB, HNDLE hKeyClient)
Definition odb.cxx:3064
#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 2215 of file midas.cxx.

2215 {
2216 if (_hKeyClient) {
2217 cm_msg(MERROR, "cm_check_connect", "cm_disconnect_experiment not called at end of program");
2219 }
2220}
INT cm_msg_flush_buffer()
Definition midas.cxx:879
static HNDLE _hKeyClient
Definition midas.cxx:1470
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 3911 of file midas.cxx.

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

7632 {
7633 if (rpc_is_remote())
7634 return rpc_call(RPC_CM_CLEANUP, client_name);
7635
7636#ifdef LOCAL_ROUTINES
7637 {
7640
7641 std::vector<BUFFER*> mybuffers;
7642
7643 gBuffersMutex.lock();
7645 gBuffersMutex.unlock();
7646
7647 /* check buffers */
7648 for (BUFFER* pbuf : mybuffers) {
7649 if (!pbuf)
7650 continue;
7651 if (pbuf->attached) {
7652 std::string msg;
7653
7655
7656 if (!pbuf_guard.is_locked())
7657 continue;
7658
7659 /* update the last_activity entry to show that we are alive */
7660 BUFFER_HEADER *pheader = pbuf->buffer_header;
7662 pclient->last_activity = ss_millitime();
7663
7664 /* now check other clients */
7665 for (int j = 0; j < pheader->max_client_index; j++) {
7666 BUFFER_CLIENT *pbclient = &pheader->client[j];
7667 if (j != pbuf->client_index && pbclient->pid &&
7668 (client_name == NULL || client_name[0] == 0
7669 || strncmp(pbclient->name, client_name, strlen(client_name)) == 0)) {
7670 if (ignore_timeout)
7672 else
7674
7675 /* If client process has no activity, clear its buffer entry. */
7676 if (interval > 0
7677 && now > pbclient->last_activity && now - pbclient->last_activity > interval) {
7678
7679 /* now make again the check with the buffer locked */
7680 if (interval > 0
7681 && now > pbclient->last_activity && now - pbclient->last_activity > interval) {
7682 msg = msprintf(
7683 "Client \'%s\' on \'%s\' removed by cm_cleanup (idle %1.1lfs, timeout %1.0lfs)",
7684 pbclient->name, pheader->name,
7685 (ss_millitime() - pbclient->last_activity) / 1000.0,
7686 interval / 1000.0);
7687
7688 bm_remove_client_locked(pheader, j);
7689 }
7690
7691 /* go again through whole list */
7692 j = 0;
7693 }
7694 }
7695 }
7696
7697 // unlock buffer before calling cm_msg(), if we are SYSMSG, we will deadlock.
7698 pbuf_guard.unlock();
7699
7700 /* display info message after unlocking buffer */
7701 if (!msg.empty())
7702 cm_msg(MINFO, "cm_cleanup", "%s", msg.c_str());
7703 }
7704 }
7705
7706 db_cleanup2(client_name, ignore_timeout, now, "cm_cleanup");
7707 }
7708#endif /* LOCAL_ROUTINES */
7709
7710 return CM_SUCCESS;
7711}
void bm_remove_client_locked(BUFFER_HEADER *pheader, int j)
Definition midas.cxx:6057
#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:2902
#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:951
char name[NAME_LENGTH]
Definition midas.h:958
INT max_client_index
Definition midas.h:960
BUFFER_CLIENT client[MAX_CLIENTS]
Definition midas.h:967
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 2780 of file midas.cxx.

2780 {
2782 INT status, i, length, port;
2784
2785 /* find client entry in ODB */
2787
2788 status = db_find_key(hDB, 0, "System/Clients", &hKeyRoot);
2789 if (status != DB_SUCCESS)
2790 return status;
2791
2792 i = 0;
2793 do {
2794 /* search for client with specific name */
2797 return CM_NO_CLIENT;
2798
2799 status = db_find_key(hDB, hSubkey, "Name", &hKey);
2800 if (status != DB_SUCCESS)
2801 return status;
2802
2805 if (status != DB_SUCCESS)
2806 return status;
2807
2808 if (equal_ustring(name, client_name)) {
2809 status = db_find_key(hDB, hSubkey, "Server Port", &hKey);
2810 if (status != DB_SUCCESS)
2811 return status;
2812
2813 length = sizeof(INT);
2814 status = db_get_data(hDB, hKey, &port, &length, TID_INT32);
2815 if (status != DB_SUCCESS)
2816 return status;
2817
2818 status = db_find_key(hDB, hSubkey, "Host", &hKey);
2819 if (status != DB_SUCCESS)
2820 return status;
2821
2822 length = sizeof(host_name);
2824 if (status != DB_SUCCESS)
2825 return status;
2826
2827 /* client found -> connect to its server port */
2828 return rpc_client_connect(host_name, port, client_name, hConn);
2829 }
2830
2831
2832 } while (TRUE);
2833}
INT cm_get_experiment_database(HNDLE *hDB, HNDLE *hKeyClient)
Definition midas.cxx:3025
#define CM_NO_CLIENT
Definition midas.h:584
#define DB_NO_MORE_SUBKEYS
Definition midas.h:646
#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:3206
INT db_get_data(HNDLE hDB, HNDLE hKey, void *data, INT *buf_size, DWORD type)
Definition odb.cxx:6544
INT db_find_key(HNDLE hDB, HNDLE hKey, const char *key_name, HNDLE *subhKey)
Definition odb.cxx:4084
INT db_enum_key(HNDLE hDB, HNDLE hKey, INT idx, HNDLE *subkey_handle)
Definition odb.cxx:5591
INT rpc_client_connect(const char *host_name, INT port, const char *client_name, HNDLE *hConnection)
Definition midas.cxx:12034
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:2292
INT cm_disconnect_experiment(void)
Definition midas.cxx:2860
INT cm_get_environment(char *host_name, int host_name_size, char *exp_name, int exp_name_size)
Definition midas.cxx:2148
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 2292 of file midas.cxx.

2292 {
2293 INT status;
2294
2297 if (status != CM_SUCCESS) {
2298 std::string s = cm_get_error(status);
2299 puts(s.c_str());
2300 }
2301
2302 return status;
2303}
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:2311
std::string cm_get_error(INT code)
Definition midas.cxx:467
#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 2311 of file midas.cxx.

2312 {
2313 INT status, size;
2315 char password[NAME_LENGTH], str[256];
2316 HNDLE hDB = 0, hKeyClient = 0;
2318
2319 ss_tzset(); // required for localtime_r()
2320
2321 if (_hKeyClient)
2323
2325
2326 //cm_msg(MERROR, "cm_connect_experiment", "test cm_msg before connecting to experiment");
2327 //cm_msg_flush_buffer();
2328
2329 rpc_set_name(client_name);
2330
2331 /* check for local host */
2332 if (equal_ustring(host_name, "local"))
2333 host_name = NULL;
2334
2335#ifdef OS_WINNT
2336 {
2338
2339 /* Start windows sockets */
2340 if (WSAStartup(MAKEWORD(1, 1), &WSAData) != 0)
2341 return RPC_NET_ERROR;
2342 }
2343#endif
2344
2345 std::string default_exp_name1;
2346 if (default_exp_name)
2348
2349 /* connect to MIDAS server */
2350 if (host_name && host_name[0]) {
2351 if (default_exp_name1.length() == 0) {
2353 if (status != CM_SUCCESS)
2354 return status;
2355 }
2356
2358
2360 if (status != RPC_SUCCESS)
2361 return status;
2362
2363 /* register MIDAS library functions */
2365 if (status != RPC_SUCCESS)
2366 return status;
2367 } else {
2368 /* lookup path for *SHM files and save it */
2369
2370#ifdef LOCAL_ROUTINES
2372 if (status != CM_SUCCESS)
2373 return status;
2374
2376
2378
2380
2381 /* create alarm and elog semaphores */
2383 if (status != SS_CREATED && status != SS_SUCCESS) {
2384 cm_msg(MERROR, "cm_connect_experiment", "Cannot create alarm semaphore");
2385 return status;
2386 }
2388 if (status != SS_CREATED && status != SS_SUCCESS) {
2389 cm_msg(MERROR, "cm_connect_experiment", "Cannot create elog semaphore");
2390 return status;
2391 }
2393 if (status != SS_CREATED && status != SS_SUCCESS) {
2394 cm_msg(MERROR, "cm_connect_experiment", "Cannot create history semaphore");
2395 return status;
2396 }
2398 if (status != SS_CREATED && status != SS_SUCCESS) {
2399 cm_msg(MERROR, "cm_connect_experiment", "Cannot create message semaphore");
2400 return status;
2401 }
2402
2404#else
2405 return CM_UNDEF_EXP;
2406#endif
2407 }
2408
2409 //cm_msg(MERROR, "cm_connect_experiment", "test cm_msg before open ODB");
2410 //cm_msg_flush_buffer();
2411
2412 /* open ODB */
2413 if (odb_size == 0)
2415
2416 status = db_open_database("ODB", odb_size, &hDB, client_name);
2417 if (status != DB_SUCCESS && status != DB_CREATED) {
2418 cm_msg(MERROR, "cm_connect_experiment1", "cannot open database, db_open_database() status %d", status);
2419 return status;
2420 }
2421
2422 //cm_msg(MERROR, "cm_connect_experiment", "test cm_msg after open ODB");
2423 //cm_msg_flush_buffer();
2424
2426 size = sizeof(odb_timeout);
2427 status = db_get_value(hDB, 0, "/Experiment/ODB timeout", &odb_timeout, &size, TID_INT32, TRUE);
2428 if (status != DB_SUCCESS) {
2429 cm_msg(MERROR, "cm_connect_experiment1", "cannot get ODB /Experiment/ODB timeout, status %d", status);
2430 }
2431
2432 if (odb_timeout > 0) {
2434 }
2435
2437 size = sizeof(protect_odb);
2438 status = db_get_value(hDB, 0, "/Experiment/Protect ODB", &protect_odb, &size, TID_BOOL, TRUE);
2439 if (status != DB_SUCCESS) {
2440 cm_msg(MERROR, "cm_connect_experiment1", "cannot get ODB /Experiment/Protect ODB, status %d", status);
2441 }
2442
2443 if (protect_odb) {
2445 }
2446
2448 size = sizeof(enable_core_dumps);
2449 status = db_get_value(hDB, 0, "/Experiment/Enable core dumps", &enable_core_dumps, &size, TID_BOOL, TRUE);
2450 if (status != DB_SUCCESS) {
2451 cm_msg(MERROR, "cm_connect_experiment1", "cannot get ODB /Experiment/Enable core dumps, status %d", status);
2452 }
2453
2454 if (enable_core_dumps) {
2455#ifdef RLIMIT_CORE
2456 struct rlimit limit;
2457 limit.rlim_cur = RLIM_INFINITY;
2458 limit.rlim_max = RLIM_INFINITY;
2460 if (status != 0) {
2461 cm_msg(MERROR, "cm_connect_experiment", "Cannot setrlimit(RLIMIT_CORE, RLIM_INFINITY), errno %d (%s)", errno,
2462 strerror(errno));
2463 }
2464#else
2465#warning setrlimit(RLIMIT_CORE) is not available
2466#endif
2467 }
2468
2469 size = sizeof(disable_bind_rpc_to_localhost);
2470 status = db_get_value(hDB, 0, "/Experiment/Security/Enable non-localhost RPC", &disable_bind_rpc_to_localhost, &size,
2471 TID_BOOL, TRUE);
2472 if (status != DB_SUCCESS) {
2473 cm_msg(MERROR, "cm_connect_experiment1",
2474 "cannot get ODB /Experiment/Security/Enable non-localhost RPC, status %d", status);
2475 }
2476
2477 std::string local_host_name;
2478
2479 /* now setup client info */
2481 local_host_name = "localhost";
2482 else
2484
2485 /* check watchdog timeout */
2486 if (watchdog_timeout == 0)
2487 watchdog_timeout = DEFAULT_WATCHDOG_TIMEOUT;
2488
2489 strcpy(client_name1, client_name);
2490 password[0] = 0;
2491 status = cm_set_client_info(hDB, &hKeyClient, local_host_name.c_str(), client_name1, rpc_get_hw_type(), password, watchdog_timeout);
2492
2493 if (status == CM_WRONG_PASSWORD) {
2494 if (func == NULL)
2495 strcpy(str, ss_getpass("Password: "));
2496 else
2497 func(str);
2498
2499 strcpy(password, ss_crypt(str, "mi"));
2500 status = cm_set_client_info(hDB, &hKeyClient, local_host_name.c_str(), client_name1, rpc_get_hw_type(), password, watchdog_timeout);
2501 if (status != CM_SUCCESS) {
2502 /* disconnect */
2503 if (rpc_is_remote())
2506
2507 return status;
2508 }
2509 }
2510
2511 //cm_msg(MERROR, "cm_connect_experiment", "test cm_msg after set client info");
2512 //cm_msg_flush_buffer();
2513
2514 /* tell the rest of MIDAS that ODB is open for business */
2515
2517
2518 //cm_msg(MERROR, "cm_connect_experiment", "test cm_msg after set experiment database");
2519 //cm_msg_flush_buffer();
2520
2521 /* cm_msg_open_buffer() calls bm_open_buffer() calls ODB function
2522 * to get event buffer size, etc */
2523
2525 if (status != CM_SUCCESS) {
2526 cm_msg(MERROR, "cm_connect_experiment1", "cannot open message buffer, cm_msg_open_buffer() status %d", status);
2527 return status;
2528 }
2529
2530 //cm_msg(MERROR, "cm_connect_experiment", "test cm_msg after message system is ready");
2531 //cm_msg_flush_buffer();
2532
2533 /* set experiment name in ODB if not present */
2534 std::string current_name;
2535 db_get_value_string(hDB, 0, "/Experiment/Name", 0, &current_name, TRUE);
2536 if (current_name.length() == 0 || current_name == "Default") {
2537 db_set_value_string(hDB, 0, "/Experiment/Name", &default_exp_name1);
2538 }
2539
2540 if (!rpc_is_remote()) {
2541 /* experiment path is only set for local connections */
2542 /* set data dir in ODB */
2543 std::string path = cm_get_path();
2544 db_get_value_string(hDB, 0, "/Logger/Data dir", 0, &path, TRUE);
2545 }
2546
2547 /* register server to be able to be called by other clients */
2549 if (status != CM_SUCCESS) {
2550 cm_msg(MERROR, "cm_connect_experiment", "Cannot register RPC server, cm_register_server() status %d", status);
2551 if (!equal_ustring(client_name, "odbedit")) {
2552 return status;
2553 }
2554 }
2555
2556 /* set watchdog timeout */
2557 cm_get_watchdog_params(&call_watchdog, &watchdog_timeout);
2558 size = sizeof(watchdog_timeout);
2559 sprintf(str, "/Programs/%s/Watchdog Timeout", client_name);
2560 db_get_value(hDB, 0, str, &watchdog_timeout, &size, TID_INT32, TRUE);
2561 cm_set_watchdog_params(call_watchdog, watchdog_timeout);
2562
2563 /* set command line */
2564 std::string cmdline = ss_get_cmdline();
2565 std::string path = "/Programs/" + std::string(client_name);
2566 midas::odb prog(path);
2567 if (!midas::odb::exists(path + "/Start command") ||
2568 prog["Start command"] == std::string(""))
2569 prog["Start command"].set_string_size(cmdline, 256);
2570
2571 /* get final client name */
2572 std::string xclient_name = rpc_get_name();
2573
2574 /* startup message is not displayed */
2575 cm_msg(MLOG, "cm_connect_experiment", "Program %s on host %s started", xclient_name.c_str(), local_host_name.c_str());
2576
2577 /* enable system and user messages to stdout as default */
2579
2580 /* call cm_check_connect when exiting */
2581 atexit((void (*)(void)) cm_check_connect);
2582
2583 /* register ctrl-c handler */
2585
2586 //cm_msg(MERROR, "cm_connect_experiment", "test cm_msg after connect to experiment is complete");
2587 //cm_msg_flush_buffer();
2588
2589 return CM_SUCCESS;
2590}
static bool exists(const std::string &name)
Definition odbxx.cxx:75
INT cm_get_watchdog_params(BOOL *call_watchdog, DWORD *timeout)
Definition midas.cxx:3339
INT cm_select_experiment_remote(const char *host_name, std::string *exp_name)
Definition midas.cxx:2733
INT cm_register_server(void)
Definition midas.cxx:3474
void cm_check_connect(void)
Definition midas.cxx:2215
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:1907
std::string cm_get_path()
Definition midas.cxx:1551
int cm_set_experiment_local(const char *exp_name)
Definition midas.cxx:2180
std::string cm_get_experiment_name()
Definition midas.cxx:1594
INT cm_set_experiment_database(HNDLE hDB, HNDLE hKeyClient)
Definition midas.cxx:2953
void cm_ctrlc_handler(int sig)
Definition midas.cxx:5463
INT cm_set_watchdog_params(BOOL call_watchdog, DWORD timeout)
Definition midas.cxx:3297
INT cm_set_experiment_semaphore(INT semaphore_alarm, INT semaphore_elog, INT semaphore_history, INT semaphore_msg)
Definition midas.cxx:2972
INT cm_set_experiment_name(const char *name)
Definition midas.cxx:1572
#define CM_UNDEF_EXP
Definition midas.h:586
#define CM_WRONG_PASSWORD
Definition midas.h:589
#define DB_CREATED
Definition midas.h:632
#define SS_SUCCESS
Definition midas.h:663
#define SS_CREATED
Definition midas.h:664
#define RPC_SUCCESS
Definition midas.h:698
#define RPC_NET_ERROR
Definition midas.h:701
#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:716
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:479
int cm_msg_open_buffer(void)
Definition midas.cxx:486
INT cm_set_msg_print(INT system_mask, INT user_mask, int(*func)(const char *))
Definition midas.cxx:659
INT db_get_value(HNDLE hDB, HNDLE hKeyRoot, const char *key_name, void *data, INT *buf_size, DWORD type, BOOL create)
Definition odb.cxx:5420
INT db_open_database(const char *xdatabase_name, INT database_size, HNDLE *hDB, const char *client_name)
Definition odb.cxx:1789
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:13945
INT EXPRT db_set_value_string(HNDLE hDB, HNDLE hKeyRoot, const char *key_name, const std::string *s)
Definition odb.cxx:14016
INT db_set_lock_timeout(HNDLE hDB, int timeout_millisec)
Definition odb.cxx:2669
INT db_protect_database(HNDLE hDB)
Definition odb.cxx:3172
INT rpc_register_functions(const RPC_LIST *new_list, RPC_HANDLER func)
Definition midas.cxx:11849
INT rpc_server_connect(const char *host_name, const char *exp_name)
Definition midas.cxx:12403
std::string rpc_get_name()
Definition midas.cxx:13106
INT rpc_get_hw_type()
Definition midas.cxx:12856
INT rpc_server_disconnect()
Definition midas.cxx:12727
INT rpc_set_name(const char *name)
Definition midas.cxx:13130
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 5463 of file midas.cxx.

5463 {
5464 if (_ctrlc_pressed) {
5465 printf("Received 2nd Ctrl-C, hard abort\n");
5466 exit(0);
5467 }
5468 printf("Received Ctrl-C, aborting...\n");
5470
5472}
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 1866 of file midas.cxx.

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

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

2847 {
2849}
INT rpc_client_disconnect(HNDLE hConn, BOOL bShutdown)
Definition midas.cxx:12698
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 2860 of file midas.cxx.

2860 {
2861 HNDLE hDB, hKey;
2862
2863 //cm_msg(MERROR, "cm_disconnect_experiment", "test cm_msg before disconnect from experiment");
2864 //cm_msg_flush_buffer();
2865
2866 /* wait on any transition thread */
2867 if (_trp.transition && !_trp.finished) {
2868 printf("Waiting for transition to finish...\n");
2869 do {
2870 ss_sleep(10);
2871 } while (!_trp.finished);
2872 }
2873
2874 /* stop the watchdog thread */
2876
2877 /* send shutdown notification */
2878 std::string client_name = rpc_get_name();
2879
2880 std::string local_host_name;
2881
2883 local_host_name = "localhost";
2884 else {
2886 //if (strchr(local_host_name, '.'))
2887 // *strchr(local_host_name, '.') = 0;
2888 }
2889
2890 /* disconnect message not displayed */
2891 cm_msg(MLOG, "cm_disconnect_experiment", "Program %s on host %s stopped", client_name.c_str(), local_host_name.c_str());
2893
2894 if (rpc_is_remote()) {
2895 if (rpc_is_connected()) {
2896 /* close open records */
2898
2900 }
2901
2904
2906 } else {
2908
2909 /* delete client info */
2911
2912 if (hDB)
2914
2915 //cm_msg(MERROR, "cm_disconnect_experiment", "test cm_msg before close all buffers, close all databases");
2916 //cm_msg_flush_buffer();
2917
2921
2923
2924 //cm_msg(MERROR, "cm_disconnect_experiment", "test cm_msg after close all buffers, close all databases");
2925 //cm_msg_flush_buffer();
2926 }
2927
2928 if (!rpc_is_mserver())
2930
2931 /* free RPC list */
2933
2934 //cm_msg(MERROR, "cm_disconnect_experiment", "test cm_msg before deleting the message ring buffer");
2935 //cm_msg_flush_buffer();
2936
2937 /* last flush before we delete the message ring buffer */
2939
2940 //cm_msg(MERROR, "cm_disconnect_experiment", "test cm_msg after disconnect is completed");
2941 //cm_msg_flush_buffer();
2942
2943 return CM_SUCCESS;
2944}
INT bm_close_all_buffers(void)
Definition midas.cxx:7265
INT cm_stop_watchdog_thread()
Definition midas.cxx:7392
static void rpc_client_shutdown()
Definition midas.cxx:12654
INT cm_delete_client_info(HNDLE hDB, INT pid)
Definition midas.cxx:1866
INT ss_sleep(INT millisec)
Definition system.cxx:3700
int cm_msg_close_buffer(void)
Definition midas.cxx:499
INT db_close_all_records()
Definition odb.cxx:13524
INT db_close_all_databases(void)
Definition odb.cxx:2365
INT rpc_deregister_functions()
Definition midas.cxx:11892
bool rpc_is_connected(void)
Definition midas.cxx:12805
INT rpc_server_shutdown(void)
Definition midas.cxx:16205
bool rpc_is_mserver(void)
Definition midas.cxx:12840
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 5407 of file midas.cxx.

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

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

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

7542 {
7543 INT status, i, size;
7545 char client_name[NAME_LENGTH];
7546
7547 if (rpc_is_remote())
7549
7551
7552 status = db_find_key(hDB, 0, "System/Clients", &hKey);
7553 if (status != DB_SUCCESS)
7554 return DB_NO_KEY;
7555
7557
7558 /* loop over all clients */
7559 for (i = 0;; i++) {
7562 break;
7563
7564 if (hSubkey == hKeyClient)
7565 continue;
7566
7567 if (status == DB_SUCCESS) {
7568 /* get client name */
7569 size = sizeof(client_name);
7570 status = db_get_value(hDB, hSubkey, "Name", client_name, &size, TID_STRING, FALSE);
7571
7572 if (status != DB_SUCCESS) {
7573 //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);
7574 continue;
7575 }
7576
7577 if (equal_ustring(client_name, name)) {
7579 return CM_SUCCESS;
7580 }
7581
7582 if (!bUnique) {
7583 client_name[strlen(name)] = 0; /* strip number */
7584 if (equal_ustring(client_name, name)) {
7586 return CM_SUCCESS;
7587 }
7588 }
7589 }
7590 }
7591
7593
7594 return CM_NO_CLIENT;
7595}
#define DB_NO_KEY
Definition midas.h:642
INT db_lock_database(HNDLE hDB)
Definition odb.cxx:2460
INT db_unlock_database(HNDLE hDB)
Definition odb.cxx:2582
#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 7732 of file midas.cxx.

7732 {
7733 const char *s = str;
7734 std::string r;
7735 for (; *s;) {
7736 if (*s == '$') {
7737 s++;
7738 std::string envname;
7739 for (; *s;) {
7740 if (*s == DIR_SEPARATOR)
7741 break;
7742 envname += *s;
7743 s++;
7744 }
7745 const char *e = getenv(envname.c_str());
7746 //printf("expanding [%s] at [%s] envname [%s] value [%s]\n", filename, s, envname.c_str(), e);
7747 if (!e) {
7748 //cm_msg(MERROR, "expand_env", "Env.variable \"%s\" cannot be expanded in \"%s\"", envname.c_str(), filename);
7749 r += '$';
7750 r += envname;
7751 } else {
7752 r += e;
7753 //if (r[r.length()-1] != DIR_SEPARATOR)
7754 //r += DIR_SEPARATOR_STR;
7755 }
7756 } else {
7757 r += *s;
7758 s++;
7759 }
7760 }
7761 return r;
7762}
#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 2073 of file midas.cxx.

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

2148 {
2149 if (host_name)
2150 host_name[0] = 0;
2151 if (exp_name)
2152 exp_name[0] = 0;
2153
2154 if (host_name && getenv("MIDAS_SERVER_HOST"))
2155 mstrlcpy(host_name, getenv("MIDAS_SERVER_HOST"), host_name_size);
2156
2157 if (exp_name && getenv("MIDAS_EXPT_NAME"))
2158 mstrlcpy(exp_name, getenv("MIDAS_EXPT_NAME"), exp_name_size);
2159
2160 return CM_SUCCESS;
2161}
Here is the call graph for this function:
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 2163 of file midas.cxx.

2163 {
2164 if (host_name)
2165 *host_name = "";
2166 if (exp_name)
2167 *exp_name = "";
2168
2169 if (host_name && getenv("MIDAS_SERVER_HOST"))
2170 *host_name = getenv("MIDAS_SERVER_HOST");
2171
2172 if (exp_name && getenv("MIDAS_EXPT_NAME"))
2173 *exp_name = getenv("MIDAS_EXPT_NAME");
2174
2175 return CM_SUCCESS;
2176}
Here is the call graph for this function:

◆ 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.
char name[32];
int size;
size = sizeof(name);
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 3025 of file midas.cxx.

3025 {
3026 if (_hDB) {
3027 //printf("cm_get_experiment_database %d %d\n", _hDB, _hKeyClient);
3028 if (hDB != NULL)
3029 *hDB = _hDB;
3030 if (hKeyClient != NULL)
3032 return CM_SUCCESS;
3033 } else {
3034 //printf("cm_get_experiment_database no init\n");
3035 if (hDB != NULL)
3036 *hDB = 0;
3037 if (hKeyClient != NULL)
3038 *hKeyClient = 0;
3039 return CM_DB_ERROR;
3040 }
3041}
#define CM_DB_ERROR
Definition midas.h:585
static HNDLE _hDB
Definition midas.cxx:1471
Here is the call graph for this function:

◆ cm_get_experiment_name() [1/2]

std::string cm_get_experiment_name ( )

Return the experiment name

Returns
experiment name

Definition at line 1594 of file midas.cxx.

1594 {
1595 return _experiment_name;
1596}
static std::string _experiment_name
Definition midas.cxx:1472
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 1584 of file midas.cxx.

1584 {
1586 return CM_SUCCESS;
1587}
Here is the call graph for this function:

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

3067{
3068 if (semaphore_alarm)
3070 if (semaphore_elog)
3074 //if (semaphore_msg)
3075 // *semaphore_msg = _semaphore_msg;
3076 if (semaphore_msg)
3077 *semaphore_msg = -1;
3078
3079 return CM_SUCCESS;
3080}
INT _semaphore_alarm
Definition midas.cxx:1476
INT _semaphore_elog
Definition midas.cxx:1477
INT _semaphore_history
Definition midas.cxx:1478
Here is the call graph for this function:
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 1844 of file midas.cxx.

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

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

1802 {
1803 return _exptab.filename;
1804}
std::string filename
Definition midas.cxx:1615
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 1797 of file midas.cxx.

1797 {
1798 mstrlcpy(s, _exptab.filename.c_str(), size);
1799 return CM_SUCCESS;
1800}
Here is the call graph for this function:

◆ cm_get_history_path()

std::string cm_get_history_path ( const char history_channel)

dox

Definition at line 5865 of file midas.cxx.

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

1551 {
1552 assert(_path_name.length() > 0);
1553 return _path_name;
1554}
static std::string _path_name
Definition midas.cxx:1474
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 1532 of file midas.cxx.

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

◆ cm_get_path_string()

INT EXPRT cm_get_path_string ( std::string *  path)

Definition at line 1559 of file midas.cxx.

1559 {
1560 assert(path != NULL);
1561 assert(_path_name.length() > 0);
1562 *path = _path_name;
1563 return CM_SUCCESS;
1564}
Here is the call graph for this function:

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

1498 {
1499 return GIT_REVISION;
1500}
Here is the call graph for this function:
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 1490 of file midas.cxx.

1490 {
1491 return MIDAS_VERSION;
1492}
#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 3358 of file midas.cxx.

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

3339 {
3340 if (call_watchdog)
3342 if (timeout)
3343 *timeout = _watchdog_timeout;
3344
3345 return CM_SUCCESS;
3346}
static INT _watchdog_timeout
Definition midas.cxx:1475
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_is_ctrlc_pressed()

BOOL cm_is_ctrlc_pressed ( void  )

Definition at line 5474 of file midas.cxx.

5474 {
5475 return _ctrlc_pressed;
5476}
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 2600 of file midas.cxx.

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

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

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

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

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

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

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

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

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

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

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

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

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

◆ cm_set_experiment_local()

int cm_set_experiment_local ( const char exp_name)

Definition at line 2180 of file midas.cxx.

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

1572 {
1574 return CM_SUCCESS;
1575}
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 2972 of file midas.cxx.

2992{
2996 //_semaphore_msg = semaphore_msg;
2997
2998 return CM_SUCCESS;
2999}
Here is the call graph for this function:
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 1511 of file midas.cxx.

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

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

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

3259{
3260#ifdef LOCAL_ROUTINES
3261 _watchdog_timeout = timeout;
3262
3263 std::vector<BUFFER*> mybuffers;
3264
3265 gBuffersMutex.lock();
3267 gBuffersMutex.unlock();
3268
3269 /* set watchdog timeout of all open buffers */
3270 for (BUFFER* pbuf : mybuffers) {
3271
3272 if (!pbuf || !pbuf->attached)
3273 continue;
3274
3276
3277 if (!pbuf_guard.is_locked())
3278 continue;
3279
3281
3282 /* clear entry from client structure in buffer header */
3283 pclient->watchdog_timeout = timeout;
3284
3285 /* show activity */
3286 pclient->last_activity = ss_millitime();
3287 }
3288
3289 /* set watchdog timeout for ODB */
3290 db_set_watchdog_params(timeout);
3291
3292#endif /* LOCAL_ROUTINES */
3293
3294 return CM_SUCCESS;
3295}
void db_set_watchdog_params(DWORD timeout)
Definition odb.cxx:2981
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 7422 of file midas.cxx.

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

7377 {
7378 /* watchdog does not run inside remote clients.
7379 * watchdog timeout timers are maintained by the mserver */
7380 if (rpc_is_remote())
7381 return CM_SUCCESS;
7382#ifdef LOCAL_ROUTINES
7383 /* only start once */
7384 if (_watchdog_thread)
7385 return CM_SUCCESS;
7386 _watchdog_thread_run = true;
7387 _watchdog_thread.store(new std::thread(xcm_watchdog_thread));
7388#endif
7389 return CM_SUCCESS;
7390}
static std::atomic< std::thread * > _watchdog_thread
Definition midas.cxx:7345
static void xcm_watchdog_thread()
Definition midas.cxx:7371
static std::atomic< bool > _watchdog_thread_run
Definition midas.cxx:7343
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 7392 of file midas.cxx.

7392 {
7393 /* watchdog does not run inside remote clients.
7394 * watchdog timeout timers are maintained by the mserver */
7395 if (rpc_is_remote())
7396 return CM_SUCCESS;
7397#ifdef LOCAL_ROUTINES
7398 _watchdog_thread_run = false;
7400 //printf("waiting for watchdog thread to shut down\n");
7401 ss_sleep(10);
7402 }
7403 if (_watchdog_thread != NULL) {
7404 _watchdog_thread.load()->join();
7405 delete static_cast<std::thread *>(_watchdog_thread);
7407 }
7408#endif
7409 return CM_SUCCESS;
7410}
static std::atomic< bool > _watchdog_thread_is_running
Definition midas.cxx:7344
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 1383 of file midas.cxx.

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

7779 {
7780 printf("Test expand_end()\n");
7781 setenv("FOO", "foo", 1);
7782 setenv("BAR", "bar", 1);
7783 setenv("EMPTY", "", 1);
7784 unsetenv("UNDEF");
7785
7786 bool ok = true;
7787
7788 ok &= test_cm_expand_env1("aaa", "aaa");
7789 ok &= test_cm_expand_env1("$FOO", "foo");
7790 ok &= test_cm_expand_env1("/$FOO", "/foo");
7791 ok &= test_cm_expand_env1("/$FOO/", "/foo/");
7792 ok &= test_cm_expand_env1("$FOO/$BAR", "foo/bar");
7793 ok &= test_cm_expand_env1("$FOO1", "$FOO1");
7794 ok &= test_cm_expand_env1("1$FOO", "1foo");
7795 ok &= test_cm_expand_env1("$UNDEF", "$UNDEF");
7796 ok &= test_cm_expand_env1("/$UNDEF/", "/$UNDEF/");
7797
7798 if (ok) {
7799 printf("test_expand_env: all tests passed!\n");
7800 } else {
7801 printf("test_expand_env: test FAILED!\n");
7802 }
7803}
static bool test_cm_expand_env1(const char *str, const char *expected)
Definition midas.cxx:7764
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 1448 of file midas.cxx.

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

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

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

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

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

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

5290{
5291 if (_trp.thread && !_trp.finished) {
5292 //printf("main transition thread did not finish yet!\n");
5294 }
5295
5296 std::thread* t = _trp.thread.exchange(NULL);
5297
5298 if (t) {
5299 t->join();
5300 delete t;
5301 t = NULL;
5302 }
5303
5304 return CM_SUCCESS;
5305}
Here is the call graph for this function:
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 4104 of file midas.cxx.

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

7351 {
7353 //printf("cm_watchdog_thread started!\n");
7354 while (_watchdog_thread_run) {
7355 //printf("cm_watchdog_thread runs!\n");
7359 int i;
7360 for (i = 0; i < 20; i++) {
7361 ss_sleep(100);
7363 break;
7364 }
7365 }
7366 //printf("cm_watchdog_thread stopped!\n");
7368 return 0;
7369}
static void bm_update_last_activity(DWORD millitime)
Definition midas.cxx:6139
INT db_update_last_activity(DWORD millitime)
Definition odb.cxx:2697
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 5664 of file midas.cxx.

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

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

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

12655{
12656 /* close all open connections */
12657
12659
12660 for (unsigned i = 0; i < _client_connections.size(); i++) {
12662 if (c && c->connected) {
12663 int index = c->index;
12664 // must unlock the array, otherwise we hang -
12665 // rpc_client_disconnect() will do rpc_call_client()
12666 // which needs to lock the array to convert handle
12667 // to connection pointer. Ouch! K.O. Dec 2020.
12671 }
12672 }
12673
12674 for (unsigned i = 0; i < _client_connections.size(); i++) {
12676 //printf("client connection %d %p\n", i, c);
12677 if (c) {
12678 //printf("client connection %d %p connected %d\n", i, c, c->connected);
12679 if (!c->connected) {
12680 delete c;
12682 }
12683 }
12684 }
12685
12687
12688 /* close server connection from other clients */
12689 for (unsigned i = 0; i < _server_acceptions.size(); i++) {
12690 if (_server_acceptions[i] && _server_acceptions[i]->recv_sock) {
12691 send(_server_acceptions[i]->recv_sock, "EXIT", 5, 0);
12692 _server_acceptions[i]->close();
12693 }
12694 }
12695}
static std::mutex _client_connections_mutex
Definition midas.cxx:11517
static std::vector< RPC_CLIENT_CONNECTION * > _client_connections
Definition midas.cxx:11518
static std::vector< RPC_SERVER_ACCEPTION * > _server_acceptions
Definition midas.cxx:11524
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 7764 of file midas.cxx.

7764 {
7765 std::string s = cm_expand_env(str);
7766 printf("test_expand_env: [%s] -> [%s] expected [%s]",
7767 str,
7768 s.c_str(),
7769 expected);
7770 if (s != expected) {
7771 printf(", MISMATCH!\n");
7772 return false;
7773 }
7774
7775 printf("\n");
7776 return true;
7777}
std::string cm_expand_env(const char *str)
Definition midas.cxx:7732
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 3998 of file midas.cxx.

3998 {
3999 return arg1->sequence_number < arg2->sequence_number;
4000}
Here is the call graph for this function:
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 4018 of file midas.cxx.

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

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

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

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

8059 {
8060 // NB: locking order: 1st buffer mutex, 2nd buffer semaphore. Unlock in reverse order.
8061
8062#if 0
8063 int x = MAX_CLIENTS-1;
8064 if (pbuf->attached) {
8065 if (pbuf->buffer_header->client[x].unused1 != getpid()) {
8066 printf("unlock [%s] unused1 %d pid %d\n", pbuf->buffer_header->name, pbuf->buffer_header->client[x].unused1, getpid());
8067 }
8068 pbuf->buffer_header->client[x].unused1 = 0;
8069 } else {
8070 printf("unlock [??????] unused1 ????? pid %d\n", getpid());
8071 }
8072#endif
8073
8074 // protect against double unlock
8075 assert(pbuf->locked);
8076 pbuf->locked = FALSE;
8077
8078 ss_semaphore_release(pbuf->semaphore);
8079 pbuf->buffer_mutex.unlock();
8080}
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 7371 of file midas.cxx.

7371 {
7373}
INT cm_watchdog_thread(void *unused)
Definition midas.cxx:7351
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 5461 of file midas.cxx.

◆ _deferred_transition_mask

DWORD _deferred_transition_mask
static

Definition at line 3841 of file midas.cxx.

◆ _exptab

exptab_struct _exptab
static

Definition at line 1619 of file midas.cxx.

◆ _requested_transition

INT _requested_transition
static

dox

Definition at line 3840 of file midas.cxx.

◆ _watchdog_thread

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

Definition at line 7345 of file midas.cxx.

7345{NULL};

◆ _watchdog_thread_is_running

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

Definition at line 7344 of file midas.cxx.

7344{false}; // set by watchdog thread

◆ _watchdog_thread_run

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

Definition at line 7343 of file midas.cxx.

7343{false}; // set by main thread