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

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

11348{
11349 INT i;
11350
11351 if ((uint16_t(pevent->event_id) & uint16_t(0xF000)) == uint16_t(EVENTID_FRAG1)) {
11352 /*---- start new event ----*/
11353
11354 //printf("First Frag detected : Ser#:%d ID=0x%x \n", pevent->serial_number, pevent->event_id);
11355
11356 /* check if fragments already stored */
11357 for (i = 0; i < MAX_DEFRAG_EVENTS; i++)
11358 if (defrag_buffer[i].event_id == (pevent->event_id & 0x0FFF))
11359 break;
11360
11361 if (i < MAX_DEFRAG_EVENTS) {
11362 free(defrag_buffer[i].pevent);
11365 cm_msg(MERROR, "bm_defragement_event",
11366 "Received new event with ID %d while old fragments were not completed",
11367 (pevent->event_id & 0x0FFF));
11368 }
11369
11370 /* search new slot */
11371 for (i = 0; i < MAX_DEFRAG_EVENTS; i++)
11372 if (defrag_buffer[i].event_id == 0)
11373 break;
11374
11375 if (i == MAX_DEFRAG_EVENTS) {
11376 cm_msg(MERROR, "bm_defragment_event",
11377 "Not enough defragment buffers, please increase MAX_DEFRAG_EVENTS and recompile");
11378 return;
11379 }
11380
11381 /* check event size */
11382 if (pevent->data_size != sizeof(DWORD)) {
11383 cm_msg(MERROR, "bm_defragment_event",
11384 "Received first event fragment with %d bytes instead of %d bytes, event ignored",
11385 pevent->data_size, (int) sizeof(DWORD));
11386 return;
11387 }
11388
11389 /* setup defragment buffer */
11390 defrag_buffer[i].event_id = (pevent->event_id & 0x0FFF);
11394
11395 if (defrag_buffer[i].pevent == NULL) {
11397 cm_msg(MERROR, "bm_defragement_event", "Not enough memory to allocate event defragment buffer");
11398 return;
11399 }
11400
11401 memcpy(defrag_buffer[i].pevent, pevent, sizeof(EVENT_HEADER));
11404
11405 // printf("First frag[%d] (ID %d) Ser#:%d sz:%d\n", i, defrag_buffer[i].event_id,
11406 // pevent->serial_number, defrag_buffer[i].data_size);
11407
11408 return;
11409 }
11410
11411 /* search buffer for that event */
11412 for (i = 0; i < MAX_DEFRAG_EVENTS; i++)
11413 if (defrag_buffer[i].event_id == (pevent->event_id & 0xFFF))
11414 break;
11415
11416 if (i == MAX_DEFRAG_EVENTS) {
11417 /* no buffer available -> no first fragment received */
11418 cm_msg(MERROR, "bm_defragement_event",
11419 "Received fragment without first fragment (ID %d) Ser#:%d",
11420 pevent->event_id & 0x0FFF, pevent->serial_number);
11421 return;
11422 }
11423
11424 /* add fragment to buffer */
11426 free(defrag_buffer[i].pevent);
11429 cm_msg(MERROR, "bm_defragement_event",
11430 "Received fragments with more data (%d) than event size (%d)",
11432 return;
11433 }
11434
11435 memcpy(((char *) defrag_buffer[i].pevent) + sizeof(EVENT_HEADER) +
11436 defrag_buffer[i].received, pdata, pevent->data_size);
11437
11438 defrag_buffer[i].received += pevent->data_size;
11439
11440 //printf("Other frag[%d][%d] (ID %d) Ser#:%d sz:%d\n", i, j++,
11441 // defrag_buffer[i].event_id, pevent->serial_number, pevent->data_size);
11442
11443 if (defrag_buffer[i].received == defrag_buffer[i].data_size) {
11444 /* event complete */
11445 dispatcher(buffer_handle, request_id, defrag_buffer[i].pevent, defrag_buffer[i].pevent + 1);
11446 free(defrag_buffer[i].pevent);
11449 }
11450}
#define MAX_DEFRAG_EVENTS
Definition midas.cxx:11310
static EVENT_DEFRAG_BUFFER defrag_buffer[MAX_DEFRAG_EVENTS]
Definition midas.cxx:11319
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:930
INT i
Definition mdump.cxx:32
int INT
Definition midas.h:129
#define EVENTID_FRAG1
Definition midas.h:907
#define event_id
EVENT_HEADER * pevent
Definition midas.cxx:11316
short int event_id
Definition midas.h:853
DWORD data_size
Definition midas.h:857
DWORD serial_number
Definition midas.h:855
Here is the call graph for this function:
Here is the caller graph for this function:

◆ bm_get_buffer()

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

dox

Definition at line 6645 of file midas.cxx.

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

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

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

◆ bm_lock_buffer_read_cache()

static int bm_lock_buffer_read_cache ( BUFFER pbuf)
static

Definition at line 7927 of file midas.cxx.

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

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

11106{
11107 static DWORD last_time = 0;
11109
11110 //printf("bm_notify_client: buffer [%s], socket %d, time %d\n", buffer_name, client_socket, now - last_time);
11111
11112 BUFFER* fbuf = NULL;
11113
11114 gBuffersMutex.lock();
11115
11116 for (size_t i = 0; i < gBuffers.size(); i++) {
11117 BUFFER* pbuf = gBuffers[i];
11118 if (!pbuf || !pbuf->attached)
11119 continue;
11120 if (strcmp(buffer_name, pbuf->buffer_header->name) == 0) {
11121 fbuf = pbuf;
11122 break;
11123 }
11124 }
11125
11126 gBuffersMutex.unlock();
11127
11128 if (!fbuf)
11129 return BM_INVALID_HANDLE;
11130
11131 /* don't send notification if client has no callback defined
11132 to receive events -> client calls bm_receive_event manually */
11133 if (!fbuf->callback)
11134 return DB_SUCCESS;
11135
11136 int convert_flags = rpc_get_convert_flags();
11137
11138 /* only send notification once each 500ms */
11139 if (now - last_time < 500)
11140 return DB_SUCCESS;
11141
11142 last_time = now;
11143
11144 char buffer[32];
11145 NET_COMMAND *nc = (NET_COMMAND *) buffer;
11146
11147 nc->header.routine_id = MSG_BM;
11148 nc->header.param_size = 0;
11149
11150 if (convert_flags) {
11153 }
11154
11155 //printf("bm_notify_client: Sending MSG_BM! buffer [%s]\n", buffer_name);
11156
11157 /* send the update notification to the client */
11158 send_tcp(client_socket, (char *) buffer, sizeof(NET_COMMAND_HEADER), 0);
11159
11160 return BM_SUCCESS;
11161}
#define DB_SUCCESS
Definition midas.h:632
#define TID_UINT32
Definition midas.h:337
#define MSG_BM
Definition msystem.h:302
DWORD ss_millitime()
Definition system.cxx:3465
INT send_tcp(int sock, char *buffer, DWORD buffer_size, INT flags)
Definition system.cxx:5357
INT rpc_get_convert_flags(void)
Definition midas.cxx:13068
void rpc_convert_single(void *data, INT tid, INT flags, INT convert_flags)
Definition midas.cxx:11719
DWORD last_time
Definition mana.cxx:3070
char buffer_name[NAME_LENGTH]
Definition mevb.cxx:45
#define RPC_OUTGOING
Definition midas.h:1584
NET_COMMAND_HEADER header
Definition msystem.h:293
Here is the call graph for this function:
Here is the caller graph for this function:

◆ bm_push_event()

static INT bm_push_event ( const char buffer_name)
static

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

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

Definition at line 10956 of file midas.cxx.

10957{
10958 std::vector<BUFFER*> mybuffers;
10959
10960 gBuffersMutex.lock();
10962 gBuffersMutex.unlock();
10963
10964 for (size_t i = 0; i < mybuffers.size(); i++) {
10965 BUFFER *pbuf = mybuffers[i];
10966 if (!pbuf || !pbuf->attached)
10967 continue;
10968 // FIXME: unlocked read access to pbuf->buffer_name!
10969 if (strcmp(buffer_name, pbuf->buffer_name) == 0) {
10970 return bm_push_buffer(pbuf, i + 1);
10971 }
10972 }
10973
10974 return BM_INVALID_HANDLE;
10975}
static INT bm_push_buffer(BUFFER *pbuf, int buffer_handle)
Definition midas.cxx:10940
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 5479 of file midas.cxx.

5479 {
5481}
#define FALSE
Definition cfortran.h:309
static BOOL _ctrlc_pressed
Definition midas.cxx:5462
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 1427 of file midas.cxx.

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

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

1884 {
1885 if (rpc_is_remote())
1887
1888#ifdef LOCAL_ROUTINES
1890#endif /*LOCAL_ROUTINES */
1891 return CM_SUCCESS;
1892}
INT db_check_client(HNDLE hDB, HNDLE hKeyClient)
Definition odb.cxx:3064
#define RPC_CM_CHECK_CLIENT
Definition mrpc.h:34
HNDLE hDB
main ODB handle
Definition mana.cxx:207
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_check_connect()

void cm_check_connect ( void  )

Definition at line 2216 of file midas.cxx.

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

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

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

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

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

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

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

1867 {
1868 /* only do it if local */
1869 if (!rpc_is_remote()) {
1871 }
1872 return CM_SUCCESS;
1873}
int db_delete_client_info(HNDLE hDB, int pid)
Definition odb.cxx:2796
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_deregister_transition()

INT cm_deregister_transition ( INT  transition)

Definition at line 3692 of file midas.cxx.

3692 {
3693 INT status;
3695 char str[256];
3696
3697 /* check for valid transition */
3699 cm_msg(MERROR, "cm_deregister_transition", "Invalid transition request \"%d\"", transition);
3700 return CM_INVALID_TRANSITION;
3701 }
3702
3704
3705 {
3706 std::lock_guard<std::mutex> guard(_trans_table_mutex);
3707
3708 /* remove existing transition request */
3709 for (size_t i = 0; i < _trans_table.size(); i++) {
3711 _trans_table[i].transition = 0;
3712 _trans_table[i].sequence_number = 0;
3713 _trans_table[i].func = NULL;
3714 }
3715 }
3716
3717 // implicit unlock
3718 }
3719
3720 sprintf(str, "Transition %s", cm_transition_name(transition).c_str());
3721
3722 /* unlock database */
3724
3725 /* set value */
3727 if (hKeyTrans) {
3729 if (status != DB_SUCCESS)
3730 return status;
3731 }
3732
3733 /* re-lock database */
3735
3736 return CM_SUCCESS;
3737}
#define CM_INVALID_TRANSITION
Definition midas.h:594
#define TR_RESUME
Definition midas.h:408
#define TR_PAUSE
Definition midas.h:407
#define TR_START
Definition midas.h:405
#define TR_STARTABORT
Definition midas.h:409
#define MODE_DELETE
Definition midas.h:372
#define MODE_WRITE
Definition midas.h:371
#define MODE_READ
Definition midas.h:370
#define TR_STOP
Definition midas.h:406
INT db_delete_key(HNDLE hDB, HNDLE hKey, BOOL follow_links)
Definition odb.cxx:3861
INT db_set_mode(HNDLE hDB, HNDLE hKey, WORD mode, BOOL recurse)
Definition odb.cxx:8032
static std::vector< TRANS_TABLE > _trans_table
Definition midas.cxx:248
std::string cm_transition_name(int transition)
Definition midas.cxx:133
static std::mutex _trans_table_mutex
Definition midas.cxx:247
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_disconnect_client()

INT cm_disconnect_client ( HNDLE  hConn,
BOOL  bShutdown 
)

Disconnect from a MIDAS client

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

Definition at line 2848 of file midas.cxx.

2848 {
2850}
INT rpc_client_disconnect(HNDLE hConn, BOOL bShutdown)
Definition midas.cxx:12714
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 2861 of file midas.cxx.

2861 {
2862 HNDLE hDB, hKey;
2863
2864 //cm_msg(MERROR, "cm_disconnect_experiment", "test cm_msg before disconnect from experiment");
2865 //cm_msg_flush_buffer();
2866
2867 /* wait on any transition thread */
2868 if (_trp.transition && !_trp.finished) {
2869 printf("Waiting for transition to finish...\n");
2870 do {
2871 ss_sleep(10);
2872 } while (!_trp.finished);
2873 }
2874
2875 /* stop the watchdog thread */
2877
2878 /* send shutdown notification */
2879 std::string client_name = rpc_get_name();
2880
2881 std::string local_host_name;
2882
2884 local_host_name = "localhost";
2885 else {
2887 //if (strchr(local_host_name, '.'))
2888 // *strchr(local_host_name, '.') = 0;
2889 }
2890
2891 /* disconnect message not displayed */
2892 cm_msg(MLOG, "cm_disconnect_experiment", "Program %s on host %s stopped", client_name.c_str(), local_host_name.c_str());
2894
2895 if (rpc_is_remote()) {
2896 if (rpc_is_connected()) {
2897 /* close open records */
2899
2901 }
2902
2905
2907 } else {
2909
2910 /* delete client info */
2912
2913 if (hDB)
2915
2916 //cm_msg(MERROR, "cm_disconnect_experiment", "test cm_msg before close all buffers, close all databases");
2917 //cm_msg_flush_buffer();
2918
2922
2924
2925 //cm_msg(MERROR, "cm_disconnect_experiment", "test cm_msg after close all buffers, close all databases");
2926 //cm_msg_flush_buffer();
2927 }
2928
2929 if (!rpc_is_mserver())
2931
2932 /* free RPC list */
2934
2935 //cm_msg(MERROR, "cm_disconnect_experiment", "test cm_msg before deleting the message ring buffer");
2936 //cm_msg_flush_buffer();
2937
2938 /* last flush before we delete the message ring buffer */
2940
2941 //cm_msg(MERROR, "cm_disconnect_experiment", "test cm_msg after disconnect is completed");
2942 //cm_msg_flush_buffer();
2943
2944 return CM_SUCCESS;
2945}
INT bm_close_all_buffers(void)
Definition midas.cxx:7266
INT cm_stop_watchdog_thread()
Definition midas.cxx:7393
static void rpc_client_shutdown()
Definition midas.cxx:12670
INT cm_delete_client_info(HNDLE hDB, INT pid)
Definition midas.cxx:1867
INT ss_sleep(INT millisec)
Definition system.cxx:3700
int cm_msg_close_buffer(void)
Definition midas.cxx:500
INT db_close_all_records()
Definition odb.cxx:13527
INT db_close_all_databases(void)
Definition odb.cxx:2365
INT rpc_deregister_functions()
Definition midas.cxx:11908
bool rpc_is_connected(void)
Definition midas.cxx:12821
INT rpc_server_shutdown(void)
Definition midas.cxx:16221
bool rpc_is_mserver(void)
Definition midas.cxx:12856
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 5408 of file midas.cxx.

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

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

5746 {
5747 char str[256];
5748 INT n;
5749 int fh;
5750 int status = 0;
5751 static int check_cm_execute = 1;
5752 static int enable_cm_execute = 0;
5753
5754 if (rpc_is_remote())
5755 return rpc_call(RPC_CM_EXECUTE, command, result, bufsize);
5756
5757 if (check_cm_execute) {
5758 int status;
5759 int size;
5760 HNDLE hDB;
5761 check_cm_execute = 0;
5762
5764 assert(status == DB_SUCCESS);
5765
5766 size = sizeof(enable_cm_execute);
5767 status = db_get_value(hDB, 0, "/Experiment/Enable cm_execute", &enable_cm_execute, &size, TID_BOOL, TRUE);
5768 assert(status == DB_SUCCESS);
5769
5770 //printf("enable_cm_execute %d\n", enable_cm_execute);
5771 }
5772
5773 if (!enable_cm_execute) {
5774 char buf[32];
5775 mstrlcpy(buf, command, sizeof(buf));
5776 cm_msg(MERROR, "cm_execute", "cm_execute(%s...) is disabled by ODB \"/Experiment/Enable cm_execute\"", buf);
5777 return CM_WRONG_PASSWORD;
5778 }
5779
5780 if (bufsize > 0) {
5781 strcpy(str, command);
5782 sprintf(str, "%s > %d.tmp", command, ss_getpid());
5783
5784 status = system(str);
5785
5786 sprintf(str, "%d.tmp", ss_getpid());
5787 fh = open(str, O_RDONLY, 0644);
5788 result[0] = 0;
5789 if (fh) {
5790 n = read(fh, result, bufsize - 1);
5791 result[MAX(0, n)] = 0;
5792 close(fh);
5793 }
5794 remove(str);
5795 } else {
5796 status = system(command);
5797 }
5798
5799 if (status < 0) {
5800 cm_msg(MERROR, "cm_execute", "cm_execute(%s) error %d", command, status);
5801 return CM_SET_ERROR;
5802 }
5803
5804 return CM_SUCCESS;
5805}
#define CM_SET_ERROR
Definition midas.h:583
#define MAX(a, b)
Definition midas.h:509
INT ss_getpid(void)
Definition system.cxx:1379
#define RPC_CM_EXECUTE
Definition mrpc.h:26
DWORD n[4]
Definition mana.cxx:247
#define read(n, a, f)
static std::string remove(const std::string s, char c)
Definition mjsonrpc.cxx:253
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_exist()

INT cm_exist ( const char name,
BOOL  bUnique 
)

Check if a MIDAS client exists in current experiment

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

Definition at line 7543 of file midas.cxx.

7543 {
7544 INT status, i, size;
7546 char client_name[NAME_LENGTH];
7547
7548 if (rpc_is_remote())
7550
7552
7553 status = db_find_key(hDB, 0, "System/Clients", &hKey);
7554 if (status != DB_SUCCESS)
7555 return DB_NO_KEY;
7556
7558
7559 /* loop over all clients */
7560 for (i = 0;; i++) {
7563 break;
7564
7565 if (hSubkey == hKeyClient)
7566 continue;
7567
7568 if (status == DB_SUCCESS) {
7569 /* get client name */
7570 size = sizeof(client_name);
7571 status = db_get_value(hDB, hSubkey, "Name", client_name, &size, TID_STRING, FALSE);
7572
7573 if (status != DB_SUCCESS) {
7574 //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);
7575 continue;
7576 }
7577
7578 if (equal_ustring(client_name, name)) {
7580 return CM_SUCCESS;
7581 }
7582
7583 if (!bUnique) {
7584 client_name[strlen(name)] = 0; /* strip number */
7585 if (equal_ustring(client_name, name)) {
7587 return CM_SUCCESS;
7588 }
7589 }
7590 }
7591 }
7592
7594
7595 return CM_NO_CLIENT;
7596}
#define DB_NO_KEY
Definition midas.h:643
INT db_lock_database(HNDLE hDB)
Definition odb.cxx:2460
INT db_unlock_database(HNDLE hDB)
Definition odb.cxx:2582
#define RPC_CM_EXIST
Definition mrpc.h:31
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_expand_env()

std::string cm_expand_env ( const char str)

Expand environment variables in filesystem file path names

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

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

Parameters
strInput file path
Returns
expanded file path

Definition at line 7733 of file midas.cxx.

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

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

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

2164 {
2165 if (host_name)
2166 *host_name = "";
2167 if (exp_name)
2168 *exp_name = "";
2169
2170 if (host_name && getenv("MIDAS_SERVER_HOST"))
2171 *host_name = getenv("MIDAS_SERVER_HOST");
2172
2173 if (exp_name && getenv("MIDAS_EXPT_NAME"))
2174 *exp_name = getenv("MIDAS_EXPT_NAME");
2175
2176 return CM_SUCCESS;
2177}
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 3026 of file midas.cxx.

3026 {
3027 if (_hDB) {
3028 //printf("cm_get_experiment_database %d %d\n", _hDB, _hKeyClient);
3029 if (hDB != NULL)
3030 *hDB = _hDB;
3031 if (hKeyClient != NULL)
3033 return CM_SUCCESS;
3034 } else {
3035 //printf("cm_get_experiment_database no init\n");
3036 if (hDB != NULL)
3037 *hDB = 0;
3038 if (hKeyClient != NULL)
3039 *hKeyClient = 0;
3040 return CM_DB_ERROR;
3041 }
3042}
#define CM_DB_ERROR
Definition midas.h:585
static HNDLE _hDB
Definition midas.cxx:1472
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 1595 of file midas.cxx.

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

1585 {
1587 return CM_SUCCESS;
1588}
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 3048 of file midas.cxx.

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

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

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

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

1798 {
1799 mstrlcpy(s, _exptab.filename.c_str(), size);
1800 return CM_SUCCESS;
1801}
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 5866 of file midas.cxx.

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

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

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

◆ cm_get_path_string()

INT EXPRT cm_get_path_string ( std::string *  path)

Definition at line 1560 of file midas.cxx.

1560 {
1561 assert(path != NULL);
1562 assert(_path_name.length() > 0);
1563 *path = _path_name;
1564 return CM_SUCCESS;
1565}
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 1499 of file midas.cxx.

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

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

3359 {
3360 if (rpc_is_remote())
3361 return rpc_call(RPC_CM_GET_WATCHDOG_INFO, hDB, client_name, timeout, last);
3362
3363#ifdef LOCAL_ROUTINES
3364 return db_get_watchdog_info(hDB, client_name, timeout, last);
3365#else /* LOCAL_ROUTINES */
3366 return CM_SUCCESS;
3367#endif /* LOCAL_ROUTINES */
3368}
INT db_get_watchdog_info(HNDLE hDB, const char *client_name, DWORD *timeout, DWORD *last)
Definition odb.cxx:3019
#define RPC_CM_GET_WATCHDOG_INFO
Definition mrpc.h:24
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_get_watchdog_params()

INT cm_get_watchdog_params ( BOOL call_watchdog,
DWORD timeout 
)

Return the current watchdog parameters

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

Definition at line 3340 of file midas.cxx.

3340 {
3341 if (call_watchdog)
3343 if (timeout)
3344 *timeout = _watchdog_timeout;
3345
3346 return CM_SUCCESS;
3347}
static INT _watchdog_timeout
Definition midas.cxx:1476
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 5475 of file midas.cxx.

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

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

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

◆ cm_periodic_tasks()

INT cm_periodic_tasks ( void  )

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

Returns
CM_SUCCESS

Definition at line 5602 of file midas.cxx.

5602 {
5603 static DWORD alarm_last_checked_sec = 0;
5604 DWORD now_sec = ss_time();
5605
5607 static DWORD last_millitime = 0;
5609 const DWORD kPeriod = 1000;
5610 if (last_millitime == 0) {
5612 tdiff_millitime = kPeriod; // make sure first time we come here we do something.
5613 }
5614
5615 //printf("cm_periodic_tasks! tdiff_millitime %d\n", (int)tdiff_millitime);
5616
5617 //if (now_millitime < last_millitime) {
5618 // printf("millitime wraparound 0x%08x -> 0x%08x\n", last_millitime, now_millitime);
5619 //}
5620
5621 /* check alarms once every 10 seconds */
5622 if (now_sec - alarm_last_checked_sec > 10) {
5623 al_check();
5625 }
5626
5627 /* run periodic checks previously done by cm_watchdog */
5628
5629 if (tdiff_millitime >= kPeriod) {
5631 if (tdiff_millitime > 60000)
5633
5634 //printf("millitime %u, diff %u, wrong_interval %d\n", now_millitime, tdiff_millitime, wrong_interval);
5635
5636 bm_cleanup("cm_periodic_tasks", now_millitime, wrong_interval);
5637 db_cleanup("cm_periodic_tasks", now_millitime, wrong_interval);
5638
5640
5642 }
5643
5644 /* reap transition thread */
5645
5647
5648 return CM_SUCCESS;
5649}
INT al_check()
Definition alarm.cxx:614
INT bm_write_statistics_to_odb(void)
Definition midas.cxx:7303
static void bm_cleanup(const char *who, DWORD actual_time, BOOL wrong_interval)
Definition midas.cxx:6175
INT cm_transition_cleanup()
Definition midas.cxx:5290
DWORD ss_time()
Definition system.cxx:3534
void db_cleanup(const char *who, DWORD actual_time, BOOL wrong_interval)
Definition odb.cxx:2832
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_read_exptab()

INT cm_read_exptab ( exptab_struct exptab)

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

Returns
CM_SUCCESS
CM_UNDEF_EXP exptab not found and MIDAS_DIR not set

Definition at line 1629 of file midas.cxx.

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

3860 {
3861 INT status, size;
3862 char tr_key_name[256];
3863 HNDLE hDB, hKey;
3864
3866
3867 for (int i = 0; _deferred_trans_table[i].transition; i++)
3869 _deferred_trans_table[i].func = (int (*)(int, char *)) func;
3870
3871 /* set new transition mask */
3873
3874 sprintf(tr_key_name, "Transition %s DEFERRED", cm_transition_name(transition).c_str());
3875
3876 /* unlock database */
3878
3879 /* set value */
3880 int i = 0;
3881 status = db_set_value(hDB, hKey, tr_key_name, &i, sizeof(INT), 1, TID_INT32);
3882 if (status != DB_SUCCESS)
3883 return status;
3884
3885 /* re-lock database */
3887
3888 /* hot link requested transition */
3889 size = sizeof(_requested_transition);
3890 db_get_value(hDB, 0, "/Runinfo/Requested Transition", &_requested_transition, &size, TID_INT32, TRUE);
3891 db_find_key(hDB, 0, "/Runinfo/Requested Transition", &hKey);
3893 if (status != DB_SUCCESS) {
3894 cm_msg(MERROR, "cm_register_deferred_transition", "Cannot hotlink /Runinfo/Requested Transition");
3895 return status;
3896 }
3897
3898 return CM_SUCCESS;
3899}
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:13303
INT db_set_value(HNDLE hDB, HNDLE hKeyRoot, const char *key_name, const void *data, INT data_size, INT num_values, DWORD type)
Definition odb.cxx:5266
INT(* func)(INT, char *)
Definition midas.cxx:244
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_register_function()

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

dox

Definition at line 5813 of file midas.cxx.

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

3493{
3494 if (!_rpc_registered) {
3495 INT status;
3496 int size;
3497 HNDLE hDB, hKey;
3498 char name[NAME_LENGTH];
3499 char str[256];
3500 int port = 0;
3501
3503
3504 size = sizeof(name);
3505 status = db_get_value(hDB, hKey, "Name", &name, &size, TID_STRING, FALSE);
3506
3507 if (status != DB_SUCCESS) {
3508 cm_msg(MERROR, "cm_register_server", "cannot get client name, db_get_value() status %d", status);
3509 return status;
3510 }
3511
3512 mstrlcpy(str, "/Experiment/Security/RPC ports/", sizeof(str));
3513 mstrlcat(str, name, sizeof(str));
3514
3515 size = sizeof(port);
3516 status = db_get_value(hDB, 0, str, &port, &size, TID_UINT32, TRUE);
3517
3518 if (status != DB_SUCCESS) {
3519 cm_msg(MERROR, "cm_register_server", "cannot get RPC port number, db_get_value(%s) status %d", str, status);
3520 return status;
3521 }
3522
3523 int lport = 0; // actual port number assigned to us by the OS
3524
3526 if (status != RPC_SUCCESS) {
3527 cm_msg(MERROR, "cm_register_server", "error, rpc_register_server(port=%d) status %d", port, status);
3528 return status;
3529 }
3530
3532
3533 /* register MIDAS library functions */
3535
3536 /* store port number in ODB */
3537
3538 status = db_find_key(hDB, hKey, "Server Port", &hKey);
3539 if (status != DB_SUCCESS) {
3540 cm_msg(MERROR, "cm_register_server", "error, db_find_key(\"Server Port\") status %d", status);
3541 return status;
3542 }
3543
3544 /* unlock database */
3546
3547 /* set value */
3548 status = db_set_data(hDB, hKey, &lport, sizeof(INT), 1, TID_INT32);
3549 if (status != DB_SUCCESS) {
3550 cm_msg(MERROR, "cm_register_server", "error, db_set_data(\"Server Port\"=%d) status %d", port, status);
3551 return status;
3552 }
3553
3554 /* lock database */
3556
3558 }
3559
3560 return CM_SUCCESS;
3561}
static void init_rpc_hosts(HNDLE hDB)
Definition midas.cxx:3427
INT db_set_data(HNDLE hDB, HNDLE hKey, const void *data, INT buf_size, INT num_values, DWORD type)
Definition odb.cxx:7220
INT rpc_register_server(int port, int *plsock, int *pport)
Definition midas.cxx:14576
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:3616
INT cm_yield(INT millisec)
Definition midas.cxx:5665
#define SS_ABORT
Definition midas.h:678
#define RPC_SHUTDOWN
Definition midas.h:708
INT run_number[2]
Definition mana.cxx:246
Parameters
transitionTransition to register for (see state_transition)
funcCallback function.
sequence_numberSequence number for that transition (1..1000)
Returns
CM_SUCCESS

Definition at line 3616 of file midas.cxx.

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

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

◆ cm_select_experiment_remote()

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

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

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

Definition at line 2734 of file midas.cxx.

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

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

◆ cm_set_client_run_state()

INT cm_set_client_run_state ( INT  state)

Definition at line 3806 of file midas.cxx.

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

2954 {
2955 //printf("cm_set_experiment_database: hDB %d, hKeyClient %d\n", hDB, hKeyClient);
2956
2957 _hDB = hDB;
2959
2960 //if (hDB == 0) {
2961 // rpc_set_server_option(RPC_ODB_HANDLE, 0);
2962 //}
2963
2964 return CM_SUCCESS;
2965}
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 2181 of file midas.cxx.

2182{
2183 std::string exp_name1;
2184
2185 if ((exp_name != NULL) && (strlen(exp_name) > 0)) {
2187 } else {
2189 if (status != CM_SUCCESS)
2190 return status;
2191 }
2192
2193 std::string expdir, expuser;
2194
2195 int status = cm_get_exptab(exp_name1.c_str(), &expdir, &expuser);
2196
2197 if (status != CM_SUCCESS) {
2198 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());
2199 return CM_UNDEF_EXP;
2200 }
2201
2202 if (!ss_dir_exist(expdir.c_str())) {
2203 cm_msg(MERROR, "cm_set_experiment_local", "Experiment \"%s\" directory \"%s\" does not exist", exp_name1.c_str(), expdir.c_str());
2204 return CM_UNDEF_EXP;
2205 }
2206
2208 cm_set_path(expdir.c_str());
2209
2210 return CM_SUCCESS;
2211}
INT cm_set_path(const char *path)
Definition midas.cxx:1512
INT cm_select_experiment_local(std::string *exp_name)
Definition midas.cxx:2685
std::string cm_get_exptab_filename()
Definition midas.cxx:1803
int ss_dir_exist(const char *path)
Definition system.cxx:7264
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_set_experiment_name()

INT cm_set_experiment_name ( const char name)

Set name of the experiment

Parameters
nameExperiment name
Returns
CM_SUCCESS

Definition at line 1573 of file midas.cxx.

1573 {
1575 return CM_SUCCESS;
1576}
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 2973 of file midas.cxx.

2993{
2997 //_semaphore_msg = semaphore_msg;
2998
2999 return CM_SUCCESS;
3000}
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 1512 of file midas.cxx.

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

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

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

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

◆ cm_shutdown()

INT cm_shutdown ( const char name,
BOOL  bUnique 
)

Shutdown (exit) other MIDAS client

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

Definition at line 7423 of file midas.cxx.

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

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

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

1384 {
1385 INT sec, status;
1386
1387 /* if connected to server, get time from there */
1388 if (rpc_is_remote()) {
1390
1391 /* set local time */
1392 if (status == CM_SUCCESS)
1393 ss_settime(sec);
1394 }
1395
1396 /* return time to caller */
1397 if (seconds != NULL) {
1398 *seconds = ss_time();
1399 }
1400
1401 return CM_SUCCESS;
1402}
DWORD ss_settime(DWORD seconds)
Definition system.cxx:3547
#define RPC_CM_SYNCHRONIZE
Definition mrpc.h:27
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_test_expand_env()

void cm_test_expand_env ( )

Definition at line 7780 of file midas.cxx.

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

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

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

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

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

◆ cm_transition_call()

static int cm_transition_call ( TrState s,
int  idx 
)
static

Definition at line 4188 of file midas.cxx.

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

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

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

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

7352 {
7354 //printf("cm_watchdog_thread started!\n");
7355 while (_watchdog_thread_run) {
7356 //printf("cm_watchdog_thread runs!\n");
7360 int i;
7361 for (i = 0; i < 20; i++) {
7362 ss_sleep(100);
7364 break;
7365 }
7366 }
7367 //printf("cm_watchdog_thread stopped!\n");
7369 return 0;
7370}
static void bm_update_last_activity(DWORD millitime)
Definition midas.cxx:6140
INT db_update_last_activity(DWORD millitime)
Definition odb.cxx:2697
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_yield()

INT cm_yield ( INT  millisec)

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

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

Definition at line 5665 of file midas.cxx.

5665 {
5666 INT status;
5667 INT bMore;
5668 //static DWORD last_yield = 0;
5669 //static DWORD last_yield_time = 0;
5670 //DWORD start_yield = ss_millitime();
5671
5672 /* check for ctrl-c */
5673 if (_ctrlc_pressed)
5674 return RPC_SHUTDOWN;
5675
5676 /* flush the cm_msg buffer */
5678
5679 if (!rpc_is_remote()) {
5680 /* flush the ODB to its binary file */
5681 /* for remote clients, ODB is flushed by the mserver */
5682 HNDLE hDB;
5685 }
5686
5687 /* check for available events */
5688 if (rpc_is_remote()) {
5689 //printf("cm_yield() calling bm_poll_event()\n");
5691
5692 if (status == SS_ABORT) {
5693 return status;
5694 }
5695
5696 if (status == BM_SUCCESS) {
5697 /* one or more events received by bm_poll_event() */
5698 status = ss_suspend(0, 0);
5699 } else {
5701 }
5702
5703 return status;
5704 }
5705
5707
5708 if (status != CM_SUCCESS)
5709 return status;
5710
5711 //DWORD start_check = ss_millitime();
5712
5714
5715 //DWORD end_check = ss_millitime();
5716 //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);
5717 //fflush(stdout);
5718
5719 if (bMore == BM_CORRUPTED) {
5720 status = SS_ABORT;
5721 } else if (bMore) {
5722 /* if events available, quickly check other IPC channels */
5723 status = ss_suspend(0, 0);
5724 } else {
5726 }
5727
5728 /* flush the cm_msg buffer */
5730
5731 //DWORD end_yield = ss_millitime();
5732 //last_yield_time = end_yield - start_yield;
5733 //last_yield = start_yield;
5734
5735 return status;
5736}
INT bm_poll_event()
Definition midas.cxx:11164
INT bm_check_buffers()
Definition midas.cxx:10992
INT cm_periodic_tasks()
Definition midas.cxx:5602
#define BM_CORRUPTED
Definition midas.h:623
INT ss_suspend(INT millisec, INT msg)
Definition system.cxx:4615
Here is the call graph for this function:
Here is the caller graph for this function:

◆ init_rpc_hosts()

static void init_rpc_hosts ( HNDLE  hDB)
static

Definition at line 3427 of file midas.cxx.

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

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

12671{
12672 /* close all open connections */
12673
12675
12676 for (unsigned i = 0; i < _client_connections.size(); i++) {
12678 if (c && c->connected) {
12679 int index = c->index;
12680 // must unlock the array, otherwise we hang -
12681 // rpc_client_disconnect() will do rpc_call_client()
12682 // which needs to lock the array to convert handle
12683 // to connection pointer. Ouch! K.O. Dec 2020.
12687 }
12688 }
12689
12690 for (unsigned i = 0; i < _client_connections.size(); i++) {
12692 //printf("client connection %d %p\n", i, c);
12693 if (c) {
12694 //printf("client connection %d %p connected %d\n", i, c, c->connected);
12695 if (!c->connected) {
12696 delete c;
12698 }
12699 }
12700 }
12701
12703
12704 /* close server connection from other clients */
12705 for (unsigned i = 0; i < _server_acceptions.size(); i++) {
12706 if (_server_acceptions[i] && _server_acceptions[i]->recv_sock) {
12707 send(_server_acceptions[i]->recv_sock, "EXIT", 5, 0);
12708 _server_acceptions[i]->close();
12709 }
12710 }
12711}
static std::mutex _client_connections_mutex
Definition midas.cxx:11533
static std::vector< RPC_CLIENT_CONNECTION * > _client_connections
Definition midas.cxx:11534
static std::vector< RPC_SERVER_ACCEPTION * > _server_acceptions
Definition midas.cxx:11540
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 7765 of file midas.cxx.

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

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

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

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

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

◆ xbm_lock_buffer()

static int xbm_lock_buffer ( BUFFER pbuf)
static

Definition at line 7998 of file midas.cxx.

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

◆ xbm_unlock_buffer()

static void xbm_unlock_buffer ( BUFFER pbuf)
static

Definition at line 8060 of file midas.cxx.

8060 {
8061 // NB: locking order: 1st buffer mutex, 2nd buffer semaphore. Unlock in reverse order.
8062
8063#if 0
8064 int x = MAX_CLIENTS-1;
8065 if (pbuf->attached) {
8066 if (pbuf->buffer_header->client[x].unused1 != getpid()) {
8067 printf("unlock [%s] unused1 %d pid %d\n", pbuf->buffer_header->name, pbuf->buffer_header->client[x].unused1, getpid());
8068 }
8069 pbuf->buffer_header->client[x].unused1 = 0;
8070 } else {
8071 printf("unlock [??????] unused1 ????? pid %d\n", getpid());
8072 }
8073#endif
8074
8075 // protect against double unlock
8076 assert(pbuf->locked);
8077 pbuf->locked = FALSE;
8078
8079 ss_semaphore_release(pbuf->semaphore);
8080 pbuf->buffer_mutex.unlock();
8081}
INT ss_semaphore_release(HNDLE semaphore_handle)
Definition system.cxx:2853
Here is the call graph for this function:
Here is the caller graph for this function:

◆ xcm_watchdog_thread()

static void xcm_watchdog_thread ( )
static

Definition at line 7372 of file midas.cxx.

7372 {
7374}
INT cm_watchdog_thread(void *unused)
Definition midas.cxx:7352
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 5462 of file midas.cxx.

◆ _deferred_transition_mask

DWORD _deferred_transition_mask
static

Definition at line 3842 of file midas.cxx.

◆ _exptab

exptab_struct _exptab
static

Definition at line 1620 of file midas.cxx.

◆ _requested_transition

INT _requested_transition
static

dox

Definition at line 3841 of file midas.cxx.

◆ _watchdog_thread

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

Definition at line 7346 of file midas.cxx.

7346{NULL};

◆ _watchdog_thread_is_running

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

Definition at line 7345 of file midas.cxx.

7345{false}; // set by watchdog thread

◆ _watchdog_thread_run

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

Definition at line 7344 of file midas.cxx.

7344{false}; // set by main thread