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

6161{
6162#ifdef LOCAL_ROUTINES
6163
6164 //printf("bm_cleanup: called by %s, actual_time %d, wrong_interval %d\n", who, actual_time, wrong_interval);
6165
6166 std::vector<BUFFER*> mybuffers;
6167
6168 gBuffersMutex.lock();
6170 gBuffersMutex.unlock();
6171
6172 /* check buffers */
6173 for (BUFFER* pbuf : mybuffers) {
6174 if (!pbuf)
6175 continue;
6176 if (pbuf->attached) {
6177 /* update the last_activity entry to show that we are alive */
6178
6180
6181 if (!pbuf_guard.is_locked())
6182 continue;
6183
6185 pclient->last_activity = actual_time;
6186
6187 /* don't check other clients if interval is strange */
6188 if (!wrong_interval)
6190 }
6191 }
6192#endif // LOCAL_ROUTINES
6193}
static void bm_cleanup_buffer_locked(BUFFER *pbuf, const char *who, DWORD actual_time)
Definition midas.cxx:6074
static BUFFER_CLIENT * bm_get_my_client_locked(bm_lock_buffer_guard &pbuf_guard)
Definition midas.cxx:6007
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 11292 of file midas.cxx.

11318{
11319 INT i;
11320
11321 if ((uint16_t(pevent->event_id) & uint16_t(0xF000)) == uint16_t(EVENTID_FRAG1)) {
11322 /*---- start new event ----*/
11323
11324 //printf("First Frag detected : Ser#:%d ID=0x%x \n", pevent->serial_number, pevent->event_id);
11325
11326 /* check if fragments already stored */
11327 for (i = 0; i < MAX_DEFRAG_EVENTS; i++)
11328 if (defrag_buffer[i].event_id == (pevent->event_id & 0x0FFF))
11329 break;
11330
11331 if (i < MAX_DEFRAG_EVENTS) {
11332 free(defrag_buffer[i].pevent);
11335 cm_msg(MERROR, "bm_defragement_event",
11336 "Received new event with ID %d while old fragments were not completed",
11337 (pevent->event_id & 0x0FFF));
11338 }
11339
11340 /* search new slot */
11341 for (i = 0; i < MAX_DEFRAG_EVENTS; i++)
11342 if (defrag_buffer[i].event_id == 0)
11343 break;
11344
11345 if (i == MAX_DEFRAG_EVENTS) {
11346 cm_msg(MERROR, "bm_defragment_event",
11347 "Not enough defragment buffers, please increase MAX_DEFRAG_EVENTS and recompile");
11348 return;
11349 }
11350
11351 /* check event size */
11352 if (pevent->data_size != sizeof(DWORD)) {
11353 cm_msg(MERROR, "bm_defragment_event",
11354 "Received first event fragment with %d bytes instead of %d bytes, event ignored",
11355 pevent->data_size, (int) sizeof(DWORD));
11356 return;
11357 }
11358
11359 /* setup defragment buffer */
11360 defrag_buffer[i].event_id = (pevent->event_id & 0x0FFF);
11364
11365 if (defrag_buffer[i].pevent == NULL) {
11367 cm_msg(MERROR, "bm_defragement_event", "Not enough memory to allocate event defragment buffer");
11368 return;
11369 }
11370
11371 memcpy(defrag_buffer[i].pevent, pevent, sizeof(EVENT_HEADER));
11374
11375 // printf("First frag[%d] (ID %d) Ser#:%d sz:%d\n", i, defrag_buffer[i].event_id,
11376 // pevent->serial_number, defrag_buffer[i].data_size);
11377
11378 return;
11379 }
11380
11381 /* search buffer for that event */
11382 for (i = 0; i < MAX_DEFRAG_EVENTS; i++)
11383 if (defrag_buffer[i].event_id == (pevent->event_id & 0xFFF))
11384 break;
11385
11386 if (i == MAX_DEFRAG_EVENTS) {
11387 /* no buffer available -> no first fragment received */
11388 cm_msg(MERROR, "bm_defragement_event",
11389 "Received fragment without first fragment (ID %d) Ser#:%d",
11390 pevent->event_id & 0x0FFF, pevent->serial_number);
11391 return;
11392 }
11393
11394 /* add fragment to buffer */
11396 free(defrag_buffer[i].pevent);
11399 cm_msg(MERROR, "bm_defragement_event",
11400 "Received fragments with more data (%d) than event size (%d)",
11402 return;
11403 }
11404
11405 memcpy(((char *) defrag_buffer[i].pevent) + sizeof(EVENT_HEADER) +
11406 defrag_buffer[i].received, pdata, pevent->data_size);
11407
11408 defrag_buffer[i].received += pevent->data_size;
11409
11410 //printf("Other frag[%d][%d] (ID %d) Ser#:%d sz:%d\n", i, j++,
11411 // defrag_buffer[i].event_id, pevent->serial_number, pevent->data_size);
11412
11413 if (defrag_buffer[i].received == defrag_buffer[i].data_size) {
11414 /* event complete */
11415 dispatcher(buffer_handle, request_id, defrag_buffer[i].pevent, defrag_buffer[i].pevent + 1);
11416 free(defrag_buffer[i].pevent);
11419 }
11420}
#define MAX_DEFRAG_EVENTS
Definition midas.cxx:11280
static EVENT_DEFRAG_BUFFER defrag_buffer[MAX_DEFRAG_EVENTS]
Definition midas.cxx:11289
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:915
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:11286
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 6630 of file midas.cxx.

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

6007 {
6009 return pbuf_guard.get_pbuf()->buffer_header->client + my_client_index;
6010}
static int bm_validate_client_index_locked(bm_lock_buffer_guard &pbuf_guard)
Definition midas.cxx:5930
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 7954 of file midas.cxx.

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

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

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

11076{
11077 static DWORD last_time = 0;
11079
11080 //printf("bm_notify_client: buffer [%s], socket %d, time %d\n", buffer_name, client_socket, now - last_time);
11081
11082 BUFFER* fbuf = NULL;
11083
11084 gBuffersMutex.lock();
11085
11086 for (size_t i = 0; i < gBuffers.size(); i++) {
11087 BUFFER* pbuf = gBuffers[i];
11088 if (!pbuf || !pbuf->attached)
11089 continue;
11090 if (strcmp(buffer_name, pbuf->buffer_header->name) == 0) {
11091 fbuf = pbuf;
11092 break;
11093 }
11094 }
11095
11096 gBuffersMutex.unlock();
11097
11098 if (!fbuf)
11099 return BM_INVALID_HANDLE;
11100
11101 /* don't send notification if client has no callback defined
11102 to receive events -> client calls bm_receive_event manually */
11103 if (!fbuf->callback)
11104 return DB_SUCCESS;
11105
11106 int convert_flags = rpc_get_convert_flags();
11107
11108 /* only send notification once each 500ms */
11109 if (now - last_time < 500)
11110 return DB_SUCCESS;
11111
11112 last_time = now;
11113
11114 char buffer[32];
11115 NET_COMMAND *nc = (NET_COMMAND *) buffer;
11116
11117 nc->header.routine_id = MSG_BM;
11118 nc->header.param_size = 0;
11119
11120 if (convert_flags) {
11123 }
11124
11125 //printf("bm_notify_client: Sending MSG_BM! buffer [%s]\n", buffer_name);
11126
11127 /* send the update notification to the client */
11128 send_tcp(client_socket, (char *) buffer, sizeof(NET_COMMAND_HEADER), 0);
11129
11130 return BM_SUCCESS;
11131}
#define DB_SUCCESS
Definition midas.h:631
#define TID_UINT32
Definition midas.h:337
#define MSG_BM
Definition msystem.h:295
DWORD ss_millitime()
Definition system.cxx:3393
INT send_tcp(int sock, char *buffer, DWORD buffer_size, INT flags)
Definition system.cxx:5285
INT rpc_get_convert_flags(void)
Definition midas.cxx:13038
void rpc_convert_single(void *data, INT tid, INT flags, INT convert_flags)
Definition midas.cxx:11689
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:286
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 10926 of file midas.cxx.

10927{
10928 std::vector<BUFFER*> mybuffers;
10929
10930 gBuffersMutex.lock();
10932 gBuffersMutex.unlock();
10933
10934 for (size_t i = 0; i < mybuffers.size(); i++) {
10935 BUFFER *pbuf = mybuffers[i];
10936 if (!pbuf || !pbuf->attached)
10937 continue;
10938 // FIXME: unlocked read access to pbuf->buffer_name!
10939 if (strcmp(buffer_name, pbuf->buffer_name) == 0) {
10940 return bm_push_buffer(pbuf, i + 1);
10941 }
10942 }
10943
10944 return BM_INVALID_HANDLE;
10945}
static INT bm_push_buffer(BUFFER *pbuf, int buffer_handle)
Definition midas.cxx:10910
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 5464 of file midas.cxx.

5464 {
5466}
#define FALSE
Definition cfortran.h:309
static BOOL _ctrlc_pressed
Definition midas.cxx:5447
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 1412 of file midas.cxx.

1412 {
1413 /* if connected to server, get time from there */
1414 if (rpc_is_remote()) {
1415 char buf[256];
1416 int status = rpc_call(RPC_CM_ASCTIME, buf, sizeof(buf));
1417 if (status == CM_SUCCESS) {
1418 return buf;
1419 } else {
1420 return "";
1421 }
1422 }
1423
1424 /* return local time */
1425 return ss_asctime();
1426}
#define CM_SUCCESS
Definition midas.h:582
std::string ss_asctime()
Definition system.cxx:3549
#define RPC_CM_ASCTIME
Definition mrpc.h:28
bool rpc_is_remote(void)
Definition midas.cxx:12769
INT rpc_call(DWORD routine_id,...)
Definition midas.cxx:13671
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 1396 of file midas.cxx.

1396 {
1397 /* if connected to server, get time from there */
1398 if (rpc_is_remote())
1399 return rpc_call(RPC_CM_ASCTIME, str, buf_size);
1400
1401 /* return local time */
1402 mstrlcpy(str, ss_asctime().c_str(), buf_size);
1403
1404 return CM_SUCCESS;
1405}
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 1869 of file midas.cxx.

1869 {
1870 if (rpc_is_remote())
1872
1873#ifdef LOCAL_ROUTINES
1875#endif /*LOCAL_ROUTINES */
1876 return CM_SUCCESS;
1877}
INT db_check_client(HNDLE hDB, HNDLE hKeyClient)
Definition odb.cxx:3059
#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 2201 of file midas.cxx.

2201 {
2202 if (_hKeyClient) {
2203 cm_msg(MERROR, "cm_check_connect", "cm_disconnect_experiment not called at end of program");
2205 }
2206}
INT cm_msg_flush_buffer()
Definition midas.cxx:865
static HNDLE _hKeyClient
Definition midas.cxx:1456
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 3897 of file midas.cxx.

3897 {
3898 INT i, status;
3899 char str[256];
3900 static BOOL first;
3901
3902 if (_requested_transition == 0)
3903 first = TRUE;
3904
3906 for (i = 0; _deferred_trans_table[i].transition; i++)
3908 break;
3909
3913 if (status != CM_SUCCESS)
3914 cm_msg(MERROR, "cm_check_deferred_transition", "Cannot perform deferred transition: %s", str);
3915
3916 /* bypass hotlink and set _requested_transition directly to zero */
3918
3919 return status;
3920 }
3921 first = FALSE;
3922 }
3923 }
3924
3925 return SUCCESS;
3926}
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:5294
static DWORD _deferred_transition_mask
Definition midas.cxx:3827
static INT _requested_transition
Definition midas.cxx:3826
#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 7618 of file midas.cxx.

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

2766 {
2768 INT status, i, length, port;
2770
2771 /* find client entry in ODB */
2773
2774 status = db_find_key(hDB, 0, "System/Clients", &hKeyRoot);
2775 if (status != DB_SUCCESS)
2776 return status;
2777
2778 i = 0;
2779 do {
2780 /* search for client with specific name */
2783 return CM_NO_CLIENT;
2784
2785 status = db_find_key(hDB, hSubkey, "Name", &hKey);
2786 if (status != DB_SUCCESS)
2787 return status;
2788
2791 if (status != DB_SUCCESS)
2792 return status;
2793
2794 if (equal_ustring(name, client_name)) {
2795 status = db_find_key(hDB, hSubkey, "Server Port", &hKey);
2796 if (status != DB_SUCCESS)
2797 return status;
2798
2799 length = sizeof(INT);
2800 status = db_get_data(hDB, hKey, &port, &length, TID_INT32);
2801 if (status != DB_SUCCESS)
2802 return status;
2803
2804 status = db_find_key(hDB, hSubkey, "Host", &hKey);
2805 if (status != DB_SUCCESS)
2806 return status;
2807
2808 length = sizeof(host_name);
2810 if (status != DB_SUCCESS)
2811 return status;
2812
2813 /* client found -> connect to its server port */
2814 return rpc_client_connect(host_name, port, client_name, hConn);
2815 }
2816
2817
2818 } while (TRUE);
2819}
INT cm_get_experiment_database(HNDLE *hDB, HNDLE *hKeyClient)
Definition midas.cxx:3011
#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:3201
INT db_get_data(HNDLE hDB, HNDLE hKey, void *data, INT *buf_size, DWORD type)
Definition odb.cxx:6539
INT db_find_key(HNDLE hDB, HNDLE hKey, const char *key_name, HNDLE *subhKey)
Definition odb.cxx:4079
INT db_enum_key(HNDLE hDB, HNDLE hKey, INT idx, HNDLE *subkey_handle)
Definition odb.cxx:5586
INT rpc_client_connect(const char *host_name, INT port, const char *client_name, HNDLE *hConnection)
Definition midas.cxx:12020
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:2278
INT cm_disconnect_experiment(void)
Definition midas.cxx:2846
INT cm_get_environment(char *host_name, int host_name_size, char *exp_name, int exp_name_size)
Definition midas.cxx:2134
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 2278 of file midas.cxx.

2278 {
2279 INT status;
2280
2283 if (status != CM_SUCCESS) {
2284 std::string s = cm_get_error(status);
2285 puts(s.c_str());
2286 }
2287
2288 return status;
2289}
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:2297
std::string cm_get_error(INT code)
Definition midas.cxx:455
#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 2297 of file midas.cxx.

2298 {
2299 INT status, size;
2301 char password[NAME_LENGTH], str[256];
2302 HNDLE hDB = 0, hKeyClient = 0;
2304
2305 ss_tzset(); // required for localtime_r()
2306
2307 if (_hKeyClient)
2309
2311
2312 //cm_msg(MERROR, "cm_connect_experiment", "test cm_msg before connecting to experiment");
2313 //cm_msg_flush_buffer();
2314
2315 rpc_set_name(client_name);
2316
2317 /* check for local host */
2318 if (equal_ustring(host_name, "local"))
2319 host_name = NULL;
2320
2321#ifdef OS_WINNT
2322 {
2324
2325 /* Start windows sockets */
2326 if (WSAStartup(MAKEWORD(1, 1), &WSAData) != 0)
2327 return RPC_NET_ERROR;
2328 }
2329#endif
2330
2331 std::string default_exp_name1;
2332 if (default_exp_name)
2334
2335 /* connect to MIDAS server */
2336 if (host_name && host_name[0]) {
2337 if (default_exp_name1.length() == 0) {
2339 if (status != CM_SUCCESS)
2340 return status;
2341 }
2342
2344
2346 if (status != RPC_SUCCESS)
2347 return status;
2348
2349 /* register MIDAS library functions */
2351 if (status != RPC_SUCCESS)
2352 return status;
2353 } else {
2354 /* lookup path for *SHM files and save it */
2355
2356#ifdef LOCAL_ROUTINES
2358 if (status != CM_SUCCESS)
2359 return status;
2360
2362
2364
2366
2367 /* create alarm and elog semaphores */
2369 if (status != SS_CREATED && status != SS_SUCCESS) {
2370 cm_msg(MERROR, "cm_connect_experiment", "Cannot create alarm semaphore");
2371 return status;
2372 }
2374 if (status != SS_CREATED && status != SS_SUCCESS) {
2375 cm_msg(MERROR, "cm_connect_experiment", "Cannot create elog semaphore");
2376 return status;
2377 }
2379 if (status != SS_CREATED && status != SS_SUCCESS) {
2380 cm_msg(MERROR, "cm_connect_experiment", "Cannot create history semaphore");
2381 return status;
2382 }
2384 if (status != SS_CREATED && status != SS_SUCCESS) {
2385 cm_msg(MERROR, "cm_connect_experiment", "Cannot create message semaphore");
2386 return status;
2387 }
2388
2390#else
2391 return CM_UNDEF_EXP;
2392#endif
2393 }
2394
2395 //cm_msg(MERROR, "cm_connect_experiment", "test cm_msg before open ODB");
2396 //cm_msg_flush_buffer();
2397
2398 /* open ODB */
2399 if (odb_size == 0)
2401
2402 status = db_open_database("ODB", odb_size, &hDB, client_name);
2403 if (status != DB_SUCCESS && status != DB_CREATED) {
2404 cm_msg(MERROR, "cm_connect_experiment1", "cannot open database, db_open_database() status %d", status);
2405 return status;
2406 }
2407
2408 //cm_msg(MERROR, "cm_connect_experiment", "test cm_msg after open ODB");
2409 //cm_msg_flush_buffer();
2410
2412 size = sizeof(odb_timeout);
2413 status = db_get_value(hDB, 0, "/Experiment/ODB timeout", &odb_timeout, &size, TID_INT32, TRUE);
2414 if (status != DB_SUCCESS) {
2415 cm_msg(MERROR, "cm_connect_experiment1", "cannot get ODB /Experiment/ODB timeout, status %d", status);
2416 }
2417
2418 if (odb_timeout > 0) {
2420 }
2421
2423 size = sizeof(protect_odb);
2424 status = db_get_value(hDB, 0, "/Experiment/Protect ODB", &protect_odb, &size, TID_BOOL, TRUE);
2425 if (status != DB_SUCCESS) {
2426 cm_msg(MERROR, "cm_connect_experiment1", "cannot get ODB /Experiment/Protect ODB, status %d", status);
2427 }
2428
2429 if (protect_odb) {
2431 }
2432
2434 size = sizeof(enable_core_dumps);
2435 status = db_get_value(hDB, 0, "/Experiment/Enable core dumps", &enable_core_dumps, &size, TID_BOOL, TRUE);
2436 if (status != DB_SUCCESS) {
2437 cm_msg(MERROR, "cm_connect_experiment1", "cannot get ODB /Experiment/Enable core dumps, status %d", status);
2438 }
2439
2440 if (enable_core_dumps) {
2441#ifdef RLIMIT_CORE
2442 struct rlimit limit;
2443 limit.rlim_cur = RLIM_INFINITY;
2444 limit.rlim_max = RLIM_INFINITY;
2446 if (status != 0) {
2447 cm_msg(MERROR, "cm_connect_experiment", "Cannot setrlimit(RLIMIT_CORE, RLIM_INFINITY), errno %d (%s)", errno,
2448 strerror(errno));
2449 }
2450#else
2451#warning setrlimit(RLIMIT_CORE) is not available
2452#endif
2453 }
2454
2455 size = sizeof(disable_bind_rpc_to_localhost);
2456 status = db_get_value(hDB, 0, "/Experiment/Security/Enable non-localhost RPC", &disable_bind_rpc_to_localhost, &size,
2457 TID_BOOL, TRUE);
2458 if (status != DB_SUCCESS) {
2459 cm_msg(MERROR, "cm_connect_experiment1",
2460 "cannot get ODB /Experiment/Security/Enable non-localhost RPC, status %d", status);
2461 }
2462
2463 std::string local_host_name;
2464
2465 /* now setup client info */
2467 local_host_name = "localhost";
2468 else
2470
2471 /* check watchdog timeout */
2472 if (watchdog_timeout == 0)
2473 watchdog_timeout = DEFAULT_WATCHDOG_TIMEOUT;
2474
2475 strcpy(client_name1, client_name);
2476 password[0] = 0;
2477 status = cm_set_client_info(hDB, &hKeyClient, local_host_name.c_str(), client_name1, rpc_get_hw_type(), password, watchdog_timeout);
2478
2479 if (status == CM_WRONG_PASSWORD) {
2480 if (func == NULL)
2481 strcpy(str, ss_getpass("Password: "));
2482 else
2483 func(str);
2484
2485 strcpy(password, ss_crypt(str, "mi"));
2486 status = cm_set_client_info(hDB, &hKeyClient, local_host_name.c_str(), client_name1, rpc_get_hw_type(), password, watchdog_timeout);
2487 if (status != CM_SUCCESS) {
2488 /* disconnect */
2489 if (rpc_is_remote())
2492
2493 return status;
2494 }
2495 }
2496
2497 //cm_msg(MERROR, "cm_connect_experiment", "test cm_msg after set client info");
2498 //cm_msg_flush_buffer();
2499
2500 /* tell the rest of MIDAS that ODB is open for business */
2501
2503
2504 //cm_msg(MERROR, "cm_connect_experiment", "test cm_msg after set experiment database");
2505 //cm_msg_flush_buffer();
2506
2507 /* cm_msg_open_buffer() calls bm_open_buffer() calls ODB function
2508 * to get event buffer size, etc */
2509
2511 if (status != CM_SUCCESS) {
2512 cm_msg(MERROR, "cm_connect_experiment1", "cannot open message buffer, cm_msg_open_buffer() status %d", status);
2513 return status;
2514 }
2515
2516 //cm_msg(MERROR, "cm_connect_experiment", "test cm_msg after message system is ready");
2517 //cm_msg_flush_buffer();
2518
2519 /* set experiment name in ODB if not present */
2520 std::string current_name;
2521 db_get_value_string(hDB, 0, "/Experiment/Name", 0, &current_name, TRUE);
2522 if (current_name.length() == 0 || current_name == "Default") {
2523 db_set_value_string(hDB, 0, "/Experiment/Name", &default_exp_name1);
2524 }
2525
2526 if (!rpc_is_remote()) {
2527 /* experiment path is only set for local connections */
2528 /* set data dir in ODB */
2529 std::string path = cm_get_path();
2530 db_get_value_string(hDB, 0, "/Logger/Data dir", 0, &path, TRUE);
2531 }
2532
2533 /* register server to be able to be called by other clients */
2535 if (status != CM_SUCCESS) {
2536 cm_msg(MERROR, "cm_connect_experiment", "Cannot register RPC server, cm_register_server() status %d", status);
2537 if (!equal_ustring(client_name, "odbedit")) {
2538 return status;
2539 }
2540 }
2541
2542 /* set watchdog timeout */
2543 cm_get_watchdog_params(&call_watchdog, &watchdog_timeout);
2544 size = sizeof(watchdog_timeout);
2545 sprintf(str, "/Programs/%s/Watchdog Timeout", client_name);
2546 db_get_value(hDB, 0, str, &watchdog_timeout, &size, TID_INT32, TRUE);
2547 cm_set_watchdog_params(call_watchdog, watchdog_timeout);
2548
2549 /* set name of executable */
2550 std::string executable = ss_get_executable();
2551 std::string path = "/Programs/" + std::string(client_name);
2552 midas::odb prog(path);
2553 if (!midas::odb::exists(path + "/Start command") ||
2554 prog["Start command"] == std::string(""))
2555 prog["Start command"].set_string_size(executable, 256);
2556
2557 /* get final client name */
2558 std::string xclient_name = rpc_get_name();
2559
2560 /* startup message is not displayed */
2561 cm_msg(MLOG, "cm_connect_experiment", "Program %s on host %s started", xclient_name.c_str(), local_host_name.c_str());
2562
2563 /* enable system and user messages to stdout as default */
2565
2566 /* call cm_check_connect when exiting */
2567 atexit((void (*)(void)) cm_check_connect);
2568
2569 /* register ctrl-c handler */
2571
2572 //cm_msg(MERROR, "cm_connect_experiment", "test cm_msg after connect to experiment is complete");
2573 //cm_msg_flush_buffer();
2574
2575 return CM_SUCCESS;
2576}
static bool exists(const std::string &name)
Definition odbxx.cxx:75
INT cm_get_watchdog_params(BOOL *call_watchdog, DWORD *timeout)
Definition midas.cxx:3325
INT cm_select_experiment_remote(const char *host_name, std::string *exp_name)
Definition midas.cxx:2719
INT cm_register_server(void)
Definition midas.cxx:3460
void cm_check_connect(void)
Definition midas.cxx:2201
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:1893
std::string cm_get_path()
Definition midas.cxx:1537
int cm_set_experiment_local(const char *exp_name)
Definition midas.cxx:2166
std::string cm_get_experiment_name()
Definition midas.cxx:1580
INT cm_set_experiment_database(HNDLE hDB, HNDLE hKeyClient)
Definition midas.cxx:2939
void cm_ctrlc_handler(int sig)
Definition midas.cxx:5449
INT cm_set_watchdog_params(BOOL call_watchdog, DWORD timeout)
Definition midas.cxx:3283
INT cm_set_experiment_semaphore(INT semaphore_alarm, INT semaphore_elog, INT semaphore_history, INT semaphore_msg)
Definition midas.cxx:2958
INT cm_set_experiment_name(const char *name)
Definition midas.cxx:1558
#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:5712
INT ss_suspend_init_odb_port()
Definition system.cxx:4305
INT ss_semaphore_create(const char *name, HNDLE *semaphore_handle)
Definition system.cxx:2460
char * ss_getpass(const char *prompt)
Definition system.cxx:7446
void ss_tzset()
Definition system.cxx:3355
char * ss_crypt(const char *buf, const char *salt)
Definition system.cxx:7897
void * ss_ctrlc_handler(void(*func)(int))
Definition system.cxx:3899
std::string ss_get_executable(void)
Definition system.cxx:1488
int cm_msg_early_init(void)
Definition midas.cxx:467
int cm_msg_open_buffer(void)
Definition midas.cxx:474
INT cm_set_msg_print(INT system_mask, INT user_mask, int(*func)(const char *))
Definition midas.cxx:647
INT db_get_value(HNDLE hDB, HNDLE hKeyRoot, const char *key_name, void *data, INT *buf_size, DWORD type, BOOL create)
Definition odb.cxx:5415
INT db_open_database(const char *xdatabase_name, INT database_size, HNDLE *hDB, const char *client_name)
Definition odb.cxx:1787
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:13935
INT EXPRT db_set_value_string(HNDLE hDB, HNDLE hKeyRoot, const char *key_name, const std::string *s)
Definition odb.cxx:14006
INT db_set_lock_timeout(HNDLE hDB, int timeout_millisec)
Definition odb.cxx:2664
INT db_protect_database(HNDLE hDB)
Definition odb.cxx:3167
INT rpc_register_functions(const RPC_LIST *new_list, RPC_HANDLER func)
Definition midas.cxx:11835
INT rpc_server_connect(const char *host_name, const char *exp_name)
Definition midas.cxx:12389
std::string rpc_get_name()
Definition midas.cxx:13092
INT rpc_get_hw_type()
Definition midas.cxx:12842
INT rpc_server_disconnect()
Definition midas.cxx:12713
INT rpc_set_name(const char *name)
Definition midas.cxx:13116
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 5449 of file midas.cxx.

5449 {
5450 if (_ctrlc_pressed) {
5451 printf("Received 2nd Ctrl-C, hard abort\n");
5452 exit(0);
5453 }
5454 printf("Received Ctrl-C, aborting...\n");
5456
5458}
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 1852 of file midas.cxx.

1852 {
1853 /* only do it if local */
1854 if (!rpc_is_remote()) {
1856 }
1857 return CM_SUCCESS;
1858}
int db_delete_client_info(HNDLE hDB, int pid)
Definition odb.cxx:2791
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 3677 of file midas.cxx.

3677 {
3678 INT status;
3680 char str[256];
3681
3682 /* check for valid transition */
3684 cm_msg(MERROR, "cm_deregister_transition", "Invalid transition request \"%d\"", transition);
3685 return CM_INVALID_TRANSITION;
3686 }
3687
3689
3690 {
3691 std::lock_guard<std::mutex> guard(_trans_table_mutex);
3692
3693 /* remove existing transition request */
3694 for (size_t i = 0; i < _trans_table.size(); i++) {
3696 _trans_table[i].transition = 0;
3697 _trans_table[i].sequence_number = 0;
3698 _trans_table[i].func = NULL;
3699 }
3700 }
3701
3702 // implicit unlock
3703 }
3704
3705 sprintf(str, "Transition %s", cm_transition_name(transition).c_str());
3706
3707 /* unlock database */
3709
3710 /* set value */
3712 if (hKeyTrans) {
3714 if (status != DB_SUCCESS)
3715 return status;
3716 }
3717
3718 /* re-lock database */
3720
3721 return CM_SUCCESS;
3722}
#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:3856
INT db_set_mode(HNDLE hDB, HNDLE hKey, WORD mode, BOOL recurse)
Definition odb.cxx:8027
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 2833 of file midas.cxx.

2833 {
2835}
INT rpc_client_disconnect(HNDLE hConn, BOOL bShutdown)
Definition midas.cxx:12684
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 2846 of file midas.cxx.

2846 {
2847 HNDLE hDB, hKey;
2848
2849 //cm_msg(MERROR, "cm_disconnect_experiment", "test cm_msg before disconnect from experiment");
2850 //cm_msg_flush_buffer();
2851
2852 /* wait on any transition thread */
2853 if (_trp.transition && !_trp.finished) {
2854 printf("Waiting for transition to finish...\n");
2855 do {
2856 ss_sleep(10);
2857 } while (!_trp.finished);
2858 }
2859
2860 /* stop the watchdog thread */
2862
2863 /* send shutdown notification */
2864 std::string client_name = rpc_get_name();
2865
2866 std::string local_host_name;
2867
2869 local_host_name = "localhost";
2870 else {
2872 //if (strchr(local_host_name, '.'))
2873 // *strchr(local_host_name, '.') = 0;
2874 }
2875
2876 /* disconnect message not displayed */
2877 cm_msg(MLOG, "cm_disconnect_experiment", "Program %s on host %s stopped", client_name.c_str(), local_host_name.c_str());
2879
2880 if (rpc_is_remote()) {
2881 if (rpc_is_connected()) {
2882 /* close open records */
2884
2886 }
2887
2890
2892 } else {
2894
2895 /* delete client info */
2897
2898 if (hDB)
2900
2901 //cm_msg(MERROR, "cm_disconnect_experiment", "test cm_msg before close all buffers, close all databases");
2902 //cm_msg_flush_buffer();
2903
2907
2909
2910 //cm_msg(MERROR, "cm_disconnect_experiment", "test cm_msg after close all buffers, close all databases");
2911 //cm_msg_flush_buffer();
2912 }
2913
2914 if (!rpc_is_mserver())
2916
2917 /* free RPC list */
2919
2920 //cm_msg(MERROR, "cm_disconnect_experiment", "test cm_msg before deleting the message ring buffer");
2921 //cm_msg_flush_buffer();
2922
2923 /* last flush before we delete the message ring buffer */
2925
2926 //cm_msg(MERROR, "cm_disconnect_experiment", "test cm_msg after disconnect is completed");
2927 //cm_msg_flush_buffer();
2928
2929 return CM_SUCCESS;
2930}
INT bm_close_all_buffers(void)
Definition midas.cxx:7251
INT cm_stop_watchdog_thread()
Definition midas.cxx:7378
static void rpc_client_shutdown()
Definition midas.cxx:12640
INT cm_delete_client_info(HNDLE hDB, INT pid)
Definition midas.cxx:1852
INT ss_sleep(INT millisec)
Definition system.cxx:3628
int cm_msg_close_buffer(void)
Definition midas.cxx:487
INT db_close_all_records()
Definition odb.cxx:13515
INT db_close_all_databases(void)
Definition odb.cxx:2360
INT rpc_deregister_functions()
Definition midas.cxx:11878
bool rpc_is_connected(void)
Definition midas.cxx:12791
INT rpc_server_shutdown(void)
Definition midas.cxx:16191
bool rpc_is_mserver(void)
Definition midas.cxx:12826
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 5393 of file midas.cxx.

5412{
5413 if (message[0] == 'O') {
5415 INT index;
5416 index = 0;
5417 sscanf(message + 2, "%d %d %d %d", &hDB, &hKeyRoot, &hKey, &index);
5418 if (client_socket) {
5420 } else {
5422 }
5423 }
5424
5425 /* message == "B" means "resume event sender" */
5426 if (message[0] == 'B' && message[2] != ' ') {
5427 char str[NAME_LENGTH];
5428
5429 //printf("cm_dispatch_ipc: message [%s], s=%d\n", message, s);
5430
5431 mstrlcpy(str, message + 2, sizeof(str));
5432 if (strchr(str, ' '))
5433 *strchr(str, ' ') = 0;
5434
5435 if (client_socket)
5437 else
5438 return bm_push_event(str);
5439 }
5440
5441 //printf("cm_dispatch_ipc: message [%s] ignored\n", message);
5442
5443 return CM_SUCCESS;
5444}
static INT bm_push_event(const char *buffer_name)
Definition midas.cxx:10926
static INT bm_notify_client(const char *buffer_name, int s)
Definition midas.cxx:11056
INT db_update_record_local(INT hDB, INT hKeyRoot, INT hKey, int index)
Definition odb.cxx:13553
INT db_update_record_mserver(INT hDB, INT hKeyRoot, INT hKey, int index, int client_socket)
Definition odb.cxx:13600
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 5469 of file midas.cxx.

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

5731 {
5732 char str[256];
5733 INT n;
5734 int fh;
5735 int status = 0;
5736 static int check_cm_execute = 1;
5737 static int enable_cm_execute = 0;
5738
5739 if (rpc_is_remote())
5740 return rpc_call(RPC_CM_EXECUTE, command, result, bufsize);
5741
5742 if (check_cm_execute) {
5743 int status;
5744 int size;
5745 HNDLE hDB;
5746 check_cm_execute = 0;
5747
5749 assert(status == DB_SUCCESS);
5750
5751 size = sizeof(enable_cm_execute);
5752 status = db_get_value(hDB, 0, "/Experiment/Enable cm_execute", &enable_cm_execute, &size, TID_BOOL, TRUE);
5753 assert(status == DB_SUCCESS);
5754
5755 //printf("enable_cm_execute %d\n", enable_cm_execute);
5756 }
5757
5758 if (!enable_cm_execute) {
5759 char buf[32];
5760 mstrlcpy(buf, command, sizeof(buf));
5761 cm_msg(MERROR, "cm_execute", "cm_execute(%s...) is disabled by ODB \"/Experiment/Enable cm_execute\"", buf);
5762 return CM_WRONG_PASSWORD;
5763 }
5764
5765 if (bufsize > 0) {
5766 strcpy(str, command);
5767 sprintf(str, "%s > %d.tmp", command, ss_getpid());
5768
5769 status = system(str);
5770
5771 sprintf(str, "%d.tmp", ss_getpid());
5772 fh = open(str, O_RDONLY, 0644);
5773 result[0] = 0;
5774 if (fh) {
5775 n = read(fh, result, bufsize - 1);
5776 result[MAX(0, n)] = 0;
5777 close(fh);
5778 }
5779 remove(str);
5780 } else {
5781 status = system(command);
5782 }
5783
5784 if (status < 0) {
5785 cm_msg(MERROR, "cm_execute", "cm_execute(%s) error %d", command, status);
5786 return CM_SET_ERROR;
5787 }
5788
5789 return CM_SUCCESS;
5790}
#define CM_SET_ERROR
Definition midas.h:583
#define MAX(a, b)
Definition midas.h:509
INT ss_getpid(void)
Definition system.cxx:1377
#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 7528 of file midas.cxx.

7528 {
7529 INT status, i, size;
7531 char client_name[NAME_LENGTH];
7532
7533 if (rpc_is_remote())
7535
7537
7538 status = db_find_key(hDB, 0, "System/Clients", &hKey);
7539 if (status != DB_SUCCESS)
7540 return DB_NO_KEY;
7541
7543
7544 /* loop over all clients */
7545 for (i = 0;; i++) {
7548 break;
7549
7550 if (hSubkey == hKeyClient)
7551 continue;
7552
7553 if (status == DB_SUCCESS) {
7554 /* get client name */
7555 size = sizeof(client_name);
7556 status = db_get_value(hDB, hSubkey, "Name", client_name, &size, TID_STRING, FALSE);
7557
7558 if (status != DB_SUCCESS) {
7559 //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);
7560 continue;
7561 }
7562
7563 if (equal_ustring(client_name, name)) {
7565 return CM_SUCCESS;
7566 }
7567
7568 if (!bUnique) {
7569 client_name[strlen(name)] = 0; /* strip number */
7570 if (equal_ustring(client_name, name)) {
7572 return CM_SUCCESS;
7573 }
7574 }
7575 }
7576 }
7577
7579
7580 return CM_NO_CLIENT;
7581}
#define DB_NO_KEY
Definition midas.h:642
INT db_lock_database(HNDLE hDB)
Definition odb.cxx:2455
INT db_unlock_database(HNDLE hDB)
Definition odb.cxx:2577
#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 7718 of file midas.cxx.

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

2060{
2061 INT status;
2062 HNDLE hDB, hKey;
2063
2064 /* get root key of client */
2066 if (!hDB) {
2067 return "unknown";
2068 }
2069
2070 std::string name;
2071
2072 status = db_get_value_string(hDB, hKey, "Name", 0, &name);
2073 if (status != DB_SUCCESS) {
2074 return "unknown";
2075 }
2076
2077 //printf("get client name: [%s]\n", name.c_str());
2078
2079 return name;
2080}
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 2134 of file midas.cxx.

2134 {
2135 if (host_name)
2136 host_name[0] = 0;
2137 if (exp_name)
2138 exp_name[0] = 0;
2139
2140 if (host_name && getenv("MIDAS_SERVER_HOST"))
2141 mstrlcpy(host_name, getenv("MIDAS_SERVER_HOST"), host_name_size);
2142
2143 if (exp_name && getenv("MIDAS_EXPT_NAME"))
2144 mstrlcpy(exp_name, getenv("MIDAS_EXPT_NAME"), exp_name_size);
2145
2146 return CM_SUCCESS;
2147}
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 2149 of file midas.cxx.

2149 {
2150 if (host_name)
2151 *host_name = "";
2152 if (exp_name)
2153 *exp_name = "";
2154
2155 if (host_name && getenv("MIDAS_SERVER_HOST"))
2156 *host_name = getenv("MIDAS_SERVER_HOST");
2157
2158 if (exp_name && getenv("MIDAS_EXPT_NAME"))
2159 *exp_name = getenv("MIDAS_EXPT_NAME");
2160
2161 return CM_SUCCESS;
2162}
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 3011 of file midas.cxx.

3011 {
3012 if (_hDB) {
3013 //printf("cm_get_experiment_database %d %d\n", _hDB, _hKeyClient);
3014 if (hDB != NULL)
3015 *hDB = _hDB;
3016 if (hKeyClient != NULL)
3018 return CM_SUCCESS;
3019 } else {
3020 //printf("cm_get_experiment_database no init\n");
3021 if (hDB != NULL)
3022 *hDB = 0;
3023 if (hKeyClient != NULL)
3024 *hKeyClient = 0;
3025 return CM_DB_ERROR;
3026 }
3027}
#define CM_DB_ERROR
Definition midas.h:585
static HNDLE _hDB
Definition midas.cxx:1457
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 1580 of file midas.cxx.

1580 {
1581 return _experiment_name;
1582}
static std::string _experiment_name
Definition midas.cxx:1458
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 1570 of file midas.cxx.

1570 {
1572 return CM_SUCCESS;
1573}
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 3033 of file midas.cxx.

3053{
3054 if (semaphore_alarm)
3056 if (semaphore_elog)
3060 //if (semaphore_msg)
3061 // *semaphore_msg = _semaphore_msg;
3062 if (semaphore_msg)
3063 *semaphore_msg = -1;
3064
3065 return CM_SUCCESS;
3066}
INT _semaphore_alarm
Definition midas.cxx:1462
INT _semaphore_elog
Definition midas.cxx:1463
INT _semaphore_history
Definition midas.cxx:1464
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 1830 of file midas.cxx.

1830 {
1831 std::string sdir, suser;
1833 if (status == CM_SUCCESS) {
1834 if (dir)
1835 mstrlcpy(dir, sdir.c_str(), dir_size);
1836 if (user)
1837 mstrlcpy(user, suser.c_str(), user_size);
1838 return CM_SUCCESS;
1839 }
1840 return CM_UNDEF_EXP;
1841}
int cm_get_exptab(const char *expname, std::string *dir, std::string *user)
Definition midas.cxx:1799
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 1799 of file midas.cxx.

1799 {
1800
1801 if (_exptab.exptab.size() == 0) {
1803 if (status != CM_SUCCESS)
1804 return status;
1805 }
1806
1807 for (unsigned i = 0; i < _exptab.exptab.size(); i++) {
1808 if (_exptab.exptab[i].name == expname) {
1809 if (dir)
1810 *dir = _exptab.exptab[i].directory;
1811 if (user)
1812 *user = _exptab.exptab[i].user;
1813 return CM_SUCCESS;
1814 }
1815 }
1816 if (dir)
1817 *dir = "";
1818 if (user)
1819 *user = "";
1820 return CM_UNDEF_EXP;
1821}
static exptab_struct _exptab
Definition midas.cxx:1605
INT cm_read_exptab(exptab_struct *exptab)
Definition midas.cxx:1614
std::vector< exptab_entry > exptab
Definition midas.cxx:1602
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 1788 of file midas.cxx.

1788 {
1789 return _exptab.filename;
1790}
std::string filename
Definition midas.cxx:1601
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 1783 of file midas.cxx.

1783 {
1784 mstrlcpy(s, _exptab.filename.c_str(), size);
1785 return CM_SUCCESS;
1786}
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 5851 of file midas.cxx.

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

1537 {
1538 assert(_path_name.length() > 0);
1539 return _path_name;
1540}
static std::string _path_name
Definition midas.cxx:1460
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 1518 of file midas.cxx.

1518 {
1519 // check that we were not accidentally called
1520 // with the size of the pointer to a string
1521 // instead of the size of the string buffer
1522 assert(path_size != sizeof(char *));
1523 assert(path);
1524 assert(_path_name.length() > 0);
1525
1526 mstrlcpy(path, _path_name.c_str(), path_size);
1527
1528 return CM_SUCCESS;
1529}
Here is the call graph for this function:

◆ cm_get_path_string()

INT EXPRT cm_get_path_string ( std::string *  path)

Definition at line 1545 of file midas.cxx.

1545 {
1546 assert(path != NULL);
1547 assert(_path_name.length() > 0);
1548 *path = _path_name;
1549 return CM_SUCCESS;
1550}
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 1484 of file midas.cxx.

1484 {
1485 return GIT_REVISION;
1486}
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 1476 of file midas.cxx.

1476 {
1477 return MIDAS_VERSION;
1478}
#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 3344 of file midas.cxx.

3344 {
3345 if (rpc_is_remote())
3346 return rpc_call(RPC_CM_GET_WATCHDOG_INFO, hDB, client_name, timeout, last);
3347
3348#ifdef LOCAL_ROUTINES
3349 return db_get_watchdog_info(hDB, client_name, timeout, last);
3350#else /* LOCAL_ROUTINES */
3351 return CM_SUCCESS;
3352#endif /* LOCAL_ROUTINES */
3353}
INT db_get_watchdog_info(HNDLE hDB, const char *client_name, DWORD *timeout, DWORD *last)
Definition odb.cxx:3014
#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 3325 of file midas.cxx.

3325 {
3326 if (call_watchdog)
3328 if (timeout)
3329 *timeout = _watchdog_timeout;
3330
3331 return CM_SUCCESS;
3332}
static INT _watchdog_timeout
Definition midas.cxx:1461
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 5460 of file midas.cxx.

5460 {
5461 return _ctrlc_pressed;
5462}
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 2586 of file midas.cxx.

2586 {
2587 assert(exp_names != NULL);
2588 exp_names->clear();
2589
2590 if (_exptab.exptab.size() == 0) {
2592 if (status != CM_SUCCESS)
2593 return status;
2594 }
2595
2596 for (unsigned i=0; i<_exptab.exptab.size(); i++) {
2597 exp_names->push_back(_exptab.exptab[i].name);
2598 }
2599
2600 return CM_SUCCESS;
2601}
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 2612 of file midas.cxx.

2612 {
2613 INT status;
2614 INT sock;
2615 int port = MIDAS_TCP_PORT;
2616 char hname[256];
2617 char *s;
2618
2619 assert(exp_names != NULL);
2620 exp_names->clear();
2621
2622 /* extract port number from host_name */
2623 mstrlcpy(hname, host_name, sizeof(hname));
2624 s = strchr(hname, ':');
2625 if (s) {
2626 *s = 0;
2627 port = strtoul(s + 1, NULL, 0);
2628 }
2629
2630 std::string errmsg;
2631
2632 status = ss_socket_connect_tcp(hname, port, &sock, &errmsg);
2633
2634 if (status != SS_SUCCESS) {
2635 cm_msg(MERROR, "cm_list_experiments_remote", "Cannot connect to \"%s\" port %d: %s", hname, port, errmsg.c_str());
2636 return RPC_NET_ERROR;
2637 }
2638
2639 /* request experiment list */
2640 send(sock, "I", 2, 0);
2641
2642 while (1) {
2643 char str[256];
2644
2645 status = recv_string(sock, str, sizeof(str), _rpc_connect_timeout);
2646
2647 if (status < 0)
2648 return RPC_NET_ERROR;
2649
2650 if (status == 0)
2651 break;
2652
2653 exp_names->push_back(str);
2654 }
2655
2656 ss_socket_close(&sock);
2657
2658 return CM_SUCCESS;
2659}
INT recv_string(int sock, char *buffer, DWORD buffer_size, INT millisec)
Definition system.cxx:5399
INT ss_socket_connect_tcp(const char *hostname, int tcp_port, int *sockp, std::string *error_msg_p)
Definition system.cxx:4967
INT ss_socket_close(int *sockp)
Definition system.cxx:5231
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 5587 of file midas.cxx.

5587 {
5588 static DWORD alarm_last_checked_sec = 0;
5589 DWORD now_sec = ss_time();
5590
5592 static DWORD last_millitime = 0;
5594 const DWORD kPeriod = 1000;
5595 if (last_millitime == 0) {
5597 tdiff_millitime = kPeriod; // make sure first time we come here we do something.
5598 }
5599
5600 //printf("cm_periodic_tasks! tdiff_millitime %d\n", (int)tdiff_millitime);
5601
5602 //if (now_millitime < last_millitime) {
5603 // printf("millitime wraparound 0x%08x -> 0x%08x\n", last_millitime, now_millitime);
5604 //}
5605
5606 /* check alarms once every 10 seconds */
5607 if (now_sec - alarm_last_checked_sec > 10) {
5608 al_check();
5610 }
5611
5612 /* run periodic checks previously done by cm_watchdog */
5613
5614 if (tdiff_millitime >= kPeriod) {
5616 if (tdiff_millitime > 60000)
5618
5619 //printf("millitime %u, diff %u, wrong_interval %d\n", now_millitime, tdiff_millitime, wrong_interval);
5620
5621 bm_cleanup("cm_periodic_tasks", now_millitime, wrong_interval);
5622 db_cleanup("cm_periodic_tasks", now_millitime, wrong_interval);
5623
5625
5627 }
5628
5629 /* reap transition thread */
5630
5632
5633 return CM_SUCCESS;
5634}
INT al_check()
Definition alarm.cxx:614
INT bm_write_statistics_to_odb(void)
Definition midas.cxx:7288
static void bm_cleanup(const char *who, DWORD actual_time, BOOL wrong_interval)
Definition midas.cxx:6160
INT cm_transition_cleanup()
Definition midas.cxx:5275
DWORD ss_time()
Definition system.cxx:3462
void db_cleanup(const char *who, DWORD actual_time, BOOL wrong_interval)
Definition odb.cxx:2827
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 1614 of file midas.cxx.

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

3845 {
3846 INT status, size;
3847 char tr_key_name[256];
3848 HNDLE hDB, hKey;
3849
3851
3852 for (int i = 0; _deferred_trans_table[i].transition; i++)
3854 _deferred_trans_table[i].func = (int (*)(int, char *)) func;
3855
3856 /* set new transition mask */
3858
3859 sprintf(tr_key_name, "Transition %s DEFERRED", cm_transition_name(transition).c_str());
3860
3861 /* unlock database */
3863
3864 /* set value */
3865 int i = 0;
3866 status = db_set_value(hDB, hKey, tr_key_name, &i, sizeof(INT), 1, TID_INT32);
3867 if (status != DB_SUCCESS)
3868 return status;
3869
3870 /* re-lock database */
3872
3873 /* hot link requested transition */
3874 size = sizeof(_requested_transition);
3875 db_get_value(hDB, 0, "/Runinfo/Requested Transition", &_requested_transition, &size, TID_INT32, TRUE);
3876 db_find_key(hDB, 0, "/Runinfo/Requested Transition", &hKey);
3878 if (status != DB_SUCCESS) {
3879 cm_msg(MERROR, "cm_register_deferred_transition", "Cannot hotlink /Runinfo/Requested Transition");
3880 return status;
3881 }
3882
3883 return CM_SUCCESS;
3884}
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:13292
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:5261
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 5798 of file midas.cxx.

5818{
5819 HNDLE hDB, hKey;
5820 INT status;
5821 char str[80];
5822
5823 status = rpc_register_function(id, func);
5824 if (status != RPC_SUCCESS)
5825 return status;
5826
5828
5829 /* create new key for this id */
5830 status = 1;
5831 sprintf(str, "RPC/%d", id);
5832
5834 status = db_set_value(hDB, hKey, str, &status, sizeof(BOOL), 1, TID_BOOL);
5836
5837 if (status != DB_SUCCESS)
5838 return status;
5839
5840 return CM_SUCCESS;
5841}
INT rpc_register_function(INT id, INT(*func)(INT, void **))
Definition midas.cxx:11905
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 3460 of file midas.cxx.

3478{
3479 if (!_rpc_registered) {
3480 INT status;
3481 int size;
3482 HNDLE hDB, hKey;
3483 char name[NAME_LENGTH];
3484 char str[256];
3485 int port = 0;
3486
3488
3489 size = sizeof(name);
3490 status = db_get_value(hDB, hKey, "Name", &name, &size, TID_STRING, FALSE);
3491
3492 if (status != DB_SUCCESS) {
3493 cm_msg(MERROR, "cm_register_server", "cannot get client name, db_get_value() status %d", status);
3494 return status;
3495 }
3496
3497 mstrlcpy(str, "/Experiment/Security/RPC ports/", sizeof(str));
3498 mstrlcat(str, name, sizeof(str));
3499
3500 size = sizeof(port);
3501 status = db_get_value(hDB, 0, str, &port, &size, TID_UINT32, TRUE);
3502
3503 if (status != DB_SUCCESS) {
3504 cm_msg(MERROR, "cm_register_server", "cannot get RPC port number, db_get_value(%s) status %d", str, status);
3505 return status;
3506 }
3507
3508 int lport = 0; // actual port number assigned to us by the OS
3509
3511 if (status != RPC_SUCCESS) {
3512 cm_msg(MERROR, "cm_register_server", "error, rpc_register_server(port=%d) status %d", port, status);
3513 return status;
3514 }
3515
3517
3518 /* register MIDAS library functions */
3520
3521 /* store port number in ODB */
3522
3523 status = db_find_key(hDB, hKey, "Server Port", &hKey);
3524 if (status != DB_SUCCESS) {
3525 cm_msg(MERROR, "cm_register_server", "error, db_find_key(\"Server Port\") status %d", status);
3526 return status;
3527 }
3528
3529 /* unlock database */
3531
3532 /* set value */
3533 status = db_set_data(hDB, hKey, &lport, sizeof(INT), 1, TID_INT32);
3534 if (status != DB_SUCCESS) {
3535 cm_msg(MERROR, "cm_register_server", "error, db_set_data(\"Server Port\"=%d) status %d", port, status);
3536 return status;
3537 }
3538
3539 /* lock database */
3541
3543 }
3544
3545 return CM_SUCCESS;
3546}
static void init_rpc_hosts(HNDLE hDB)
Definition midas.cxx:3412
INT db_set_data(HNDLE hDB, HNDLE hKey, const void *data, INT buf_size, INT num_values, DWORD type)
Definition odb.cxx:7215
INT rpc_register_server(int port, int *plsock, int *pport)
Definition midas.cxx:14546
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:3601
INT cm_yield(INT millisec)
Definition midas.cxx:5650
#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 3601 of file midas.cxx.

3601 {
3602 INT status;
3604 KEY key;
3605 char str[256];
3606
3607 /* check for valid transition */
3609 cm_msg(MERROR, "cm_register_transition", "Invalid transition request \"%d\"", transition);
3610 return CM_INVALID_TRANSITION;
3611 }
3612
3614
3616
3617 /* register new transition request */
3618
3619 {
3620 std::lock_guard<std::mutex> guard(_trans_table_mutex);
3621
3622 for (size_t i = 0; i < _trans_table.size(); i++) {
3623 if (_trans_table[i].transition == transition && _trans_table[i].sequence_number == sequence_number) {
3624 cm_msg(MERROR, "cm_register_transition", "transition %s with sequence number %d is already registered", cm_transition_name(transition).c_str(), sequence_number);
3625 return CM_INVALID_TRANSITION;
3626 }
3627 }
3628
3629 bool found = false;
3630 for (size_t i = 0; i < _trans_table.size(); i++) {
3631 if (!_trans_table[i].transition) {
3632 _trans_table[i].transition = transition;
3633 _trans_table[i].sequence_number = sequence_number;
3634 _trans_table[i].func = func;
3635 found = true;
3636 break;
3637 }
3638 }
3639
3640 if (!found) {
3643 tt.sequence_number = sequence_number;
3644 tt.func = func;
3645 _trans_table.push_back(tt);
3646 }
3647
3648 // implicit unlock
3649 }
3650
3651 sprintf(str, "Transition %s", cm_transition_name(transition).c_str());
3652
3653 /* unlock database */
3655
3656 /* set value */
3658 if (!hKeyTrans) {
3659 status = db_set_value(hDB, hKey, str, &sequence_number, sizeof(INT), 1, TID_INT32);
3660 if (status != DB_SUCCESS)
3661 return status;
3662 } else {
3664 if (status != DB_SUCCESS)
3665 return status;
3666 status = db_set_data_index(hDB, hKeyTrans, &sequence_number, sizeof(INT), key.num_values, TID_INT32);
3667 if (status != DB_SUCCESS)
3668 return status;
3669 }
3670
3671 /* re-lock database */
3673
3674 return CM_SUCCESS;
3675}
INT db_set_data_index(HNDLE hDB, HNDLE hKey, const void *data, INT data_size, INT idx, DWORD type)
Definition odb.cxx:7648
#define RPC_RC_TRANSITION
Definition mrpc.h:116
static INT rpc_transition_dispatch(INT idx, void *prpc_param[])
Definition midas.cxx:14064
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 2670 of file midas.cxx.

2670 {
2671 INT status;
2673
2674 assert(exp_name != NULL);
2675
2676 /* retrieve list of experiments and make selection */
2678 if (status != CM_SUCCESS)
2679 return status;
2680
2681 if (expts.size() == 1) {
2682 *exp_name = expts[0];
2683 } else if (expts.size() > 1) {
2684 printf("Available experiments on local computer:\n");
2685
2686 for (unsigned i = 0; i < expts.size(); i++) {
2687 printf("%d : %s\n", i, expts[i].c_str());
2688 }
2689
2690 while (1) {
2691 printf("Select number from 0 to %d: ", ((int)expts.size())-1);
2692 char str[32];
2693 ss_gets(str, 32);
2694 int isel = atoi(str);
2695 if (isel < 0)
2696 continue;
2697 if (isel >= (int)expts.size())
2698 continue;
2699 *exp_name = expts[isel];
2700 break;
2701 }
2702 } else {
2703 return CM_UNDEF_EXP;
2704 }
2705
2706 return CM_SUCCESS;
2707}
INT cm_list_experiments_local(STRING_LIST *exp_names)
Definition midas.cxx:2586
char * ss_gets(char *string, int size)
Definition system.cxx:7776
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 2719 of file midas.cxx.

2719 {
2720 INT status;
2722
2723 assert(exp_name != NULL);
2724
2725 /* retrieve list of experiments and make selection */
2727 if (status != CM_SUCCESS)
2728 return status;
2729
2730 if (expts.size() > 1) {
2731 printf("Available experiments on server %s:\n", host_name);
2732
2733 for (unsigned i = 0; i < expts.size(); i++) {
2734 printf("%d : %s\n", i, expts[i].c_str());
2735 }
2736
2737 while (1) {
2738 printf("Select number from 0 to %d: ", ((int)expts.size())-1);
2739 char str[32];
2740 ss_gets(str, 32);
2741 int isel = atoi(str);
2742 if (isel < 0)
2743 continue;
2744 if (isel >= (int)expts.size())
2745 continue;
2746 *exp_name = expts[isel];
2747 break;
2748 }
2749 } else {
2750 *exp_name = expts[0];
2751 }
2752
2753 return CM_SUCCESS;
2754}
INT cm_list_experiments_remote(const char *host_name, STRING_LIST *exp_names)
Definition midas.cxx:2612
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 1893 of file midas.cxx.

1894 {
1895 if (rpc_is_remote())
1897 host_name, client_name, hw_type, password, watchdog_timeout);
1898
1899#ifdef LOCAL_ROUTINES
1900 {
1901 INT status, pid, data, i, idx, size;
1906
1907 /* check security if password is present */
1908 status = db_find_key(hDB, 0, "/Experiment/Security/Password", &hKey);
1909 if (hKey) {
1910 /* get password */
1911 size = sizeof(pwd);
1912 db_get_data(hDB, hKey, pwd, &size, TID_STRING);
1913
1914 /* first check allowed hosts list */
1915 allow = FALSE;
1916 db_find_key(hDB, 0, "/Experiment/Security/Allowed hosts", &hKey);
1918 allow = TRUE;
1919
1920 /* check allowed programs list */
1921 db_find_key(hDB, 0, "/Experiment/Security/Allowed programs", &hKey);
1922 if (hKey && db_find_key(hDB, hKey, client_name, &hKey) == DB_SUCCESS)
1923 allow = TRUE;
1924
1925 /* now check password */
1926 if (!allow && strcmp(password, pwd) != 0) {
1927 if (password[0])
1928 cm_msg(MINFO, "cm_set_client_info", "Wrong password for host %s", host_name);
1929 return CM_WRONG_PASSWORD;
1930 }
1931 }
1932
1933 /* make following operation atomic by locking database */
1935
1936 /* check if entry with this pid exists already */
1937 pid = ss_getpid();
1938
1939 sprintf(str, "System/Clients/%0d", pid);
1940 status = db_find_key(hDB, 0, str, &hKey);
1941 if (status == DB_SUCCESS) {
1944 }
1945
1946 if (strlen(client_name) >= NAME_LENGTH)
1947 client_name[NAME_LENGTH] = 0;
1948
1949 strcpy(name, client_name);
1950 strcpy(orig_name, client_name);
1951
1952 /* check if client name already exists */
1953 status = db_find_key(hDB, 0, "System/Clients", &hKey);
1954
1955 for (idx = 1; status != DB_NO_MORE_SUBKEYS; idx++) {
1956 for (i = 0;; i++) {
1959 break;
1960
1961 if (status == DB_SUCCESS) {
1962 size = sizeof(str);
1963 status = db_get_value(hDB, hSubkey, "Name", str, &size, TID_STRING, FALSE);
1964 if (status != DB_SUCCESS)
1965 continue;
1966 }
1967
1968 /* check if client is living */
1970 continue;
1971
1972 if (equal_ustring(str, name)) {
1973 sprintf(name, "%s%d", client_name, idx);
1974 break;
1975 }
1976 }
1977 }
1978
1979 /* set name */
1980 sprintf(str, "System/Clients/%0d/Name", pid);
1982 if (status != DB_SUCCESS) {
1984 cm_msg(MERROR, "cm_set_client_info", "cannot set client name, db_set_value(%s) status %d", str, status);
1985 return status;
1986 }
1987
1988 /* copy new client name */
1989 strcpy(client_name, name);
1990 db_set_client_name(hDB, client_name);
1991
1992 /* set also as rpc name */
1993 rpc_set_name(client_name);
1994
1995 /* use /system/clients/PID as root */
1996 sprintf(str, "System/Clients/%0d", pid);
1997 db_find_key(hDB, 0, str, &hKey);
1998
1999 /* set host name */
2001 if (status != DB_SUCCESS) {
2003 return status;
2004 }
2005
2006 /* set computer id */
2007 status = db_set_value(hDB, hKey, "Hardware type", &hw_type, sizeof(hw_type), 1, TID_INT32);
2008 if (status != DB_SUCCESS) {
2010 return status;
2011 }
2012
2013 /* set server port */
2014 data = 0;
2015 status = db_set_value(hDB, hKey, "Server Port", &data, sizeof(INT), 1, TID_INT32);
2016 if (status != DB_SUCCESS) {
2018 return status;
2019 }
2020
2021 /* lock client entry */
2023
2024 /* get (set) default watchdog timeout */
2025 size = sizeof(watchdog_timeout);
2026 sprintf(str, "/Programs/%s/Watchdog Timeout", orig_name);
2027 db_get_value(hDB, 0, str, &watchdog_timeout, &size, TID_INT32, TRUE);
2028
2029 /* define /programs entry */
2030 sprintf(str, "/Programs/%s", orig_name);
2032
2033 /* save handle for ODB and client */
2035
2036 /* save watchdog timeout */
2038 cm_set_watchdog_params(call_watchdog, watchdog_timeout);
2039
2040 /* end of atomic operations */
2042
2043 /* touch notify key to inform others */
2044 data = 0;
2045 db_set_value(hDB, 0, "/System/Client Notify", &data, sizeof(data), 1, TID_INT32);
2046
2047 *hKeyClient = hKey;
2048 }
2049#endif /* LOCAL_ROUTINES */
2050
2051 return CM_SUCCESS;
2052}
INT cm_check_client(HNDLE hDB, HNDLE hKeyClient)
Definition midas.cxx:1869
std::string strcomb1(const char **list)
Definition odb.cxx:598
INT db_set_client_name(HNDLE hDB, const char *client_name)
Definition odb.cxx:2402
INT db_create_record(HNDLE hDB, HNDLE hKey, const char *orig_key_name, const char *init_str)
Definition odb.cxx:12801
#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 3791 of file midas.cxx.

3791 {
3792 INT status;
3793 HNDLE hDB, hKey;
3794 KEY key;
3795
3797
3798 /* check that hKey is still valid */
3800
3801 if (status != DB_SUCCESS) {
3802 cm_msg(MERROR, "cm_set_client_run_state",
3803 "Cannot set client run state, client hKey %d into /System/Clients is not valid, maybe this client was removed by a watchdog timeout",
3804 hKey);
3805 return status;
3806 }
3807
3808 /* unlock database */
3810
3811 /* set value */
3812 status = db_set_value(hDB, hKey, "Run state", &state, sizeof(INT), 1, TID_INT32);
3813 if (status != DB_SUCCESS)
3814 return status;
3815
3816 /* re-lock database */
3818
3819 return CM_SUCCESS;
3820
3821}
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 2939 of file midas.cxx.

2939 {
2940 //printf("cm_set_experiment_database: hDB %d, hKeyClient %d\n", hDB, hKeyClient);
2941
2942 _hDB = hDB;
2944
2945 //if (hDB == 0) {
2946 // rpc_set_server_option(RPC_ODB_HANDLE, 0);
2947 //}
2948
2949 return CM_SUCCESS;
2950}
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 2166 of file midas.cxx.

2167{
2168 std::string exp_name1;
2169
2170 if ((exp_name != NULL) && (strlen(exp_name) > 0)) {
2172 } else {
2174 if (status != CM_SUCCESS)
2175 return status;
2176 }
2177
2178 std::string expdir, expuser;
2179
2180 int status = cm_get_exptab(exp_name1.c_str(), &expdir, &expuser);
2181
2182 if (status != CM_SUCCESS) {
2183 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());
2184 return CM_UNDEF_EXP;
2185 }
2186
2187 if (!ss_dir_exist(expdir.c_str())) {
2188 cm_msg(MERROR, "cm_set_experiment_local", "Experiment \"%s\" directory \"%s\" does not exist", exp_name1.c_str(), expdir.c_str());
2189 return CM_UNDEF_EXP;
2190 }
2191
2193 cm_set_path(expdir.c_str());
2194
2195 return CM_SUCCESS;
2196}
INT cm_set_path(const char *path)
Definition midas.cxx:1497
INT cm_select_experiment_local(std::string *exp_name)
Definition midas.cxx:2670
std::string cm_get_exptab_filename()
Definition midas.cxx:1788
int ss_dir_exist(const char *path)
Definition system.cxx:7192
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 1558 of file midas.cxx.

1558 {
1560 return CM_SUCCESS;
1561}
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 2958 of file midas.cxx.

2978{
2982 //_semaphore_msg = semaphore_msg;
2983
2984 return CM_SUCCESS;
2985}
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 1497 of file midas.cxx.

1497 {
1498 assert(path);
1499 assert(path[0] != 0);
1500
1501 _path_name = path;
1502
1503 if (_path_name.back() != DIR_SEPARATOR) {
1505 }
1506
1507 //printf("cm_set_path [%s]\n", _path_name.c_str());
1508
1509 return CM_SUCCESS;
1510}
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 3731 of file midas.cxx.

3731 {
3732 INT status;
3733 HNDLE hDB, hKey;
3734 char str[256];
3735
3736 /* check for valid transition */
3738 cm_msg(MERROR, "cm_set_transition_sequence", "Invalid transition request \"%d\"", transition);
3739 return CM_INVALID_TRANSITION;
3740 }
3741
3742 {
3743 std::lock_guard<std::mutex> guard(_trans_table_mutex);
3744
3745 int count = 0;
3746 for (size_t i = 0; i < _trans_table.size(); i++) {
3748 _trans_table[i].sequence_number = sequence_number;
3749 count++;
3750 }
3751 }
3752
3753 if (count == 0) {
3754 cm_msg(MERROR, "cm_set_transition_sequence", "transition %s is not registered", cm_transition_name(transition).c_str());
3755 return CM_INVALID_TRANSITION;
3756 } else if (count > 1) {
3757 cm_msg(MERROR, "cm_set_transition_sequence", "cannot change sequence number, transition %s is registered %d times", cm_transition_name(transition).c_str(), count);
3758 return CM_INVALID_TRANSITION;
3759 }
3760
3761 /* Change local sequence number for this transition type */
3762
3763 for (size_t i = 0; i < _trans_table.size(); i++) {
3765 _trans_table[i].sequence_number = sequence_number;
3766 }
3767 }
3768
3769 // implicit unlock
3770 }
3771
3773
3774 /* unlock database */
3776
3777 sprintf(str, "Transition %s", cm_transition_name(transition).c_str());
3778
3779 /* set value */
3780 status = db_set_value(hDB, hKey, str, &sequence_number, sizeof(INT), 1, TID_INT32);
3781 if (status != DB_SUCCESS)
3782 return status;
3783
3784 /* re-lock database */
3786
3787 return CM_SUCCESS;
3788
3789}
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 3283 of file midas.cxx.

3284{
3285 /* set also local timeout to requested value (needed by cm_enable_watchdog()) */
3286 _watchdog_timeout = timeout;
3287
3288 if (rpc_is_remote()) { // we are connected remotely
3289
3291
3292 } else if (rpc_is_mserver()) { // we are the mserver
3293
3295 if (sa)
3296 sa->watchdog_timeout = timeout;
3297
3298 /* write timeout value to client entry in ODB */
3299 HNDLE hDB, hKey;
3301
3302 if (hDB) {
3304 db_set_value(hDB, hKey, "Link timeout", &timeout, sizeof(timeout), 1, TID_INT32);
3306 }
3307
3308 /* set the watchdog for the local mserver program */
3310
3311 } else { // only running locally
3312
3314
3315 }
3316}
INT cm_set_watchdog_params_local(BOOL call_watchdog, DWORD timeout)
Definition midas.cxx:3244
RPC_SERVER_ACCEPTION * rpc_get_mserver_acception()
Definition midas.cxx:11521
#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 3244 of file midas.cxx.

3245{
3246#ifdef LOCAL_ROUTINES
3247 _watchdog_timeout = timeout;
3248
3249 std::vector<BUFFER*> mybuffers;
3250
3251 gBuffersMutex.lock();
3253 gBuffersMutex.unlock();
3254
3255 /* set watchdog timeout of all open buffers */
3256 for (BUFFER* pbuf : mybuffers) {
3257
3258 if (!pbuf || !pbuf->attached)
3259 continue;
3260
3262
3263 if (!pbuf_guard.is_locked())
3264 continue;
3265
3267
3268 /* clear entry from client structure in buffer header */
3269 pclient->watchdog_timeout = timeout;
3270
3271 /* show activity */
3272 pclient->last_activity = ss_millitime();
3273 }
3274
3275 /* set watchdog timeout for ODB */
3276 db_set_watchdog_params(timeout);
3277
3278#endif /* LOCAL_ROUTINES */
3279
3280 return CM_SUCCESS;
3281}
void db_set_watchdog_params(DWORD timeout)
Definition odb.cxx:2976
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 7408 of file midas.cxx.

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

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

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

1369 {
1370 INT sec, status;
1371
1372 /* if connected to server, get time from there */
1373 if (rpc_is_remote()) {
1375
1376 /* set local time */
1377 if (status == CM_SUCCESS)
1378 ss_settime(sec);
1379 }
1380
1381 /* return time to caller */
1382 if (seconds != NULL) {
1383 *seconds = ss_time();
1384 }
1385
1386 return CM_SUCCESS;
1387}
DWORD ss_settime(DWORD seconds)
Definition system.cxx:3475
#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 7765 of file midas.cxx.

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

1434 {
1435 /* if connected to server, get time from there */
1436 if (rpc_is_remote())
1437 return rpc_call(RPC_CM_TIME, t);
1438
1439 /* return local time */
1440 *t = ss_time();
1441
1442 return CM_SUCCESS;
1443}
#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 5294 of file midas.cxx.

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

5246 {
5247 int status;
5248
5249 status = cm_transition2(transition, run_number, errstr, errstr_size, async_flag, debug_flag);
5250
5251 if (transition == TR_START && status != CM_SUCCESS) {
5252 cm_msg(MERROR, "cm_transition", "Could not start a run: cm_transition() status %d, message \'%s\'", status,
5253 errstr);
5254 cm_transition2(TR_STARTABORT, run_number, NULL, 0, async_flag, debug_flag);
5255 }
5256
5257 return status;
5258}
static INT cm_transition2(INT transition, INT run_number, char *errstr, INT errstr_size, INT async_flag, INT debug_flag)
Definition midas.cxx:4531
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 4531 of file midas.cxx.

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

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

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

5276{
5277 if (_trp.thread && !_trp.finished) {
5278 //printf("main transition thread did not finish yet!\n");
5280 }
5281
5282 std::thread* t = _trp.thread.exchange(NULL);
5283
5284 if (t) {
5285 t->join();
5286 delete t;
5287 t = NULL;
5288 }
5289
5290 return CM_SUCCESS;
5291}
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 4090 of file midas.cxx.

4090 {
4091 HNDLE hDB;
4092 int status;
4093 const char *args[100];
4094 std::string path;
4095 char debug_arg[256];
4096 char start_arg[256];
4097 std::string expt_name;
4098 std::string mserver_hostname;
4099
4100 int iarg = 0;
4101
4103
4104 const char *midassys = getenv("MIDASSYS");
4105 if (midassys) {
4106 path += midassys;
4107 path += DIR_SEPARATOR_STR;
4108 path += "bin";
4109 path += DIR_SEPARATOR_STR;
4110 }
4111 path += "mtransition";
4112
4113 args[iarg++] = path.c_str();
4114
4115 if (rpc_is_remote()) {
4116 /* if connected to mserver, pass connection info to mtransition */
4118 args[iarg++] = "-h";
4119 args[iarg++] = mserver_hostname.c_str();
4120 }
4121
4122 /* get experiment name from ODB */
4123 db_get_value_string(hDB, 0, "/Experiment/Name", 0, &expt_name, FALSE);
4124
4125 if (expt_name.length() > 0) {
4126 args[iarg++] = "-e";
4127 args[iarg++] = expt_name.c_str();
4128 }
4129
4130 if (debug_flag) {
4131 args[iarg++] = "-d";
4132
4133 sprintf(debug_arg, "%d", debug_flag);
4134 args[iarg++] = debug_arg;
4135 }
4136
4137 if (transition == TR_STOP)
4138 args[iarg++] = "STOP";
4139 else if (transition == TR_PAUSE)
4140 args[iarg++] = "PAUSE";
4141 else if (transition == TR_RESUME)
4142 args[iarg++] = "RESUME";
4143 else if (transition == TR_START) {
4144 args[iarg++] = "START";
4145
4147 args[iarg++] = start_arg;
4148 }
4149
4150 args[iarg++] = NULL;
4151
4152#if 0
4153 for (iarg = 0; args[iarg] != NULL; iarg++) {
4154 printf("arg[%d] [%s]\n", iarg, args[iarg]);
4155 }
4156#endif
4157
4159
4160 if (status != SS_SUCCESS) {
4161 if (errstr != NULL) {
4162 sprintf(errstr, "Cannot execute mtransition, ss_spawnv() returned %d", status);
4163 }
4164 return CM_SET_ERROR;
4165 }
4166
4167 return CM_SUCCESS;
4168}
INT ss_spawnv(INT mode, const char *cmdname, const char *const argv[])
Definition system.cxx:1630
std::string rpc_get_mserver_hostname(void)
Definition midas.cxx:12813
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 7337 of file midas.cxx.

7337 {
7339 //printf("cm_watchdog_thread started!\n");
7340 while (_watchdog_thread_run) {
7341 //printf("cm_watchdog_thread runs!\n");
7345 int i;
7346 for (i = 0; i < 20; i++) {
7347 ss_sleep(100);
7349 break;
7350 }
7351 }
7352 //printf("cm_watchdog_thread stopped!\n");
7354 return 0;
7355}
static void bm_update_last_activity(DWORD millitime)
Definition midas.cxx:6125
INT db_update_last_activity(DWORD millitime)
Definition odb.cxx:2692
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 5650 of file midas.cxx.

5650 {
5651 INT status;
5652 INT bMore;
5653 //static DWORD last_yield = 0;
5654 //static DWORD last_yield_time = 0;
5655 //DWORD start_yield = ss_millitime();
5656
5657 /* check for ctrl-c */
5658 if (_ctrlc_pressed)
5659 return RPC_SHUTDOWN;
5660
5661 /* flush the cm_msg buffer */
5663
5664 if (!rpc_is_remote()) {
5665 /* flush the ODB to its binary file */
5666 /* for remote clients, ODB is flushed by the mserver */
5667 HNDLE hDB;
5670 }
5671
5672 /* check for available events */
5673 if (rpc_is_remote()) {
5674 //printf("cm_yield() calling bm_poll_event()\n");
5676
5677 if (status == SS_ABORT) {
5678 return status;
5679 }
5680
5681 if (status == BM_SUCCESS) {
5682 /* one or more events received by bm_poll_event() */
5683 status = ss_suspend(0, 0);
5684 } else {
5686 }
5687
5688 return status;
5689 }
5690
5692
5693 if (status != CM_SUCCESS)
5694 return status;
5695
5696 //DWORD start_check = ss_millitime();
5697
5699
5700 //DWORD end_check = ss_millitime();
5701 //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);
5702 //fflush(stdout);
5703
5704 if (bMore == BM_CORRUPTED) {
5705 status = SS_ABORT;
5706 } else if (bMore) {
5707 /* if events available, quickly check other IPC channels */
5708 status = ss_suspend(0, 0);
5709 } else {
5711 }
5712
5713 /* flush the cm_msg buffer */
5715
5716 //DWORD end_yield = ss_millitime();
5717 //last_yield_time = end_yield - start_yield;
5718 //last_yield = start_yield;
5719
5720 return status;
5721}
INT bm_poll_event()
Definition midas.cxx:11134
INT bm_check_buffers()
Definition midas.cxx:10962
INT cm_periodic_tasks()
Definition midas.cxx:5587
#define BM_CORRUPTED
Definition midas.h:623
INT ss_suspend(INT millisec, INT msg)
Definition system.cxx:4543
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 3412 of file midas.cxx.

3412 {
3413 int status;
3414 char buf[256];
3415 int size, i;
3416 HNDLE hKey;
3417
3418 strcpy(buf, "localhost");
3419 size = sizeof(buf);
3420
3421 status = db_get_value(hDB, 0, "/Experiment/Security/RPC hosts/Allowed hosts[0]", buf, &size, TID_STRING, TRUE);
3422
3423 if (status != DB_SUCCESS) {
3424 cm_msg(MERROR, "init_rpc_hosts", "Cannot create the RPC hosts access control list, db_get_value() status %d",
3425 status);
3426 return;
3427 }
3428
3429 size = sizeof(i);
3430 i = 0;
3431 status = db_get_value(hDB, 0, "/Experiment/Security/Disable RPC hosts check", &i, &size, TID_BOOL, TRUE);
3432
3433 if (status != DB_SUCCESS) {
3434 cm_msg(MERROR, "init_rpc_hosts", "Cannot create \"Disable RPC hosts check\", db_get_value() status %d", status);
3435 return;
3436 }
3437
3438 if (i != 0) // RPC hosts check is disabled
3439 return;
3440
3441 status = db_find_key(hDB, 0, "/Experiment/Security/RPC hosts/Allowed hosts", &hKey);
3442
3443 if (status != DB_SUCCESS || hKey == 0) {
3444 cm_msg(MERROR, "init_rpc_hosts", "Cannot find the RPC hosts access control list, db_find_key() status %d",
3445 status);
3446 return;
3447 }
3448
3449 load_rpc_hosts(hDB, hKey, -99, NULL);
3450
3452
3453 if (status != DB_SUCCESS) {
3454 cm_msg(MERROR, "init_rpc_hosts", "Cannot watch the RPC hosts access control list, db_watch() status %d", status);
3455 return;
3456 }
3457}
static void load_rpc_hosts(HNDLE hDB, HNDLE hKey, int index, void *info)
Definition midas.cxx:3361
INT db_watch(HNDLE hDB, HNDLE hKey, void(*dispatcher)(INT, INT, INT, void *), void *info)
Definition odb.cxx:13814
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 3361 of file midas.cxx.

3361 {
3362 int status;
3363 int i, last;
3364 KEY key;
3365 int max_size;
3366 char *str;
3367
3368// if (index != -99)
3369// cm_msg(MINFO, "load_rpc_hosts", "Reloading RPC hosts access control list via hotlink callback");
3370
3372
3373 if (status != DB_SUCCESS)
3374 return;
3375
3376 //printf("clear rpc hosts!\n");
3378
3380 str = (char *) malloc(max_size);
3381
3382 last = 0;
3383 for (i = 0; i < key.num_values; i++) {
3384 int size = max_size;
3386 if (status != DB_SUCCESS)
3387 break;
3388
3389 if (strlen(str) < 1) // skip emties
3390 continue;
3391
3392 if (str[0] == '#') // skip commented-out entries
3393 continue;
3394
3395 //printf("add rpc hosts %d [%s]\n", i, str);
3397 last = i;
3398 }
3399
3400 if (key.num_values - last < 10) {
3401 int new_size = last + 10;
3403 if (status != DB_SUCCESS) {
3404 cm_msg(MERROR, "load_rpc_hosts",
3405 "Cannot resize the RPC hosts access control list, db_set_num_values(%d) status %d", new_size, status);
3406 }
3407 }
3408
3409 free(str);
3410}
INT db_set_num_values(HNDLE hDB, HNDLE hKey, INT num_values)
Definition odb.cxx:7502
INT rpc_add_allowed_host(const char *hostname)
Definition midas.cxx:15243
INT rpc_clear_allowed_hosts()
Definition midas.cxx:15218
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 12640 of file midas.cxx.

12641{
12642 /* close all open connections */
12643
12645
12646 for (unsigned i = 0; i < _client_connections.size(); i++) {
12648 if (c && c->connected) {
12649 int index = c->index;
12650 // must unlock the array, otherwise we hang -
12651 // rpc_client_disconnect() will do rpc_call_client()
12652 // which needs to lock the array to convert handle
12653 // to connection pointer. Ouch! K.O. Dec 2020.
12657 }
12658 }
12659
12660 for (unsigned i = 0; i < _client_connections.size(); i++) {
12662 //printf("client connection %d %p\n", i, c);
12663 if (c) {
12664 //printf("client connection %d %p connected %d\n", i, c, c->connected);
12665 if (!c->connected) {
12666 delete c;
12668 }
12669 }
12670 }
12671
12673
12674 /* close server connection from other clients */
12675 for (unsigned i = 0; i < _server_acceptions.size(); i++) {
12676 if (_server_acceptions[i] && _server_acceptions[i]->recv_sock) {
12677 send(_server_acceptions[i]->recv_sock, "EXIT", 5, 0);
12678 _server_acceptions[i]->close();
12679 }
12680 }
12681}
static std::mutex _client_connections_mutex
Definition midas.cxx:11503
static std::vector< RPC_CLIENT_CONNECTION * > _client_connections
Definition midas.cxx:11504
static std::vector< RPC_SERVER_ACCEPTION * > _server_acceptions
Definition midas.cxx:11510
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 7750 of file midas.cxx.

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

3984 {
3985 return arg1->sequence_number < arg2->sequence_number;
3986}
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 4004 of file midas.cxx.

4005{
4006 DWORD end_time = ss_millitime();
4007
4008 if (transition != TR_STARTABORT) {
4009 db_set_value(hDB, 0, "/System/Transition/end_time", &end_time, sizeof(DWORD), 1, TID_UINT32);
4010 db_set_value(hDB, 0, "/System/Transition/status", &status, sizeof(INT), 1, TID_INT32);
4011
4012 if (errorstr) {
4013 db_set_value(hDB, 0, "/System/Transition/error", errorstr, strlen(errorstr) + 1, 1, TID_STRING);
4014 } else if (status == CM_SUCCESS) {
4015 const char *buf = "Success";
4016 db_set_value(hDB, 0, "/System/Transition/error", buf, strlen(buf) + 1, 1, TID_STRING);
4017 } else {
4018 char buf[256];
4019 sprintf(buf, "status %d", status);
4020 db_set_value(hDB, 0, "/System/Transition/error", buf, strlen(buf) + 1, 1, TID_STRING);
4021 }
4022 }
4023
4024 tr->status = status;
4025 tr->end_time = end_time;
4026 if (errorstr) {
4027 tr->errorstr = errorstr;
4028 } else {
4029 tr->errorstr = "(null)";
4030 }
4031
4032 return status;
4033}
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 5262 of file midas.cxx.

5262 {
5263 INT status;
5264 TR_PARAM *trp;
5265
5266 trp = (TR_PARAM *) param;
5267 status = cm_transition1(trp->transition, trp->run_number, trp->errstr, trp->errstr_size, trp->async_flag, trp->debug_flag);
5268
5269 trp->status = status;
5270 trp->finished = TRUE;
5271
5272 return 0;
5273}
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 4037 of file midas.cxx.

4037 {
4038 //printf("Writing client [%s] to ODB\n", tr_client->client_name.c_str());
4039
4040 int status;
4041 HNDLE hKey;
4042
4043 if (tr_client->transition == TR_STARTABORT) {
4044 status = db_create_key(hDB, 0, "/System/Transition/TR_STARTABORT", TID_KEY);
4045 status = db_find_key(hDB, 0, "/System/Transition/TR_STARTABORT", &hKey);
4046 if (status != DB_SUCCESS)
4047 return;
4048 } else {
4049 status = db_create_key(hDB, 0, "/System/Transition/Clients", TID_KEY);
4050 status = db_find_key(hDB, 0, "/System/Transition/Clients", &hKey);
4051 if (status != DB_SUCCESS)
4052 return;
4053 }
4054
4055 // same client_name can exist with different sequence numbers!
4056 std::string keyname = msprintf("%s_%d", tr_client->client_name.c_str(), tr_client->sequence_number);
4057
4059 status = db_find_key(hDB, hKey, keyname.c_str(), &hKey);
4060 if (status != DB_SUCCESS)
4061 return;
4062
4064
4065 //int transition;
4066 //int run_number;
4067 //int async_flag;
4068 //int debug_flag;
4069 status = db_set_value(hDB, hKey, "sequence_number", &tr_client->sequence_number, sizeof(INT), 1, TID_INT32);
4070 status = db_set_value(hDB, hKey, "client_name", tr_client->client_name.c_str(), tr_client->client_name.length() + 1, 1, TID_STRING);
4071 status = db_set_value(hDB, hKey, "host_name", tr_client->host_name.c_str(), tr_client->host_name.length() + 1, 1, TID_STRING);
4072 status = db_set_value(hDB, hKey, "port", &tr_client->port, sizeof(INT), 1, TID_INT32);
4073 status = db_set_value(hDB, hKey, "init_time", &tr_client->init_time, sizeof(DWORD), 1, TID_UINT32);
4074 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);
4075 status = db_set_value(hDB, hKey, "connect_timeout", &tr_client->connect_timeout, sizeof(DWORD), 1, TID_UINT32);
4076 status = db_set_value(hDB, hKey, "connect_start_time", &tr_client->connect_start_time, sizeof(DWORD), 1, TID_UINT32);
4077 status = db_set_value(hDB, hKey, "connect_end_time", &tr_client->connect_end_time, sizeof(DWORD), 1, TID_UINT32);
4078 status = db_set_value(hDB, hKey, "rpc_timeout", &tr_client->rpc_timeout, sizeof(DWORD), 1, TID_UINT32);
4079 status = db_set_value(hDB, hKey, "rpc_start_time", &tr_client->rpc_start_time, sizeof(DWORD), 1, TID_UINT32);
4080 status = db_set_value(hDB, hKey, "rpc_end_time", &tr_client->rpc_end_time, sizeof(DWORD), 1, TID_UINT32);
4081 status = db_set_value(hDB, hKey, "end_time", &tr_client->end_time, sizeof(DWORD), 1, TID_UINT32);
4082 status = db_set_value(hDB, hKey, "status", &tr_client->status, sizeof(INT), 1, TID_INT32);
4083 status = db_set_value(hDB, hKey, "error", tr_client->errorstr.c_str(), tr_client->errorstr.length() + 1, 1, TID_STRING);
4084 status = db_set_value(hDB, hKey, "last_updated", &now, sizeof(DWORD), 1, TID_UINT32);
4085}
INT db_create_key(HNDLE hDB, HNDLE hKey, const char *key_name, DWORD type)
Definition odb.cxx:3308
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 7983 of file midas.cxx.

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

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

7357 {
7359}
INT cm_watchdog_thread(void *unused)
Definition midas.cxx:7337
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 5447 of file midas.cxx.

◆ _deferred_transition_mask

DWORD _deferred_transition_mask
static

Definition at line 3827 of file midas.cxx.

◆ _exptab

exptab_struct _exptab
static

Definition at line 1605 of file midas.cxx.

◆ _requested_transition

INT _requested_transition
static

dox

Definition at line 3826 of file midas.cxx.

◆ _watchdog_thread

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

Definition at line 7331 of file midas.cxx.

7331{NULL};

◆ _watchdog_thread_is_running

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

Definition at line 7330 of file midas.cxx.

7330{false}; // set by watchdog thread

◆ _watchdog_thread_run

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

Definition at line 7329 of file midas.cxx.

7329{false}; // set by main thread