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

6153{
6154#ifdef LOCAL_ROUTINES
6155
6156 //printf("bm_cleanup: called by %s, actual_time %d, wrong_interval %d\n", who, actual_time, wrong_interval);
6157
6158 std::vector<BUFFER*> mybuffers;
6159
6160 gBuffersMutex.lock();
6162 gBuffersMutex.unlock();
6163
6164 /* check buffers */
6165 for (BUFFER* pbuf : mybuffers) {
6166 if (!pbuf)
6167 continue;
6168 if (pbuf->attached) {
6169 /* update the last_activity entry to show that we are alive */
6170
6172
6173 if (!pbuf_guard.is_locked())
6174 continue;
6175
6177 pclient->last_activity = actual_time;
6178
6179 /* don't check other clients if interval is strange */
6180 if (!wrong_interval)
6182 }
6183 }
6184#endif // LOCAL_ROUTINES
6185}
static void bm_cleanup_buffer_locked(BUFFER *pbuf, const char *who, DWORD actual_time)
Definition midas.cxx:6066
static BUFFER_CLIENT * bm_get_my_client_locked(bm_lock_buffer_guard &pbuf_guard)
Definition midas.cxx:5999
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 11284 of file midas.cxx.

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

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

5999 {
6001 return pbuf_guard.get_pbuf()->buffer_header->client + my_client_index;
6002}
static int bm_validate_client_index_locked(bm_lock_buffer_guard &pbuf_guard)
Definition midas.cxx:5922
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 7946 of file midas.cxx.

7947{
7948 //printf("bm_lock_buffer_mutex %s!\n", pbuf->buffer_name);
7949
7950 bool locked = ss_timed_mutex_wait_for_sec(pbuf->buffer_mutex, "buffer mutex", _bm_mutex_timeout_sec);
7951
7952 if (!locked) {
7953 fprintf(stderr, "bm_lock_buffer_mutex: Error: Cannot lock buffer \"%s\", ss_timed_mutex_wait_for_sec() timeout, aborting...\n", pbuf->buffer_name);
7954 cm_msg(MERROR, "bm_lock_buffer_mutex", "Cannot lock buffer \"%s\", ss_timed_mutex_wait_for_sec() timeout, aborting...", pbuf->buffer_name);
7955 abort();
7956 /* DOES NOT RETURN */
7957 }
7958
7959 if (!pbuf->attached) {
7960 pbuf->buffer_mutex.unlock();
7961 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);
7962 return BM_INVALID_HANDLE;
7963 }
7964
7965 //static int counter = 0;
7966 //counter++;
7967 //printf("locked %d!\n", counter);
7968 //if (counter > 50)
7969 // ::sleep(3);
7970
7971 return BM_SUCCESS;
7972}
static double _bm_mutex_timeout_sec
Definition midas.cxx:5920
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 7904 of file midas.cxx.

7905{
7906 bool locked = ss_timed_mutex_wait_for_sec(pbuf->read_cache_mutex, "buffer read cache", _bm_mutex_timeout_sec);
7907
7908 if (!locked) {
7909 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);
7910 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);
7911 abort();
7912 /* DOES NOT RETURN */
7913 }
7914
7915 if (!pbuf->attached) {
7916 pbuf->read_cache_mutex.unlock();
7917 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);
7918 return BM_INVALID_HANDLE;
7919 }
7920
7921 return BM_SUCCESS;
7922}
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 7925 of file midas.cxx.

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

11068{
11069 static DWORD last_time = 0;
11071
11072 //printf("bm_notify_client: buffer [%s], socket %d, time %d\n", buffer_name, client_socket, now - last_time);
11073
11074 BUFFER* fbuf = NULL;
11075
11076 gBuffersMutex.lock();
11077
11078 for (size_t i = 0; i < gBuffers.size(); i++) {
11079 BUFFER* pbuf = gBuffers[i];
11080 if (!pbuf || !pbuf->attached)
11081 continue;
11082 if (strcmp(buffer_name, pbuf->buffer_header->name) == 0) {
11083 fbuf = pbuf;
11084 break;
11085 }
11086 }
11087
11088 gBuffersMutex.unlock();
11089
11090 if (!fbuf)
11091 return BM_INVALID_HANDLE;
11092
11093 /* don't send notification if client has no callback defined
11094 to receive events -> client calls bm_receive_event manually */
11095 if (!fbuf->callback)
11096 return DB_SUCCESS;
11097
11098 int convert_flags = rpc_get_convert_flags();
11099
11100 /* only send notification once each 500ms */
11101 if (now - last_time < 500)
11102 return DB_SUCCESS;
11103
11104 last_time = now;
11105
11106 char buffer[32];
11107 NET_COMMAND *nc = (NET_COMMAND *) buffer;
11108
11109 nc->header.routine_id = MSG_BM;
11110 nc->header.param_size = 0;
11111
11112 if (convert_flags) {
11115 }
11116
11117 //printf("bm_notify_client: Sending MSG_BM! buffer [%s]\n", buffer_name);
11118
11119 /* send the update notification to the client */
11120 send_tcp(client_socket, (char *) buffer, sizeof(NET_COMMAND_HEADER), 0);
11121
11122 return BM_SUCCESS;
11123}
#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:5279
INT rpc_get_convert_flags(void)
Definition midas.cxx:13030
void rpc_convert_single(void *data, INT tid, INT flags, INT convert_flags)
Definition midas.cxx:11681
DWORD last_time
Definition mana.cxx:3070
char buffer_name[NAME_LENGTH]
Definition mevb.cxx:45
#define RPC_OUTGOING
Definition midas.h:1585
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 10918 of file midas.cxx.

10919{
10920 std::vector<BUFFER*> mybuffers;
10921
10922 gBuffersMutex.lock();
10924 gBuffersMutex.unlock();
10925
10926 for (size_t i = 0; i < mybuffers.size(); i++) {
10927 BUFFER *pbuf = mybuffers[i];
10928 if (!pbuf || !pbuf->attached)
10929 continue;
10930 // FIXME: unlocked read access to pbuf->buffer_name!
10931 if (strcmp(buffer_name, pbuf->buffer_name) == 0) {
10932 return bm_push_buffer(pbuf, i + 1);
10933 }
10934 }
10935
10936 return BM_INVALID_HANDLE;
10937}
static INT bm_push_buffer(BUFFER *pbuf, int buffer_handle)
Definition midas.cxx:10902
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 5456 of file midas.cxx.

5456 {
5458}
#define FALSE
Definition cfortran.h:309
static BOOL _ctrlc_pressed
Definition midas.cxx:5439
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:12761
INT rpc_call(DWORD routine_id,...)
Definition midas.cxx:13663
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 3889 of file midas.cxx.

3889 {
3890 INT i, status;
3891 char str[256];
3892 static BOOL first;
3893
3894 if (_requested_transition == 0)
3895 first = TRUE;
3896
3898 for (i = 0; _deferred_trans_table[i].transition; i++)
3900 break;
3901
3905 if (status != CM_SUCCESS)
3906 cm_msg(MERROR, "cm_check_deferred_transition", "Cannot perform deferred transition: %s", str);
3907
3908 /* bypass hotlink and set _requested_transition directly to zero */
3910
3911 return status;
3912 }
3913 first = FALSE;
3914 }
3915 }
3916
3917 return SUCCESS;
3918}
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:5286
static DWORD _deferred_transition_mask
Definition midas.cxx:3819
static INT _requested_transition
Definition midas.cxx:3818
#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 7610 of file midas.cxx.

7610 {
7611 if (rpc_is_remote())
7612 return rpc_call(RPC_CM_CLEANUP, client_name);
7613
7614#ifdef LOCAL_ROUTINES
7615 {
7618
7619 std::vector<BUFFER*> mybuffers;
7620
7621 gBuffersMutex.lock();
7623 gBuffersMutex.unlock();
7624
7625 /* check buffers */
7626 for (BUFFER* pbuf : mybuffers) {
7627 if (!pbuf)
7628 continue;
7629 if (pbuf->attached) {
7630 std::string msg;
7631
7633
7634 if (!pbuf_guard.is_locked())
7635 continue;
7636
7637 /* update the last_activity entry to show that we are alive */
7638 BUFFER_HEADER *pheader = pbuf->buffer_header;
7640 pclient->last_activity = ss_millitime();
7641
7642 /* now check other clients */
7643 for (int j = 0; j < pheader->max_client_index; j++) {
7644 BUFFER_CLIENT *pbclient = &pheader->client[j];
7645 if (j != pbuf->client_index && pbclient->pid &&
7646 (client_name == NULL || client_name[0] == 0
7647 || strncmp(pbclient->name, client_name, strlen(client_name)) == 0)) {
7648 if (ignore_timeout)
7650 else
7652
7653 /* If client process has no activity, clear its buffer entry. */
7654 if (interval > 0
7655 && now > pbclient->last_activity && now - pbclient->last_activity > interval) {
7656
7657 /* now make again the check with the buffer locked */
7658 if (interval > 0
7659 && now > pbclient->last_activity && now - pbclient->last_activity > interval) {
7660 msg = msprintf(
7661 "Client \'%s\' on \'%s\' removed by cm_cleanup (idle %1.1lfs, timeout %1.0lfs)",
7662 pbclient->name, pheader->name,
7663 (ss_millitime() - pbclient->last_activity) / 1000.0,
7664 interval / 1000.0);
7665
7666 bm_remove_client_locked(pheader, j);
7667 }
7668
7669 /* go again through whole list */
7670 j = 0;
7671 }
7672 }
7673 }
7674
7675 // unlock buffer before calling cm_msg(), if we are SYSMSG, we will deadlock.
7676 pbuf_guard.unlock();
7677
7678 /* display info message after unlocking buffer */
7679 if (!msg.empty())
7680 cm_msg(MINFO, "cm_cleanup", "%s", msg.c_str());
7681 }
7682 }
7683
7684 db_cleanup2(client_name, ignore_timeout, now, "cm_cleanup");
7685 }
7686#endif /* LOCAL_ROUTINES */
7687
7688 return CM_SUCCESS;
7689}
void bm_remove_client_locked(BUFFER_HEADER *pheader, int j)
Definition midas.cxx:6035
#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:12012
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:3317
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:3452
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:5441
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:5706
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:7440
void ss_tzset()
Definition system.cxx:3355
char * ss_crypt(const char *buf, const char *salt)
Definition system.cxx:7891
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:13934
INT EXPRT db_set_value_string(HNDLE hDB, HNDLE hKeyRoot, const char *key_name, const std::string *s)
Definition odb.cxx:14005
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:11827
INT rpc_server_connect(const char *host_name, const char *exp_name)
Definition midas.cxx:12381
std::string rpc_get_name()
Definition midas.cxx:13084
INT rpc_get_hw_type()
Definition midas.cxx:12834
INT rpc_server_disconnect()
Definition midas.cxx:12705
INT rpc_set_name(const char *name)
Definition midas.cxx:13108
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 5441 of file midas.cxx.

5441 {
5442 if (_ctrlc_pressed) {
5443 printf("Received 2nd Ctrl-C, hard abort\n");
5444 exit(0);
5445 }
5446 printf("Received Ctrl-C, aborting...\n");
5448
5450}
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 3669 of file midas.cxx.

3669 {
3670 INT status;
3672 char str[256];
3673
3674 /* check for valid transition */
3676 cm_msg(MERROR, "cm_deregister_transition", "Invalid transition request \"%d\"", transition);
3677 return CM_INVALID_TRANSITION;
3678 }
3679
3681
3682 {
3683 std::lock_guard<std::mutex> guard(_trans_table_mutex);
3684
3685 /* remove existing transition request */
3686 for (size_t i = 0; i < _trans_table.size(); i++) {
3688 _trans_table[i].transition = 0;
3689 _trans_table[i].sequence_number = 0;
3690 _trans_table[i].func = NULL;
3691 }
3692 }
3693
3694 // implicit unlock
3695 }
3696
3697 sprintf(str, "Transition %s", cm_transition_name(transition).c_str());
3698
3699 /* unlock database */
3701
3702 /* set value */
3704 if (hKeyTrans) {
3706 if (status != DB_SUCCESS)
3707 return status;
3708 }
3709
3710 /* re-lock database */
3712
3713 return CM_SUCCESS;
3714}
#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:12676
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:7243
INT cm_stop_watchdog_thread()
Definition midas.cxx:7370
static void rpc_client_shutdown()
Definition midas.cxx:12632
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:13514
INT db_close_all_databases(void)
Definition odb.cxx:2360
INT rpc_deregister_functions()
Definition midas.cxx:11870
bool rpc_is_connected(void)
Definition midas.cxx:12783
INT rpc_server_shutdown(void)
Definition midas.cxx:16183
bool rpc_is_mserver(void)
Definition midas.cxx:12818
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 5385 of file midas.cxx.

5404{
5405 if (message[0] == 'O') {
5407 INT index;
5408 index = 0;
5409 sscanf(message + 2, "%d %d %d %d", &hDB, &hKeyRoot, &hKey, &index);
5410 if (client_socket) {
5412 } else {
5414 }
5415 }
5416
5417 /* message == "B" means "resume event sender" */
5418 if (message[0] == 'B' && message[2] != ' ') {
5419 char str[NAME_LENGTH];
5420
5421 //printf("cm_dispatch_ipc: message [%s], s=%d\n", message, s);
5422
5423 mstrlcpy(str, message + 2, sizeof(str));
5424 if (strchr(str, ' '))
5425 *strchr(str, ' ') = 0;
5426
5427 if (client_socket)
5429 else
5430 return bm_push_event(str);
5431 }
5432
5433 //printf("cm_dispatch_ipc: message [%s] ignored\n", message);
5434
5435 return CM_SUCCESS;
5436}
static INT bm_push_event(const char *buffer_name)
Definition midas.cxx:10918
static INT bm_notify_client(const char *buffer_name, int s)
Definition midas.cxx:11048
INT db_update_record_local(INT hDB, INT hKeyRoot, INT hKey, int index)
Definition odb.cxx:13552
INT db_update_record_mserver(INT hDB, INT hKeyRoot, INT hKey, int index, int client_socket)
Definition odb.cxx:13599
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 5461 of file midas.cxx.

5489{
5490 HNDLE hDB, hkey;
5491 KEY key;
5492 int status;
5493
5495 if (status != DB_SUCCESS)
5496 return status;
5497
5499 if (status != DB_SUCCESS)
5500 return status;
5501
5503 if (status != DB_SUCCESS)
5504 return status;
5505
5506 std::string command;
5507
5508 if (key.type == TID_STRING) {
5509 int status = db_get_value_string(hDB, 0, odb_path_to_script, 0, &command, FALSE);
5510 if (status != DB_SUCCESS) {
5511 cm_msg(MERROR, "cm_exec_script", "Script ODB \"%s\" of type TID_STRING, db_get_value_string() error %d",
5513 return status;
5514 }
5515 } else if (key.type == TID_KEY) {
5516 for (int i = 0;; i++) {
5517 HNDLE hsubkey;
5518 KEY subkey;
5520 if (!hsubkey)
5521 break;
5523
5524 if (i > 0)
5525 command += " ";
5526
5527 if (subkey.type == TID_KEY) {
5528 cm_msg(MERROR, "cm_exec_script", "Script ODB \"%s/%s\" should not be TID_KEY", odb_path_to_script,
5529 subkey.name);
5530 return DB_TYPE_MISMATCH;
5531 } else {
5532 int size = subkey.item_size;
5533 char *buf = (char *) malloc(size);
5534 assert(buf != NULL);
5535 int status = db_get_data(hDB, hsubkey, buf, &size, subkey.type);
5536 if (status != DB_SUCCESS) {
5537 cm_msg(MERROR, "cm_exec_script", "Script ODB \"%s/%s\" of type %d, db_get_data() error %d",
5538 odb_path_to_script, subkey.name, subkey.type, status);
5539 free(buf);
5540 return status;
5541 }
5542 if (subkey.type == TID_STRING) {
5543 command += buf;
5544 } else {
5545 command += db_sprintf(buf, subkey.item_size, 0, subkey.type);
5546 }
5547 free(buf);
5548 }
5549 }
5550 } else {
5551 cm_msg(MERROR, "cm_exec_script", "Script ODB \"%s\" has invalid type %d, should be TID_STRING or TID_KEY",
5553 return DB_TYPE_MISMATCH;
5554 }
5555
5556 // printf("exec_script: %s\n", command.c_str());
5557
5558 if (command.length() > 0) {
5559 cm_msg(MINFO, "cm_exec_script", "Executing script \"%s\" from ODB \"%s\"", command.c_str(), odb_path_to_script);
5560 ss_system(command.c_str());
5561 }
5562
5563 return SUCCESS;
5564}
#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 5723 of file midas.cxx.

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

7520 {
7521 INT status, i, size;
7523 char client_name[NAME_LENGTH];
7524
7525 if (rpc_is_remote())
7527
7529
7530 status = db_find_key(hDB, 0, "System/Clients", &hKey);
7531 if (status != DB_SUCCESS)
7532 return DB_NO_KEY;
7533
7535
7536 /* loop over all clients */
7537 for (i = 0;; i++) {
7540 break;
7541
7542 if (hSubkey == hKeyClient)
7543 continue;
7544
7545 if (status == DB_SUCCESS) {
7546 /* get client name */
7547 size = sizeof(client_name);
7548 status = db_get_value(hDB, hSubkey, "Name", client_name, &size, TID_STRING, FALSE);
7549
7550 if (status != DB_SUCCESS) {
7551 //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);
7552 continue;
7553 }
7554
7555 if (equal_ustring(client_name, name)) {
7557 return CM_SUCCESS;
7558 }
7559
7560 if (!bUnique) {
7561 client_name[strlen(name)] = 0; /* strip number */
7562 if (equal_ustring(client_name, name)) {
7564 return CM_SUCCESS;
7565 }
7566 }
7567 }
7568 }
7569
7571
7572 return CM_NO_CLIENT;
7573}
#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 7710 of file midas.cxx.

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

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

3336 {
3337 if (rpc_is_remote())
3338 return rpc_call(RPC_CM_GET_WATCHDOG_INFO, hDB, client_name, timeout, last);
3339
3340#ifdef LOCAL_ROUTINES
3341 return db_get_watchdog_info(hDB, client_name, timeout, last);
3342#else /* LOCAL_ROUTINES */
3343 return CM_SUCCESS;
3344#endif /* LOCAL_ROUTINES */
3345}
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 3317 of file midas.cxx.

3317 {
3318 if (call_watchdog)
3320 if (timeout)
3321 *timeout = _watchdog_timeout;
3322
3323 return CM_SUCCESS;
3324}
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 5452 of file midas.cxx.

5452 {
5453 return _ctrlc_pressed;
5454}
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:5393
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:5225
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 5579 of file midas.cxx.

5579 {
5580 static DWORD alarm_last_checked_sec = 0;
5581 DWORD now_sec = ss_time();
5582
5584 static DWORD last_millitime = 0;
5586 const DWORD kPeriod = 1000;
5587 if (last_millitime == 0) {
5589 tdiff_millitime = kPeriod; // make sure first time we come here we do something.
5590 }
5591
5592 //printf("cm_periodic_tasks! tdiff_millitime %d\n", (int)tdiff_millitime);
5593
5594 //if (now_millitime < last_millitime) {
5595 // printf("millitime wraparound 0x%08x -> 0x%08x\n", last_millitime, now_millitime);
5596 //}
5597
5598 /* check alarms once every 10 seconds */
5599 if (now_sec - alarm_last_checked_sec > 10) {
5600 al_check();
5602 }
5603
5604 /* run periodic checks previously done by cm_watchdog */
5605
5606 if (tdiff_millitime >= kPeriod) {
5608 if (tdiff_millitime > 60000)
5610
5611 //printf("millitime %u, diff %u, wrong_interval %d\n", now_millitime, tdiff_millitime, wrong_interval);
5612
5613 bm_cleanup("cm_periodic_tasks", now_millitime, wrong_interval);
5614 db_cleanup("cm_periodic_tasks", now_millitime, wrong_interval);
5615
5617
5619 }
5620
5621 /* reap transition thread */
5622
5624
5625 return CM_SUCCESS;
5626}
INT al_check()
Definition alarm.cxx:614
INT bm_write_statistics_to_odb(void)
Definition midas.cxx:7280
static void bm_cleanup(const char *who, DWORD actual_time, BOOL wrong_interval)
Definition midas.cxx:6152
INT cm_transition_cleanup()
Definition midas.cxx:5267
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 3837 of file midas.cxx.

3837 {
3838 INT status, size;
3839 char tr_key_name[256];
3840 HNDLE hDB, hKey;
3841
3843
3844 for (int i = 0; _deferred_trans_table[i].transition; i++)
3846 _deferred_trans_table[i].func = (int (*)(int, char *)) func;
3847
3848 /* set new transition mask */
3850
3851 sprintf(tr_key_name, "Transition %s DEFERRED", cm_transition_name(transition).c_str());
3852
3853 /* unlock database */
3855
3856 /* set value */
3857 int i = 0;
3858 status = db_set_value(hDB, hKey, tr_key_name, &i, sizeof(INT), 1, TID_INT32);
3859 if (status != DB_SUCCESS)
3860 return status;
3861
3862 /* re-lock database */
3864
3865 /* hot link requested transition */
3866 size = sizeof(_requested_transition);
3867 db_get_value(hDB, 0, "/Runinfo/Requested Transition", &_requested_transition, &size, TID_INT32, TRUE);
3868 db_find_key(hDB, 0, "/Runinfo/Requested Transition", &hKey);
3870 if (status != DB_SUCCESS) {
3871 cm_msg(MERROR, "cm_register_deferred_transition", "Cannot hotlink /Runinfo/Requested Transition");
3872 return status;
3873 }
3874
3875 return CM_SUCCESS;
3876}
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:13291
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 5790 of file midas.cxx.

5810{
5811 HNDLE hDB, hKey;
5812 INT status;
5813 char str[80];
5814
5815 status = rpc_register_function(id, func);
5816 if (status != RPC_SUCCESS)
5817 return status;
5818
5820
5821 /* create new key for this id */
5822 status = 1;
5823 sprintf(str, "RPC/%d", id);
5824
5826 status = db_set_value(hDB, hKey, str, &status, sizeof(BOOL), 1, TID_BOOL);
5828
5829 if (status != DB_SUCCESS)
5830 return status;
5831
5832 return CM_SUCCESS;
5833}
INT rpc_register_function(INT id, INT(*func)(INT, void **))
Definition midas.cxx:11897
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 3452 of file midas.cxx.

3470{
3471 if (!_rpc_registered) {
3472 INT status;
3473 int size;
3474 HNDLE hDB, hKey;
3475 char name[NAME_LENGTH];
3476 char str[256];
3477 int port = 0;
3478
3480
3481 size = sizeof(name);
3482 status = db_get_value(hDB, hKey, "Name", &name, &size, TID_STRING, FALSE);
3483
3484 if (status != DB_SUCCESS) {
3485 cm_msg(MERROR, "cm_register_server", "cannot get client name, db_get_value() status %d", status);
3486 return status;
3487 }
3488
3489 mstrlcpy(str, "/Experiment/Security/RPC ports/", sizeof(str));
3490 mstrlcat(str, name, sizeof(str));
3491
3492 size = sizeof(port);
3493 status = db_get_value(hDB, 0, str, &port, &size, TID_UINT32, TRUE);
3494
3495 if (status != DB_SUCCESS) {
3496 cm_msg(MERROR, "cm_register_server", "cannot get RPC port number, db_get_value(%s) status %d", str, status);
3497 return status;
3498 }
3499
3500 int lport = 0; // actual port number assigned to us by the OS
3501
3503 if (status != RPC_SUCCESS) {
3504 cm_msg(MERROR, "cm_register_server", "error, rpc_register_server(port=%d) status %d", port, status);
3505 return status;
3506 }
3507
3509
3510 /* register MIDAS library functions */
3512
3513 /* store port number in ODB */
3514
3515 status = db_find_key(hDB, hKey, "Server Port", &hKey);
3516 if (status != DB_SUCCESS) {
3517 cm_msg(MERROR, "cm_register_server", "error, db_find_key(\"Server Port\") status %d", status);
3518 return status;
3519 }
3520
3521 /* unlock database */
3523
3524 /* set value */
3525 status = db_set_data(hDB, hKey, &lport, sizeof(INT), 1, TID_INT32);
3526 if (status != DB_SUCCESS) {
3527 cm_msg(MERROR, "cm_register_server", "error, db_set_data(\"Server Port\"=%d) status %d", port, status);
3528 return status;
3529 }
3530
3531 /* lock database */
3533
3535 }
3536
3537 return CM_SUCCESS;
3538}
static void init_rpc_hosts(HNDLE hDB)
Definition midas.cxx:3404
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:14538
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:3593
INT cm_yield(INT millisec)
Definition midas.cxx:5642
#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 3593 of file midas.cxx.

3593 {
3594 INT status;
3596 KEY key;
3597 char str[256];
3598
3599 /* check for valid transition */
3601 cm_msg(MERROR, "cm_register_transition", "Invalid transition request \"%d\"", transition);
3602 return CM_INVALID_TRANSITION;
3603 }
3604
3606
3608
3609 /* register new transition request */
3610
3611 {
3612 std::lock_guard<std::mutex> guard(_trans_table_mutex);
3613
3614 for (size_t i = 0; i < _trans_table.size(); i++) {
3615 if (_trans_table[i].transition == transition && _trans_table[i].sequence_number == sequence_number) {
3616 cm_msg(MERROR, "cm_register_transition", "transition %s with sequence number %d is already registered", cm_transition_name(transition).c_str(), sequence_number);
3617 return CM_INVALID_TRANSITION;
3618 }
3619 }
3620
3621 bool found = false;
3622 for (size_t i = 0; i < _trans_table.size(); i++) {
3623 if (!_trans_table[i].transition) {
3624 _trans_table[i].transition = transition;
3625 _trans_table[i].sequence_number = sequence_number;
3626 _trans_table[i].func = func;
3627 found = true;
3628 break;
3629 }
3630 }
3631
3632 if (!found) {
3635 tt.sequence_number = sequence_number;
3636 tt.func = func;
3637 _trans_table.push_back(tt);
3638 }
3639
3640 // implicit unlock
3641 }
3642
3643 sprintf(str, "Transition %s", cm_transition_name(transition).c_str());
3644
3645 /* unlock database */
3647
3648 /* set value */
3650 if (!hKeyTrans) {
3651 status = db_set_value(hDB, hKey, str, &sequence_number, sizeof(INT), 1, TID_INT32);
3652 if (status != DB_SUCCESS)
3653 return status;
3654 } else {
3656 if (status != DB_SUCCESS)
3657 return status;
3658 status = db_set_data_index(hDB, hKeyTrans, &sequence_number, sizeof(INT), key.num_values, TID_INT32);
3659 if (status != DB_SUCCESS)
3660 return status;
3661 }
3662
3663 /* re-lock database */
3665
3666 return CM_SUCCESS;
3667}
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:14056
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:7770
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:12800
#define RPC_CM_SET_CLIENT_INFO
Definition mrpc.h:21
void * data
Definition mana.cxx:268
#define PROGRAM_INFO_STR(_name)
Definition midas.h:1448
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 3783 of file midas.cxx.

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

3723 {
3724 INT status;
3725 HNDLE hDB, hKey;
3726 char str[256];
3727
3728 /* check for valid transition */
3730 cm_msg(MERROR, "cm_set_transition_sequence", "Invalid transition request \"%d\"", transition);
3731 return CM_INVALID_TRANSITION;
3732 }
3733
3734 {
3735 std::lock_guard<std::mutex> guard(_trans_table_mutex);
3736
3737 int count = 0;
3738 for (size_t i = 0; i < _trans_table.size(); i++) {
3740 _trans_table[i].sequence_number = sequence_number;
3741 count++;
3742 }
3743 }
3744
3745 if (count == 0) {
3746 cm_msg(MERROR, "cm_set_transition_sequence", "transition %s is not registered", cm_transition_name(transition).c_str());
3747 return CM_INVALID_TRANSITION;
3748 } else if (count > 1) {
3749 cm_msg(MERROR, "cm_set_transition_sequence", "cannot change sequence number, transition %s is registered %d times", cm_transition_name(transition).c_str(), count);
3750 return CM_INVALID_TRANSITION;
3751 }
3752
3753 /* Change local sequence number for this transition type */
3754
3755 for (size_t i = 0; i < _trans_table.size(); i++) {
3757 _trans_table[i].sequence_number = sequence_number;
3758 }
3759 }
3760
3761 // implicit unlock
3762 }
3763
3765
3766 /* unlock database */
3768
3769 sprintf(str, "Transition %s", cm_transition_name(transition).c_str());
3770
3771 /* set value */
3772 status = db_set_value(hDB, hKey, str, &sequence_number, sizeof(INT), 1, TID_INT32);
3773 if (status != DB_SUCCESS)
3774 return status;
3775
3776 /* re-lock database */
3778
3779 return CM_SUCCESS;
3780
3781}
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
3290 } else if (rpc_is_mserver()) { // we are the mserver
3292 if (sa)
3293 sa->watchdog_timeout = timeout;
3294
3295 /* write timeout value to client enty in ODB */
3296 HNDLE hDB, hKey;
3298
3299 if (hDB) {
3301 db_set_value(hDB, hKey, "Link timeout", &timeout, sizeof(timeout), 1, TID_INT32);
3303 }
3304 return DB_SUCCESS;
3305 } else {
3307 }
3308}
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:11513
#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 7400 of file midas.cxx.

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

7355 {
7356 /* watchdog does not run inside remote clients.
7357 * watchdog timeout timers are maintained by the mserver */
7358 if (rpc_is_remote())
7359 return CM_SUCCESS;
7360#ifdef LOCAL_ROUTINES
7361 /* only start once */
7362 if (_watchdog_thread)
7363 return CM_SUCCESS;
7364 _watchdog_thread_run = true;
7365 _watchdog_thread.store(new std::thread(xcm_watchdog_thread));
7366#endif
7367 return CM_SUCCESS;
7368}
static std::atomic< std::thread * > _watchdog_thread
Definition midas.cxx:7323
static void xcm_watchdog_thread()
Definition midas.cxx:7349
static std::atomic< bool > _watchdog_thread_run
Definition midas.cxx:7321
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 7370 of file midas.cxx.

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

7757 {
7758 printf("Test expand_end()\n");
7759 setenv("FOO", "foo", 1);
7760 setenv("BAR", "bar", 1);
7761 setenv("EMPTY", "", 1);
7762 unsetenv("UNDEF");
7763
7764 bool ok = true;
7765
7766 ok &= test_cm_expand_env1("aaa", "aaa");
7767 ok &= test_cm_expand_env1("$FOO", "foo");
7768 ok &= test_cm_expand_env1("/$FOO", "/foo");
7769 ok &= test_cm_expand_env1("/$FOO/", "/foo/");
7770 ok &= test_cm_expand_env1("$FOO/$BAR", "foo/bar");
7771 ok &= test_cm_expand_env1("$FOO1", "$FOO1");
7772 ok &= test_cm_expand_env1("1$FOO", "1foo");
7773 ok &= test_cm_expand_env1("$UNDEF", "$UNDEF");
7774 ok &= test_cm_expand_env1("/$UNDEF/", "/$UNDEF/");
7775
7776 if (ok) {
7777 printf("test_expand_env: all tests passed!\n");
7778 } else {
7779 printf("test_expand_env: test FAILED!\n");
7780 }
7781}
static bool test_cm_expand_env1(const char *str, const char *expected)
Definition midas.cxx:7742
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 5286 of file midas.cxx.

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

5238 {
5239 int status;
5240
5241 status = cm_transition2(transition, run_number, errstr, errstr_size, async_flag, debug_flag);
5242
5243 if (transition == TR_START && status != CM_SUCCESS) {
5244 cm_msg(MERROR, "cm_transition", "Could not start a run: cm_transition() status %d, message \'%s\'", status,
5245 errstr);
5246 cm_transition2(TR_STARTABORT, run_number, NULL, 0, async_flag, debug_flag);
5247 }
5248
5249 return status;
5250}
static INT cm_transition2(INT transition, INT run_number, char *errstr, INT errstr_size, INT async_flag, INT debug_flag)
Definition midas.cxx:4523
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 4523 of file midas.cxx.

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

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

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

5268{
5269 if (_trp.thread && !_trp.finished) {
5270 //printf("main transition thread did not finish yet!\n");
5272 }
5273
5274 std::thread* t = _trp.thread.exchange(NULL);
5275
5276 if (t) {
5277 t->join();
5278 delete t;
5279 t = NULL;
5280 }
5281
5282 return CM_SUCCESS;
5283}
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 4082 of file midas.cxx.

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

7329 {
7331 //printf("cm_watchdog_thread started!\n");
7332 while (_watchdog_thread_run) {
7333 //printf("cm_watchdog_thread runs!\n");
7337 int i;
7338 for (i = 0; i < 20; i++) {
7339 ss_sleep(100);
7341 break;
7342 }
7343 }
7344 //printf("cm_watchdog_thread stopped!\n");
7346 return 0;
7347}
static void bm_update_last_activity(DWORD millitime)
Definition midas.cxx:6117
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 5642 of file midas.cxx.

5642 {
5643 INT status;
5644 INT bMore;
5645 //static DWORD last_yield = 0;
5646 //static DWORD last_yield_time = 0;
5647 //DWORD start_yield = ss_millitime();
5648
5649 /* check for ctrl-c */
5650 if (_ctrlc_pressed)
5651 return RPC_SHUTDOWN;
5652
5653 /* flush the cm_msg buffer */
5655
5656 if (!rpc_is_remote()) {
5657 /* flush the ODB to its binary file */
5658 /* for remote clients, ODB is flushed by the mserver */
5659 HNDLE hDB;
5662 }
5663
5664 /* check for available events */
5665 if (rpc_is_remote()) {
5666 //printf("cm_yield() calling bm_poll_event()\n");
5668
5669 if (status == SS_ABORT) {
5670 return status;
5671 }
5672
5673 if (status == BM_SUCCESS) {
5674 /* one or more events received by bm_poll_event() */
5675 status = ss_suspend(0, 0);
5676 } else {
5678 }
5679
5680 return status;
5681 }
5682
5684
5685 if (status != CM_SUCCESS)
5686 return status;
5687
5688 //DWORD start_check = ss_millitime();
5689
5691
5692 //DWORD end_check = ss_millitime();
5693 //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);
5694 //fflush(stdout);
5695
5696 if (bMore == BM_CORRUPTED) {
5697 status = SS_ABORT;
5698 } else if (bMore) {
5699 /* if events available, quickly check other IPC channels */
5700 status = ss_suspend(0, 0);
5701 } else {
5703 }
5704
5705 /* flush the cm_msg buffer */
5707
5708 //DWORD end_yield = ss_millitime();
5709 //last_yield_time = end_yield - start_yield;
5710 //last_yield = start_yield;
5711
5712 return status;
5713}
INT bm_poll_event()
Definition midas.cxx:11126
INT bm_check_buffers()
Definition midas.cxx:10954
INT cm_periodic_tasks()
Definition midas.cxx:5579
#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 3404 of file midas.cxx.

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

3353 {
3354 int status;
3355 int i, last;
3356 KEY key;
3357 int max_size;
3358 char *str;
3359
3360// if (index != -99)
3361// cm_msg(MINFO, "load_rpc_hosts", "Reloading RPC hosts access control list via hotlink callback");
3362
3364
3365 if (status != DB_SUCCESS)
3366 return;
3367
3368 //printf("clear rpc hosts!\n");
3370
3372 str = (char *) malloc(max_size);
3373
3374 last = 0;
3375 for (i = 0; i < key.num_values; i++) {
3376 int size = max_size;
3378 if (status != DB_SUCCESS)
3379 break;
3380
3381 if (strlen(str) < 1) // skip emties
3382 continue;
3383
3384 if (str[0] == '#') // skip commented-out entries
3385 continue;
3386
3387 //printf("add rpc hosts %d [%s]\n", i, str);
3389 last = i;
3390 }
3391
3392 if (key.num_values - last < 10) {
3393 int new_size = last + 10;
3395 if (status != DB_SUCCESS) {
3396 cm_msg(MERROR, "load_rpc_hosts",
3397 "Cannot resize the RPC hosts access control list, db_set_num_values(%d) status %d", new_size, status);
3398 }
3399 }
3400
3401 free(str);
3402}
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:15235
INT rpc_clear_allowed_hosts()
Definition midas.cxx:15210
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 12632 of file midas.cxx.

12633{
12634 /* close all open connections */
12635
12637
12638 for (unsigned i = 0; i < _client_connections.size(); i++) {
12640 if (c && c->connected) {
12641 int index = c->index;
12642 // must unlock the array, otherwise we hang -
12643 // rpc_client_disconnect() will do rpc_call_client()
12644 // which needs to lock the array to convert handle
12645 // to connection pointer. Ouch! K.O. Dec 2020.
12649 }
12650 }
12651
12652 for (unsigned i = 0; i < _client_connections.size(); i++) {
12654 //printf("client connection %d %p\n", i, c);
12655 if (c) {
12656 //printf("client connection %d %p connected %d\n", i, c, c->connected);
12657 if (!c->connected) {
12658 delete c;
12660 }
12661 }
12662 }
12663
12665
12666 /* close server connection from other clients */
12667 for (unsigned i = 0; i < _server_acceptions.size(); i++) {
12668 if (_server_acceptions[i] && _server_acceptions[i]->recv_sock) {
12669 send(_server_acceptions[i]->recv_sock, "EXIT", 5, 0);
12670 _server_acceptions[i]->close();
12671 }
12672 }
12673}
static std::mutex _client_connections_mutex
Definition midas.cxx:11495
static std::vector< RPC_CLIENT_CONNECTION * > _client_connections
Definition midas.cxx:11496
static std::vector< RPC_SERVER_ACCEPTION * > _server_acceptions
Definition midas.cxx:11502
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 7742 of file midas.cxx.

7742 {
7743 std::string s = cm_expand_env(str);
7744 printf("test_expand_env: [%s] -> [%s] expected [%s]",
7745 str,
7746 s.c_str(),
7747 expected);
7748 if (s != expected) {
7749 printf(", MISMATCH!\n");
7750 return false;
7751 }
7752
7753 printf("\n");
7754 return true;
7755}
std::string cm_expand_env(const char *str)
Definition midas.cxx:7710
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 3976 of file midas.cxx.

3976 {
3977 return arg1->sequence_number < arg2->sequence_number;
3978}
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 3996 of file midas.cxx.

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

5254 {
5255 INT status;
5256 TR_PARAM *trp;
5257
5258 trp = (TR_PARAM *) param;
5259 status = cm_transition1(trp->transition, trp->run_number, trp->errstr, trp->errstr_size, trp->async_flag, trp->debug_flag);
5260
5261 trp->status = status;
5262 trp->finished = TRUE;
5263
5264 return 0;
5265}
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 4029 of file midas.cxx.

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

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

8037 {
8038 // NB: locking order: 1st buffer mutex, 2nd buffer semaphore. Unlock in reverse order.
8039
8040#if 0
8041 int x = MAX_CLIENTS-1;
8042 if (pbuf->attached) {
8043 if (pbuf->buffer_header->client[x].unused1 != getpid()) {
8044 printf("unlock [%s] unused1 %d pid %d\n", pbuf->buffer_header->name, pbuf->buffer_header->client[x].unused1, getpid());
8045 }
8046 pbuf->buffer_header->client[x].unused1 = 0;
8047 } else {
8048 printf("unlock [??????] unused1 ????? pid %d\n", getpid());
8049 }
8050#endif
8051
8052 // protect against double unlock
8053 assert(pbuf->locked);
8054 pbuf->locked = FALSE;
8055
8056 ss_semaphore_release(pbuf->semaphore);
8057 pbuf->buffer_mutex.unlock();
8058}
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 7349 of file midas.cxx.

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

◆ _deferred_transition_mask

DWORD _deferred_transition_mask
static

Definition at line 3819 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 3818 of file midas.cxx.

◆ _watchdog_thread

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

Definition at line 7323 of file midas.cxx.

7323{NULL};

◆ _watchdog_thread_is_running

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

Definition at line 7322 of file midas.cxx.

7322{false}; // set by watchdog thread

◆ _watchdog_thread_run

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

Definition at line 7321 of file midas.cxx.

7321{false}; // set by main thread