MIDAS
Common Functions (cm_xxx)

Classes

struct  exptab_entry
 
struct  exptab_struct
 
class  bm_lock_buffer_guard
 
struct  TrClient
 
struct  TrState
 

Functions

INT cm_synchronize (DWORD *seconds)
 
INT cm_asctime (char *str, INT buf_size)
 
std::string cm_asctime ()
 
INT cm_time (DWORD *t)
 
const char * cm_get_version ()
 
const char * cm_get_revision ()
 
INT cm_set_path (const char *path)
 
INT cm_get_path (char *path, int path_size)
 
std::string cm_get_path ()
 
INT EXPRT cm_get_path_string (std::string *path)
 
INT cm_set_experiment_name (const char *name)
 
INT cm_get_experiment_name (char *name, int name_length)
 
std::string cm_get_experiment_name ()
 
INT cm_read_exptab (exptab_struct *exptab)
 
int cm_get_exptab_filename (char *s, int size)
 
std::string cm_get_exptab_filename ()
 
int cm_get_exptab (const char *expname, std::string *dir, std::string *user)
 
int cm_get_exptab (const char *expname, char *dir, int dir_size, char *user, int user_size)
 
INT cm_delete_client_info (HNDLE hDB, INT pid)
 
INT cm_check_client (HNDLE hDB, HNDLE hKeyClient)
 
INT cm_set_client_info (HNDLE hDB, HNDLE *hKeyClient, const char *host_name, char *client_name, INT hw_type, const char *password, DWORD watchdog_timeout)
 
std::string cm_get_client_name ()
 
INT cm_get_environment (char *host_name, int host_name_size, char *exp_name, int exp_name_size)
 
INT cm_get_environment (std::string *host_name, std::string *exp_name)
 
int cm_set_experiment_local (const char *exp_name)
 
void cm_check_connect (void)
 
INT cm_connect_experiment (const char *host_name, const char *exp_name, const char *client_name, void(*func)(char *))
 
INT cm_connect_experiment1 (const char *host_name, const char *default_exp_name, const char *client_name, void(*func)(char *), INT odb_size, DWORD watchdog_timeout)
 
INT cm_list_experiments_local (STRING_LIST *exp_names)
 
INT cm_list_experiments_remote (const char *host_name, STRING_LIST *exp_names)
 
INT cm_select_experiment_local (std::string *exp_name)
 
INT cm_select_experiment_remote (const char *host_name, std::string *exp_name)
 
INT cm_connect_client (const char *client_name, HNDLE *hConn)
 
static void rpc_client_shutdown ()
 
INT cm_disconnect_client (HNDLE hConn, BOOL bShutdown)
 
INT cm_disconnect_experiment (void)
 
INT cm_set_experiment_database (HNDLE hDB, HNDLE hKeyClient)
 
INT cm_set_experiment_semaphore (INT semaphore_alarm, INT semaphore_elog, INT semaphore_history, INT semaphore_msg)
 
INT cm_get_experiment_database (HNDLE *hDB, HNDLE *hKeyClient)
 
INT cm_get_experiment_semaphore (INT *semaphore_alarm, INT *semaphore_elog, INT *semaphore_history, INT *semaphore_msg)
 
static int bm_validate_client_index (const BUFFER *buf, BOOL abort_if_invalid)
 
static BUFFER_CLIENTbm_get_my_client (BUFFER *pbuf, BUFFER_HEADER *pheader)
 
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 INT bm_notify_client (const char *buffer_name, int s)
 
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 6115 of file midas.cxx.

6116 {
6117 #ifdef LOCAL_ROUTINES
6118 
6119  //printf("bm_cleanup: called by %s, actual_time %d, wrong_interval %d\n", who, actual_time, wrong_interval);
6120 
6121  std::vector<BUFFER*> mybuffers;
6122 
6123  gBuffersMutex.lock();
6124  mybuffers = gBuffers;
6125  gBuffersMutex.unlock();
6126 
6127  /* check buffers */
6128  for (BUFFER* pbuf : mybuffers) {
6129  if (!pbuf)
6130  continue;
6131  if (pbuf->attached) {
6132  /* update the last_activity entry to show that we are alive */
6133 
6134  bm_lock_buffer_guard pbuf_guard(pbuf);
6135 
6136  if (!pbuf_guard.is_locked())
6137  continue;
6138 
6139  BUFFER_HEADER *pheader = pbuf->buffer_header;
6140  BUFFER_CLIENT *pclient = bm_get_my_client(pbuf, pheader);
6141  pclient->last_activity = actual_time;
6142 
6143  /* don't check other clients if interval is strange */
6144  if (!wrong_interval)
6146  }
6147  }
6148 #endif // LOCAL_ROUTINES
6149 }
static void bm_cleanup_buffer_locked(BUFFER *pbuf, const char *who, DWORD actual_time)
Definition: midas.cxx:6029
static BUFFER_CLIENT * bm_get_my_client(BUFFER *pbuf, BUFFER_HEADER *pheader)
Definition: midas.cxx:5962
DWORD actual_time
Definition: mfe.cxx:38
static std::mutex gBuffersMutex
Definition: midas.cxx:197
static std::vector< BUFFER * > gBuffers
Definition: midas.cxx:198
DWORD last_activity
Definition: midas.h:956
Definition: midas.h:992
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 11251 of file midas.cxx.

11277 {
11278  INT i;
11279 
11280  if ((uint16_t(pevent->event_id) & uint16_t(0xF000)) == uint16_t(EVENTID_FRAG1)) {
11281  /*---- start new event ----*/
11282 
11283  //printf("First Frag detected : Ser#:%d ID=0x%x \n", pevent->serial_number, pevent->event_id);
11284 
11285  /* check if fragments already stored */
11286  for (i = 0; i < MAX_DEFRAG_EVENTS; i++)
11287  if (defrag_buffer[i].event_id == (pevent->event_id & 0x0FFF))
11288  break;
11289 
11290  if (i < MAX_DEFRAG_EVENTS) {
11291  free(defrag_buffer[i].pevent);
11292  defrag_buffer[i].pevent = NULL;
11293  memset(&defrag_buffer[i].event_id, 0, sizeof(EVENT_DEFRAG_BUFFER));
11294  cm_msg(MERROR, "bm_defragement_event",
11295  "Received new event with ID %d while old fragments were not completed",
11296  (pevent->event_id & 0x0FFF));
11297  }
11298 
11299  /* search new slot */
11300  for (i = 0; i < MAX_DEFRAG_EVENTS; i++)
11301  if (defrag_buffer[i].event_id == 0)
11302  break;
11303 
11304  if (i == MAX_DEFRAG_EVENTS) {
11305  cm_msg(MERROR, "bm_defragment_event",
11306  "Not enough defragment buffers, please increase MAX_DEFRAG_EVENTS and recompile");
11307  return;
11308  }
11309 
11310  /* check event size */
11311  if (pevent->data_size != sizeof(DWORD)) {
11312  cm_msg(MERROR, "bm_defragment_event",
11313  "Received first event fragment with %d bytes instead of %d bytes, event ignored",
11314  pevent->data_size, (int) sizeof(DWORD));
11315  return;
11316  }
11317 
11318  /* setup defragment buffer */
11319  defrag_buffer[i].event_id = (pevent->event_id & 0x0FFF);
11320  defrag_buffer[i].data_size = *(DWORD *) pdata;
11321  defrag_buffer[i].received = 0;
11323 
11324  if (defrag_buffer[i].pevent == NULL) {
11325  memset(&defrag_buffer[i].event_id, 0, sizeof(EVENT_DEFRAG_BUFFER));
11326  cm_msg(MERROR, "bm_defragement_event", "Not enough memory to allocate event defragment buffer");
11327  return;
11328  }
11329 
11330  memcpy(defrag_buffer[i].pevent, pevent, sizeof(EVENT_HEADER));
11333 
11334  // printf("First frag[%d] (ID %d) Ser#:%d sz:%d\n", i, defrag_buffer[i].event_id,
11335  // pevent->serial_number, defrag_buffer[i].data_size);
11336 
11337  return;
11338  }
11339 
11340  /* search buffer for that event */
11341  for (i = 0; i < MAX_DEFRAG_EVENTS; i++)
11342  if (defrag_buffer[i].event_id == (pevent->event_id & 0xFFF))
11343  break;
11344 
11345  if (i == MAX_DEFRAG_EVENTS) {
11346  /* no buffer available -> no first fragment received */
11347  cm_msg(MERROR, "bm_defragement_event",
11348  "Received fragment without first fragment (ID %d) Ser#:%d",
11349  pevent->event_id & 0x0FFF, pevent->serial_number);
11350  return;
11351  }
11352 
11353  /* add fragment to buffer */
11355  free(defrag_buffer[i].pevent);
11356  defrag_buffer[i].pevent = NULL;
11357  memset(&defrag_buffer[i].event_id, 0, sizeof(EVENT_DEFRAG_BUFFER));
11358  cm_msg(MERROR, "bm_defragement_event",
11359  "Received fragments with more data (%d) than event size (%d)",
11361  return;
11362  }
11363 
11364  memcpy(((char *) defrag_buffer[i].pevent) + sizeof(EVENT_HEADER) +
11365  defrag_buffer[i].received, pdata, pevent->data_size);
11366 
11367  defrag_buffer[i].received += pevent->data_size;
11368 
11369  //printf("Other frag[%d][%d] (ID %d) Ser#:%d sz:%d\n", i, j++,
11370  // defrag_buffer[i].event_id, pevent->serial_number, pevent->data_size);
11371 
11372  if (defrag_buffer[i].received == defrag_buffer[i].data_size) {
11373  /* event complete */
11374  dispatcher(buffer_handle, request_id, defrag_buffer[i].pevent, defrag_buffer[i].pevent + 1);
11375  free(defrag_buffer[i].pevent);
11376  defrag_buffer[i].pevent = NULL;
11377  memset(&defrag_buffer[i].event_id, 0, sizeof(EVENT_DEFRAG_BUFFER));
11378  }
11379 }
#define MAX_DEFRAG_EVENTS
Definition: midas.cxx:11239
static EVENT_DEFRAG_BUFFER defrag_buffer[MAX_DEFRAG_EVENTS]
Definition: midas.cxx:11248
unsigned int DWORD
Definition: mcstd.h:51
#define MERROR
Definition: midas.h:565
INT cm_msg(INT message_type, const char *filename, INT line, const char *routine, const char *format,...)
Definition: midas.cxx:917
INT i
Definition: mdump.cxx:35
int INT
Definition: midas.h:129
#define EVENTID_FRAG1
Definition: midas.h:912
#define event_id
Definition: midas_macro.h:234
EVENT_HEADER * pevent
Definition: midas.cxx:11245
short int event_id
Definition: midas.h:858
DWORD data_size
Definition: midas.h:862
DWORD serial_number
Definition: midas.h:860
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

Definition at line 6586 of file midas.cxx.

6587 {
6588  size_t sbuffer_handle = buffer_handle;
6589 
6590  size_t nbuf = 0;
6591  BUFFER* pbuf = NULL;
6592 
6593  gBuffersMutex.lock();
6594 
6595  nbuf = gBuffers.size();
6596  if (buffer_handle >=1 && sbuffer_handle <= nbuf) {
6597  pbuf = gBuffers[buffer_handle-1];
6598  }
6599 
6600  gBuffersMutex.unlock();
6601 
6602  if (sbuffer_handle > nbuf || buffer_handle <= 0) {
6603  if (who)
6604  cm_msg(MERROR, who, "invalid buffer handle %d: out of range [1..%d]", buffer_handle, (int)nbuf);
6605  if (pstatus)
6606  *pstatus = BM_INVALID_HANDLE;
6607  return NULL;
6608  }
6609 
6610  if (!pbuf) {
6611  if (who)
6612  cm_msg(MERROR, who, "invalid buffer handle %d: empty slot", buffer_handle);
6613  if (pstatus)
6614  *pstatus = BM_INVALID_HANDLE;
6615  return NULL;
6616  }
6617 
6618  if (!pbuf->attached) {
6619  if (who)
6620  cm_msg(MERROR, who, "invalid buffer handle %d: not attached", buffer_handle);
6621  if (pstatus)
6622  *pstatus = BM_INVALID_HANDLE;
6623  return NULL;
6624  }
6625 
6626  if (pstatus)
6627  *pstatus = BM_SUCCESS;
6628 
6629  return pbuf;
6630 }
#define BM_INVALID_HANDLE
Definition: midas.h:615
#define BM_SUCCESS
Definition: midas.h:611
std::atomic_bool attached
Definition: midas.h:993
Here is the call graph for this function:
Here is the caller graph for this function:

◆ bm_get_my_client()

static BUFFER_CLIENT * bm_get_my_client ( BUFFER pbuf,
BUFFER_HEADER pheader 
)
static

Definition at line 5962 of file midas.cxx.

5962  {
5963  int my_client_index = bm_validate_client_index(pbuf, TRUE);
5964  return pheader->client + my_client_index;
5965 }
static int bm_validate_client_index(const BUFFER *buf, BOOL abort_if_invalid)
Definition: midas.cxx:5918
#define TRUE
Definition: midas.h:182
BUFFER_CLIENT client[MAX_CLIENTS]
Definition: midas.h:973
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 7911 of file midas.cxx.

7912 {
7913  //printf("bm_lock_buffer_mutex %s!\n", pbuf->buffer_name);
7914 
7915  bool locked = ss_timed_mutex_wait_for_sec(pbuf->buffer_mutex, "buffer mutex", _bm_mutex_timeout_sec);
7916 
7917  if (!locked) {
7918  fprintf(stderr, "bm_lock_buffer_mutex: Error: Cannot lock buffer \"%s\", ss_timed_mutex_wait_for_sec() timeout, aborting...\n", pbuf->buffer_name);
7919  cm_msg(MERROR, "bm_lock_buffer_mutex", "Cannot lock buffer \"%s\", ss_timed_mutex_wait_for_sec() timeout, aborting...", pbuf->buffer_name);
7920  abort();
7921  /* DOES NOT RETURN */
7922  }
7923 
7924  if (!pbuf->attached) {
7925  pbuf->buffer_mutex.unlock();
7926  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);
7927  return BM_INVALID_HANDLE;
7928  }
7929 
7930  //static int counter = 0;
7931  //counter++;
7932  //printf("locked %d!\n", counter);
7933  //if (counter > 50)
7934  // ::sleep(3);
7935 
7936  return BM_SUCCESS;
7937 }
static double _bm_mutex_timeout_sec
Definition: midas.cxx:5916
bool ss_timed_mutex_wait_for_sec(std::timed_mutex &mutex, const char *mutex_name, double timeout_sec)
Definition: system.cxx:3204
std::timed_mutex buffer_mutex
Definition: midas.h:994
char buffer_name[NAME_LENGTH]
Definition: midas.h:997
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 7869 of file midas.cxx.

7870 {
7871  bool locked = ss_timed_mutex_wait_for_sec(pbuf->read_cache_mutex, "buffer read cache", _bm_mutex_timeout_sec);
7872 
7873  if (!locked) {
7874  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);
7875  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);
7876  abort();
7877  /* DOES NOT RETURN */
7878  }
7879 
7880  if (!pbuf->attached) {
7881  pbuf->read_cache_mutex.unlock();
7882  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);
7883  return BM_INVALID_HANDLE;
7884  }
7885 
7886  return BM_SUCCESS;
7887 }
std::timed_mutex read_cache_mutex
Definition: midas.h:999
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 7890 of file midas.cxx.

7891 {
7892  bool locked = ss_timed_mutex_wait_for_sec(pbuf->write_cache_mutex, "buffer write cache", _bm_mutex_timeout_sec);
7893 
7894  if (!locked) {
7895  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);
7896  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);
7897  abort();
7898  /* DOES NOT RETURN */
7899  }
7900 
7901  if (!pbuf->attached) {
7902  pbuf->write_cache_mutex.unlock();
7903  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);
7904  return BM_INVALID_HANDLE;
7905  }
7906 
7907  return BM_SUCCESS;
7908 }
std::timed_mutex write_cache_mutex
Definition: midas.h:1004
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 11015 of file midas.cxx.

11035 {
11036  static DWORD last_time = 0;
11037  DWORD now = ss_millitime();
11038 
11039  //printf("bm_notify_client: buffer [%s], socket %d, time %d\n", buffer_name, client_socket, now - last_time);
11040 
11041  BUFFER* fbuf = NULL;
11042 
11043  gBuffersMutex.lock();
11044 
11045  for (size_t i = 0; i < gBuffers.size(); i++) {
11046  BUFFER* pbuf = gBuffers[i];
11047  if (!pbuf || !pbuf->attached)
11048  continue;
11049  if (strcmp(buffer_name, pbuf->buffer_header->name) == 0) {
11050  fbuf = pbuf;
11051  break;
11052  }
11053  }
11054 
11055  gBuffersMutex.unlock();
11056 
11057  if (!fbuf)
11058  return BM_INVALID_HANDLE;
11059 
11060  /* don't send notification if client has no callback defined
11061  to receive events -> client calls bm_receive_event manually */
11062  if (!fbuf->callback)
11063  return DB_SUCCESS;
11064 
11065  int convert_flags = rpc_get_convert_flags();
11066 
11067  /* only send notification once each 500ms */
11068  if (now - last_time < 500)
11069  return DB_SUCCESS;
11070 
11071  last_time = now;
11072 
11073  char buffer[32];
11074  NET_COMMAND *nc = (NET_COMMAND *) buffer;
11075 
11076  nc->header.routine_id = MSG_BM;
11077  nc->header.param_size = 0;
11078 
11079  if (convert_flags) {
11082  }
11083 
11084  //printf("bm_notify_client: Sending MSG_BM! buffer [%s]\n", buffer_name);
11085 
11086  /* send the update notification to the client */
11087  send_tcp(client_socket, (char *) buffer, sizeof(NET_COMMAND_HEADER), 0);
11088 
11089  return BM_SUCCESS;
11090 }
#define DB_SUCCESS
Definition: midas.h:637
#define TID_UINT32
Definition: midas.h:344
#define MSG_BM
Definition: msystem.h:295
DWORD ss_millitime()
Definition: system.cxx:3332
INT send_tcp(int sock, char *buffer, DWORD buffer_size, INT flags)
Definition: system.cxx:5218
void rpc_get_convert_flags(INT *convert_flags)
Definition: midas.cxx:11573
void rpc_convert_single(void *data, INT tid, INT flags, INT convert_flags)
Definition: midas.cxx:11648
DWORD last_time
Definition: mana.cxx:3070
char buffer_name[NAME_LENGTH]
Definition: mevb.c:45
#define RPC_OUTGOING
Definition: midas.h:1583
char name[NAME_LENGTH]
Definition: midas.h:964
BOOL callback
Definition: midas.h:1012
BUFFER_HEADER * buffer_header
Definition: midas.h:998
NET_COMMAND_HEADER header
Definition: msystem.h:286
Here is the call graph for this function:
Here is the caller graph for this function:

◆ bm_validate_client_index()

static int bm_validate_client_index ( const BUFFER buf,
BOOL  abort_if_invalid 
)
static

dox

Definition at line 5918 of file midas.cxx.

5918  {
5919  static int prevent_recursion = 1;
5920  int badindex = 0;
5921  BUFFER_CLIENT *bcl = buf->buffer_header->client;
5922 
5923  if (buf->client_index < 0)
5924  badindex = 1;
5925  else if (buf->client_index > buf->buffer_header->max_client_index)
5926  badindex = 1;
5927  else {
5928  bcl = &(buf->buffer_header->client[buf->client_index]);
5929  if (bcl->name[0] == 0)
5930  badindex = 1;
5931  else if (bcl->pid != ss_getpid())
5932  badindex = 1;
5933  }
5934 
5935 #if 0
5936  printf("bm_validate_client_index: badindex=%d, buf=%p, client_index=%d, max_client_index=%d, client_name=\'%s\', client_pid=%d, pid=%d\n",
5937  badindex, buf, buf->client_index, buf->buffer_header->max_client_index,
5939  ss_getpid());
5940 #endif
5941 
5942  if (badindex) {
5943 
5944  if (!abort_if_invalid)
5945  return -1;
5946 
5947  if (prevent_recursion) {
5948  prevent_recursion = 0;
5949  cm_msg(MERROR, "bm_validate_client_index",
5950  "My client index %d in buffer \'%s\' is invalid: client name \'%s\', pid %d should be my pid %d",
5951  buf->client_index, buf->buffer_header->name, bcl->name, bcl->pid, ss_getpid());
5952  cm_msg(MERROR, "bm_validate_client_index",
5953  "Maybe this client was removed by a timeout. See midas.log. Cannot continue, aborting...");
5954  }
5955 
5956  abort();
5957  }
5958 
5959  return buf->client_index;
5960 }
INT ss_getpid(void)
Definition: system.cxx:1383
char name[NAME_LENGTH]
Definition: midas.h:941
INT max_client_index
Definition: midas.h:966
INT client_index
Definition: midas.h:995
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 5452 of file midas.cxx.

5452  {
5454 }
#define FALSE
Definition: cfortran.h:309
static BOOL _ctrlc_pressed
Definition: midas.cxx:5435
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 1414 of file midas.cxx.

1414  {
1415  /* if connected to server, get time from there */
1416  if (rpc_is_remote()) {
1417  char buf[256];
1418  int status = rpc_call(RPC_CM_ASCTIME, buf, sizeof(buf));
1419  if (status == CM_SUCCESS) {
1420  return buf;
1421  } else {
1422  return "";
1423  }
1424  }
1425 
1426  /* return local time */
1427  return ss_asctime();
1428 }
#define CM_SUCCESS
Definition: midas.h:588
std::string ss_asctime()
Definition: system.cxx:3488
#define RPC_CM_ASCTIME
Definition: mrpc.h:28
bool rpc_is_remote(void)
Definition: midas.cxx:12728
INT rpc_call(DWORD routine_id,...)
Definition: midas.cxx:13630
DWORD status
Definition: odbhist.cxx:39
Here is the call 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 1398 of file midas.cxx.

1398  {
1399  /* if connected to server, get time from there */
1400  if (rpc_is_remote())
1401  return rpc_call(RPC_CM_ASCTIME, str, buf_size);
1402 
1403  /* return local time */
1404  strlcpy(str, ss_asctime().c_str(), buf_size);
1405 
1406  return CM_SUCCESS;
1407 }
size_t EXPRT strlcpy(char *dst, const char *src, size_t size)
char str[256]
Definition: odbhist.cxx:33
Here is the call graph for this function:
Here is the caller 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 1871 of file midas.cxx.

1871  {
1872  if (rpc_is_remote())
1873  return rpc_call(RPC_CM_CHECK_CLIENT, hDB, hKeyClient);
1874 
1875 #ifdef LOCAL_ROUTINES
1876  return db_check_client(hDB, hKeyClient);
1877 #endif /*LOCAL_ROUTINES */
1878  return CM_SUCCESS;
1879 }
INT db_check_client(HNDLE hDB, HNDLE hKeyClient)
Definition: odb.cxx:3049
#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 2203 of file midas.cxx.

2203  {
2204  if (_hKeyClient) {
2205  cm_msg(MERROR, "cm_check_connect", "cm_disconnect_experiment not called at end of program");
2207  }
2208 }
INT cm_msg_flush_buffer()
Definition: midas.cxx:867
static HNDLE _hKeyClient
Definition: midas.cxx:1458
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 3885 of file midas.cxx.

3885  {
3886  INT i, status;
3887  char str[256];
3888  static BOOL first;
3889 
3890  if (_requested_transition == 0)
3891  first = TRUE;
3892 
3894  for (i = 0; _deferred_trans_table[i].transition; i++)
3896  break;
3897 
3899  if (((BOOL(*)(INT, BOOL)) _deferred_trans_table[i].func)(_requested_transition, first)) {
3901  if (status != CM_SUCCESS)
3902  cm_msg(MERROR, "cm_check_deferred_transition", "Cannot perform deferred transition: %s", str);
3903 
3904  /* bypass hotlink and set _requested_transition directly to zero */
3906 
3907  return status;
3908  }
3909  first = FALSE;
3910  }
3911  }
3912 
3913  return SUCCESS;
3914 }
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:5282
static DWORD _deferred_transition_mask
Definition: midas.cxx:3815
static INT _requested_transition
Definition: midas.cxx:3814
#define SUCCESS
Definition: mcstd.h:54
#define TR_SYNC
Definition: midas.h:365
#define TR_DEFERRED
Definition: midas.h:417
static TRANS_TABLE _deferred_trans_table[]
Definition: midas.cxx:252
DWORD BOOL
Definition: midas.h:105
INT transition
Definition: midas.cxx:244
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 7574 of file midas.cxx.

7574  {
7575  if (rpc_is_remote())
7576  return rpc_call(RPC_CM_CLEANUP, client_name);
7577 
7578 #ifdef LOCAL_ROUTINES
7579  {
7580  DWORD interval;
7581  DWORD now = ss_millitime();
7582 
7583  std::vector<BUFFER*> mybuffers;
7584 
7585  gBuffersMutex.lock();
7586  mybuffers = gBuffers;
7587  gBuffersMutex.unlock();
7588 
7589  /* check buffers */
7590  for (BUFFER* pbuf : mybuffers) {
7591  if (!pbuf)
7592  continue;
7593  if (pbuf->attached) {
7594  std::string msg;
7595 
7596  bm_lock_buffer_guard pbuf_guard(pbuf);
7597 
7598  if (!pbuf_guard.is_locked())
7599  continue;
7600 
7601  /* update the last_activity entry to show that we are alive */
7602  BUFFER_HEADER *pheader = pbuf->buffer_header;
7603  BUFFER_CLIENT *pbclient = pheader->client;
7604  int idx = bm_validate_client_index(pbuf, FALSE);
7605  if (idx >= 0)
7606  pbclient[idx].last_activity = ss_millitime();
7607 
7608  /* now check other clients */
7609  for (int j = 0; j < pheader->max_client_index; j++, pbclient++) {
7610  if (j != pbuf->client_index && pbclient->pid &&
7611  (client_name == NULL || client_name[0] == 0
7612  || strncmp(pbclient->name, client_name, strlen(client_name)) == 0)) {
7613  if (ignore_timeout)
7614  interval = 2 * WATCHDOG_INTERVAL;
7615  else
7616  interval = pbclient->watchdog_timeout;
7617 
7618  /* If client process has no activity, clear its buffer entry. */
7619  if (interval > 0
7620  && now > pbclient->last_activity && now - pbclient->last_activity > interval) {
7621 
7622  /* now make again the check with the buffer locked */
7623  if (interval > 0
7624  && now > pbclient->last_activity && now - pbclient->last_activity > interval) {
7625  msg = msprintf(
7626  "Client \'%s\' on \'%s\' removed by cm_cleanup (idle %1.1lfs, timeout %1.0lfs)",
7627  pbclient->name, pheader->name,
7628  (ss_millitime() - pbclient->last_activity) / 1000.0,
7629  interval / 1000.0);
7630 
7631  bm_remove_client_locked(pheader, j);
7632  }
7633 
7634  /* go again through whole list */
7635  j = 0;
7636  }
7637  }
7638  }
7639 
7640  // unlock buffer before calling cm_msg(), if we are SYSMSG, we will deadlock.
7641  pbuf_guard.unlock();
7642 
7643  /* display info message after unlocking buffer */
7644  if (!msg.empty())
7645  cm_msg(MINFO, "cm_cleanup", "%s", msg.c_str());
7646  }
7647  }
7648 
7649  db_cleanup2(client_name, ignore_timeout, now, "cm_cleanup");
7650  }
7651 #endif /* LOCAL_ROUTINES */
7652 
7653  return CM_SUCCESS;
7654 }
void bm_remove_client_locked(BUFFER_HEADER *pheader, int j)
Definition: midas.cxx:5998
#define MINFO
Definition: midas.h:566
void db_cleanup2(const char *client_name, int ignore_timeout, DWORD actual_time, const char *who)
Definition: odb.cxx:2887
#define RPC_CM_CLEANUP
Definition: mrpc.h:23
std::string msprintf(const char *format,...)
Definition: midas.cxx:412
#define WATCHDOG_INTERVAL
Definition: midas.h:295
INT j
Definition: odbhist.cxx:40
DWORD watchdog_timeout
Definition: midas.h:957
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 2760 of file midas.cxx.

2760  {
2761  HNDLE hDB, hKeyRoot, hSubkey, hKey;
2762  INT status, i, length, port;
2764 
2765  /* find client entry in ODB */
2767 
2768  status = db_find_key(hDB, 0, "System/Clients", &hKeyRoot);
2769  if (status != DB_SUCCESS)
2770  return status;
2771 
2772  i = 0;
2773  do {
2774  /* search for client with specific name */
2775  status = db_enum_key(hDB, hKeyRoot, i++, &hSubkey);
2776  if (status == DB_NO_MORE_SUBKEYS)
2777  return CM_NO_CLIENT;
2778 
2779  status = db_find_key(hDB, hSubkey, "Name", &hKey);
2780  if (status != DB_SUCCESS)
2781  return status;
2782 
2783  length = NAME_LENGTH;
2784  status = db_get_data(hDB, hKey, name, &length, TID_STRING);
2785  if (status != DB_SUCCESS)
2786  return status;
2787 
2788  if (equal_ustring(name, client_name)) {
2789  status = db_find_key(hDB, hSubkey, "Server Port", &hKey);
2790  if (status != DB_SUCCESS)
2791  return status;
2792 
2793  length = sizeof(INT);
2794  status = db_get_data(hDB, hKey, &port, &length, TID_INT32);
2795  if (status != DB_SUCCESS)
2796  return status;
2797 
2798  status = db_find_key(hDB, hSubkey, "Host", &hKey);
2799  if (status != DB_SUCCESS)
2800  return status;
2801 
2802  length = sizeof(host_name);
2803  status = db_get_data(hDB, hKey, host_name, &length, TID_STRING);
2804  if (status != DB_SUCCESS)
2805  return status;
2806 
2807  /* client found -> connect to its server port */
2808  return rpc_client_connect(host_name, port, client_name, hConn);
2809  }
2810 
2811 
2812  } while (TRUE);
2813 }
INT cm_get_experiment_database(HNDLE *hDB, HNDLE *hKeyClient)
Definition: midas.cxx:3005
#define CM_NO_CLIENT
Definition: midas.h:590
#define DB_NO_MORE_SUBKEYS
Definition: midas.h:652
#define TID_INT32
Definition: midas.h:346
#define TID_STRING
Definition: midas.h:353
BOOL equal_ustring(const char *str1, const char *str2)
Definition: odb.cxx:3191
INT db_get_data(HNDLE hDB, HNDLE hKey, void *data, INT *buf_size, DWORD type)
Definition: odb.cxx:6529
INT db_find_key(HNDLE hDB, HNDLE hKey, const char *key_name, HNDLE *subhKey)
Definition: odb.cxx:4069
INT db_enum_key(HNDLE hDB, HNDLE hKey, INT idx, HNDLE *subkey_handle)
Definition: odb.cxx:5576
INT rpc_client_connect(const char *host_name, INT port, const char *client_name, HNDLE *hConnection)
Definition: midas.cxx:11979
HNDLE hKey
Definition: lazylogger.cxx:207
char host_name[HOST_NAME_LENGTH]
Definition: mana.cxx:242
HNDLE hSubkey
Definition: mdump.cxx:38
INT HNDLE
Definition: midas.h:132
#define HOST_NAME_LENGTH
Definition: midas.h:280
#define NAME_LENGTH
Definition: midas.h:279
#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()
Definition: fetest_tmfe.cxx:98
INT cm_connect_experiment(const char *host_name, const char *exp_name, const char *client_name, void(*func)(char *))
Definition: midas.cxx:2280
INT cm_disconnect_experiment(void)
Definition: midas.cxx:2840
INT cm_get_environment(char *host_name, int host_name_size, char *exp_name, int exp_name_size)
Definition: midas.cxx:2136
int main(int argc, char *argv[])
Definition: mana.cxx:5320
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 2280 of file midas.cxx.

2280  {
2281  INT status;
2282 
2285  if (status != CM_SUCCESS) {
2286  std::string s = cm_get_error(status);
2287  puts(s.c_str());
2288  }
2289 
2290  return status;
2291 }
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:2299
std::string cm_get_error(INT code)
Definition: midas.cxx:457
#define DEFAULT_WATCHDOG_TIMEOUT
Definition: midas.h:297
#define DEFAULT_ODB_SIZE
Definition: midas.h:277
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 2299 of file midas.cxx.

2300  {
2301  INT status, size;
2302  char client_name1[NAME_LENGTH];
2303  char password[NAME_LENGTH], str[256];
2304  HNDLE hDB = 0, hKeyClient = 0;
2305  BOOL call_watchdog;
2306 
2307  ss_tzset(); // required for localtime_r()
2308 
2309  if (_hKeyClient)
2311 
2313 
2314  //cm_msg(MERROR, "cm_connect_experiment", "test cm_msg before connecting to experiment");
2315  //cm_msg_flush_buffer();
2316 
2317  rpc_set_name(client_name);
2318 
2319  /* check for local host */
2320  if (equal_ustring(host_name, "local"))
2321  host_name = NULL;
2322 
2323 #ifdef OS_WINNT
2324  {
2325  WSADATA WSAData;
2326 
2327  /* Start windows sockets */
2328  if (WSAStartup(MAKEWORD(1, 1), &WSAData) != 0)
2329  return RPC_NET_ERROR;
2330  }
2331 #endif
2332 
2333  std::string default_exp_name1;
2334  if (default_exp_name)
2335  default_exp_name1 = default_exp_name;
2336 
2337  /* connect to MIDAS server */
2338  if (host_name && host_name[0]) {
2339  if (default_exp_name1.length() == 0) {
2340  status = cm_select_experiment_remote(host_name, &default_exp_name1);
2341  if (status != CM_SUCCESS)
2342  return status;
2343  }
2344 
2345  cm_set_experiment_name(default_exp_name1.c_str());
2346 
2347  status = rpc_server_connect(host_name, default_exp_name1.c_str());
2348  if (status != RPC_SUCCESS)
2349  return status;
2350 
2351  /* register MIDAS library functions */
2353  if (status != RPC_SUCCESS)
2354  return status;
2355  } else {
2356  /* lookup path for *SHM files and save it */
2357 
2358 #ifdef LOCAL_ROUTINES
2359  status = cm_set_experiment_local(default_exp_name1.c_str());
2360  if (status != CM_SUCCESS)
2361  return status;
2362 
2363  default_exp_name1 = cm_get_experiment_name();
2364 
2366 
2367  INT semaphore_elog, semaphore_alarm, semaphore_history, semaphore_msg;
2368 
2369  /* create alarm and elog semaphores */
2370  status = ss_semaphore_create("ALARM", &semaphore_alarm);
2371  if (status != SS_CREATED && status != SS_SUCCESS) {
2372  cm_msg(MERROR, "cm_connect_experiment", "Cannot create alarm semaphore");
2373  return status;
2374  }
2375  status = ss_semaphore_create("ELOG", &semaphore_elog);
2376  if (status != SS_CREATED && status != SS_SUCCESS) {
2377  cm_msg(MERROR, "cm_connect_experiment", "Cannot create elog semaphore");
2378  return status;
2379  }
2380  status = ss_semaphore_create("HISTORY", &semaphore_history);
2381  if (status != SS_CREATED && status != SS_SUCCESS) {
2382  cm_msg(MERROR, "cm_connect_experiment", "Cannot create history semaphore");
2383  return status;
2384  }
2385  status = ss_semaphore_create("MSG", &semaphore_msg);
2386  if (status != SS_CREATED && status != SS_SUCCESS) {
2387  cm_msg(MERROR, "cm_connect_experiment", "Cannot create message semaphore");
2388  return status;
2389  }
2390 
2391  cm_set_experiment_semaphore(semaphore_alarm, semaphore_elog, semaphore_history, semaphore_msg);
2392 #else
2393  return CM_UNDEF_EXP;
2394 #endif
2395  }
2396 
2397  //cm_msg(MERROR, "cm_connect_experiment", "test cm_msg before open ODB");
2398  //cm_msg_flush_buffer();
2399 
2400  /* open ODB */
2401  if (odb_size == 0)
2403 
2404  status = db_open_database("ODB", odb_size, &hDB, client_name);
2405  if (status != DB_SUCCESS && status != DB_CREATED) {
2406  cm_msg(MERROR, "cm_connect_experiment1", "cannot open database, db_open_database() status %d", status);
2407  return status;
2408  }
2409 
2410  //cm_msg(MERROR, "cm_connect_experiment", "test cm_msg after open ODB");
2411  //cm_msg_flush_buffer();
2412 
2413  int odb_timeout = db_set_lock_timeout(hDB, 0);
2414  size = sizeof(odb_timeout);
2415  status = db_get_value(hDB, 0, "/Experiment/ODB timeout", &odb_timeout, &size, TID_INT32, TRUE);
2416  if (status != DB_SUCCESS) {
2417  cm_msg(MERROR, "cm_connect_experiment1", "cannot get ODB /Experiment/ODB timeout, status %d", status);
2418  }
2419 
2420  if (odb_timeout > 0) {
2421  db_set_lock_timeout(hDB, odb_timeout);
2422  }
2423 
2424  BOOL protect_odb = FALSE;
2425  size = sizeof(protect_odb);
2426  status = db_get_value(hDB, 0, "/Experiment/Protect ODB", &protect_odb, &size, TID_BOOL, TRUE);
2427  if (status != DB_SUCCESS) {
2428  cm_msg(MERROR, "cm_connect_experiment1", "cannot get ODB /Experiment/Protect ODB, status %d", status);
2429  }
2430 
2431  if (protect_odb) {
2433  }
2434 
2435  BOOL enable_core_dumps = FALSE;
2436  size = sizeof(enable_core_dumps);
2437  status = db_get_value(hDB, 0, "/Experiment/Enable core dumps", &enable_core_dumps, &size, TID_BOOL, TRUE);
2438  if (status != DB_SUCCESS) {
2439  cm_msg(MERROR, "cm_connect_experiment1", "cannot get ODB /Experiment/Enable core dumps, status %d", status);
2440  }
2441 
2442  if (enable_core_dumps) {
2443 #ifdef RLIMIT_CORE
2444  struct rlimit limit;
2445  limit.rlim_cur = RLIM_INFINITY;
2446  limit.rlim_max = RLIM_INFINITY;
2447  status = setrlimit(RLIMIT_CORE, &limit);
2448  if (status != 0) {
2449  cm_msg(MERROR, "cm_connect_experiment", "Cannot setrlimit(RLIMIT_CORE, RLIM_INFINITY), errno %d (%s)", errno,
2450  strerror(errno));
2451  }
2452 #else
2453 #warning setrlimit(RLIMIT_CORE) is not available
2454 #endif
2455  }
2456 
2457  size = sizeof(disable_bind_rpc_to_localhost);
2458  status = db_get_value(hDB, 0, "/Experiment/Security/Enable non-localhost RPC", &disable_bind_rpc_to_localhost, &size,
2459  TID_BOOL, TRUE);
2460  if (status != DB_SUCCESS) {
2461  cm_msg(MERROR, "cm_connect_experiment1",
2462  "cannot get ODB /Experiment/Security/Enable non-localhost RPC, status %d", status);
2463  }
2464 
2465  std::string local_host_name;
2466 
2467  /* now setup client info */
2469  local_host_name = "localhost";
2470  else
2471  local_host_name = ss_gethostname();
2472 
2473  /* check watchdog timeout */
2474  if (watchdog_timeout == 0)
2475  watchdog_timeout = DEFAULT_WATCHDOG_TIMEOUT;
2476 
2477  strcpy(client_name1, client_name);
2478  password[0] = 0;
2479  status = cm_set_client_info(hDB, &hKeyClient, local_host_name.c_str(), client_name1, rpc_get_hw_type(), password, watchdog_timeout);
2480 
2481  if (status == CM_WRONG_PASSWORD) {
2482  if (func == NULL)
2483  strcpy(str, ss_getpass("Password: "));
2484  else
2485  func(str);
2486 
2487  strcpy(password, ss_crypt(str, "mi"));
2488  status = cm_set_client_info(hDB, &hKeyClient, local_host_name.c_str(), client_name1, rpc_get_hw_type(), password, watchdog_timeout);
2489  if (status != CM_SUCCESS) {
2490  /* disconnect */
2491  if (rpc_is_remote())
2494 
2495  return status;
2496  }
2497  }
2498 
2499  //cm_msg(MERROR, "cm_connect_experiment", "test cm_msg after set client info");
2500  //cm_msg_flush_buffer();
2501 
2502  /* tell the rest of MIDAS that ODB is open for business */
2503 
2504  cm_set_experiment_database(hDB, hKeyClient);
2505 
2506  //cm_msg(MERROR, "cm_connect_experiment", "test cm_msg after set experiment database");
2507  //cm_msg_flush_buffer();
2508 
2509  /* cm_msg_open_buffer() calls bm_open_buffer() calls ODB function
2510  * to get event buffer size, etc */
2511 
2513  if (status != CM_SUCCESS) {
2514  cm_msg(MERROR, "cm_connect_experiment1", "cannot open message buffer, cm_msg_open_buffer() status %d", status);
2515  return status;
2516  }
2517 
2518  //cm_msg(MERROR, "cm_connect_experiment", "test cm_msg after message system is ready");
2519  //cm_msg_flush_buffer();
2520 
2521  /* set experiment name in ODB if not present */
2522  std::string current_name;
2523  db_get_value_string(hDB, 0, "/Experiment/Name", 0, &current_name, TRUE);
2524  if (current_name.length() == 0 || current_name == "Default") {
2525  db_set_value_string(hDB, 0, "/Experiment/Name", &default_exp_name1);
2526  }
2527 
2528  if (!rpc_is_remote()) {
2529  /* experiment path is only set for local connections */
2530  /* set data dir in ODB */
2531  std::string path = cm_get_path();
2532  db_get_value_string(hDB, 0, "/Logger/Data dir", 0, &path, TRUE);
2533  }
2534 
2535  /* register server to be able to be called by other clients */
2537  if (status != CM_SUCCESS) {
2538  cm_msg(MERROR, "cm_connect_experiment", "Cannot register RPC server, cm_register_server() status %d", status);
2539  if (!equal_ustring(client_name, "odbedit")) {
2540  return status;
2541  }
2542  }
2543 
2544  /* set watchdog timeout */
2545  cm_get_watchdog_params(&call_watchdog, &watchdog_timeout);
2546  size = sizeof(watchdog_timeout);
2547  sprintf(str, "/Programs/%s/Watchdog Timeout", client_name);
2548  db_get_value(hDB, 0, str, &watchdog_timeout, &size, TID_INT32, TRUE);
2549  cm_set_watchdog_params(call_watchdog, watchdog_timeout);
2550 
2551  /* get final client name */
2552  std::string xclient_name = rpc_get_name();
2553 
2554  /* startup message is not displayed */
2555  cm_msg(MLOG, "cm_connect_experiment", "Program %s on host %s started", xclient_name.c_str(), local_host_name.c_str());
2556 
2557  /* enable system and user messages to stdout as default */
2558  cm_set_msg_print(MT_ALL, MT_ALL, puts);
2559 
2560  /* call cm_check_connect when exiting */
2561  atexit((void (*)(void)) cm_check_connect);
2562 
2563  /* register ctrl-c handler */
2565 
2566  //cm_msg(MERROR, "cm_connect_experiment", "test cm_msg after connect to experiment is complete");
2567  //cm_msg_flush_buffer();
2568 
2569  return CM_SUCCESS;
2570 }
INT cm_get_experiment_name(char *name, int name_length)
Definition: midas.cxx:1572
INT cm_get_watchdog_params(BOOL *call_watchdog, DWORD *timeout)
Definition: midas.cxx:3313
INT cm_select_experiment_remote(const char *host_name, std::string *exp_name)
Definition: midas.cxx:2713
INT cm_register_server(void)
Definition: midas.cxx:3448
void cm_check_connect(void)
Definition: midas.cxx:2203
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:1895
int cm_set_experiment_local(const char *exp_name)
Definition: midas.cxx:2168
INT cm_get_path(char *path, int path_size)
Definition: midas.cxx:1520
INT cm_set_experiment_database(HNDLE hDB, HNDLE hKeyClient)
Definition: midas.cxx:2933
void cm_ctrlc_handler(int sig)
Definition: midas.cxx:5437
INT cm_set_watchdog_params(BOOL call_watchdog, DWORD timeout)
Definition: midas.cxx:3279
INT cm_set_experiment_semaphore(INT semaphore_alarm, INT semaphore_elog, INT semaphore_history, INT semaphore_msg)
Definition: midas.cxx:2952
INT cm_set_experiment_name(const char *name)
Definition: midas.cxx:1560
#define CM_UNDEF_EXP
Definition: midas.h:592
#define CM_WRONG_PASSWORD
Definition: midas.h:595
#define DB_CREATED
Definition: midas.h:638
#define SS_SUCCESS
Definition: midas.h:669
#define SS_CREATED
Definition: midas.h:670
#define RPC_SUCCESS
Definition: midas.h:704
#define RPC_NET_ERROR
Definition: midas.h:707
#define TID_BOOL
Definition: midas.h:347
#define MT_ALL
Definition: midas.h:555
#define MLOG
Definition: midas.h:569
RPC_LIST * rpc_get_internal_list(INT flag)
Definition: mrpc.cxx:716
std::string ss_gethostname()
Definition: system.cxx:5645
INT ss_suspend_init_odb_port()
Definition: system.cxx:4244
INT ss_semaphore_create(const char *name, HNDLE *semaphore_handle)
Definition: system.cxx:2427
char * ss_getpass(const char *prompt)
Definition: system.cxx:7379
void ss_tzset()
Definition: system.cxx:3294
char * ss_crypt(const char *buf, const char *salt)
Definition: system.cxx:7830
void * ss_ctrlc_handler(void(*func)(int))
Definition: system.cxx:3838
int cm_msg_early_init(void)
Definition: midas.cxx:469
int cm_msg_open_buffer(void)
Definition: midas.cxx:476
INT cm_set_msg_print(INT system_mask, INT user_mask, int(*func)(const char *))
Definition: midas.cxx:649
INT db_get_value(HNDLE hDB, HNDLE hKeyRoot, const char *key_name, void *data, INT *buf_size, DWORD type, BOOL create)
Definition: odb.cxx:5405
INT db_open_database(const char *xdatabase_name, INT database_size, HNDLE *hDB, const char *client_name)
Definition: odb.cxx:1778
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:13937
INT EXPRT db_set_value_string(HNDLE hDB, HNDLE hKeyRoot, const char *key_name, const std::string *s)
Definition: odb.cxx:14008
INT db_set_lock_timeout(HNDLE hDB, int timeout_millisec)
Definition: odb.cxx:2652
INT db_protect_database(HNDLE hDB)
Definition: odb.cxx:3157
INT rpc_register_functions(const RPC_LIST *new_list, RPC_HANDLER func)
Definition: midas.cxx:11794
INT rpc_server_connect(const char *host_name, const char *exp_name)
Definition: midas.cxx:12348
std::string rpc_get_name()
Definition: midas.cxx:13051
INT rpc_get_hw_type()
Definition: midas.cxx:12801
INT rpc_server_disconnect()
Definition: midas.cxx:12672
INT rpc_set_name(const char *name)
Definition: midas.cxx:13075
INT odb_size
Definition: analyzer.cxx:46
static int disable_bind_rpc_to_localhost
Definition: midas.cxx:239
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 5437 of file midas.cxx.

5437  {
5438  if (_ctrlc_pressed) {
5439  printf("Received 2nd Ctrl-C, hard abort\n");
5440  exit(0);
5441  }
5442  printf("Received Ctrl-C, aborting...\n");
5443  _ctrlc_pressed = TRUE;
5444 
5446 }
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 1854 of file midas.cxx.

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

3665  {
3666  INT status;
3667  HNDLE hDB, hKey, hKeyTrans;
3668  char str[256];
3669 
3670  /* check for valid transition */
3672  cm_msg(MERROR, "cm_deregister_transition", "Invalid transition request \"%d\"", transition);
3673  return CM_INVALID_TRANSITION;
3674  }
3675 
3677 
3678  {
3679  std::lock_guard<std::mutex> guard(_trans_table_mutex);
3680 
3681  /* remove existing transition request */
3682  for (size_t i = 0; i < _trans_table.size(); i++) {
3683  if (_trans_table[i].transition == transition) {
3684  _trans_table[i].transition = 0;
3685  _trans_table[i].sequence_number = 0;
3686  _trans_table[i].func = NULL;
3687  }
3688  }
3689 
3690  // implicit unlock
3691  }
3692 
3693  sprintf(str, "Transition %s", cm_transition_name(transition).c_str());
3694 
3695  /* unlock database */
3697 
3698  /* set value */
3699  status = db_find_key(hDB, hKey, str, &hKeyTrans);
3700  if (hKeyTrans) {
3701  status = db_delete_key(hDB, hKeyTrans, FALSE);
3702  if (status != DB_SUCCESS)
3703  return status;
3704  }
3705 
3706  /* re-lock database */
3708 
3709  return CM_SUCCESS;
3710 }
#define CM_INVALID_TRANSITION
Definition: midas.h:600
#define TR_RESUME
Definition: midas.h:415
#define TR_PAUSE
Definition: midas.h:414
#define TR_START
Definition: midas.h:412
#define TR_STARTABORT
Definition: midas.h:416
#define MODE_DELETE
Definition: midas.h:379
#define MODE_WRITE
Definition: midas.h:378
#define MODE_READ
Definition: midas.h:377
#define TR_STOP
Definition: midas.h:413
INT db_delete_key(HNDLE hDB, HNDLE hKey, BOOL follow_links)
Definition: odb.cxx:3846
INT db_set_mode(HNDLE hDB, HNDLE hKey, WORD mode, BOOL recurse)
Definition: odb.cxx:8021
static std::vector< TRANS_TABLE > _trans_table
Definition: midas.cxx:250
std::string cm_transition_name(int transition)
Definition: midas.cxx:135
static std::mutex _trans_table_mutex
Definition: midas.cxx:249
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 2827 of file midas.cxx.

2827  {
2828  return rpc_client_disconnect(hConn, bShutdown);
2829 }
INT rpc_client_disconnect(HNDLE hConn, BOOL bShutdown)
Definition: midas.cxx:12643
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 2840 of file midas.cxx.

2840  {
2841  HNDLE hDB, hKey;
2842 
2843  //cm_msg(MERROR, "cm_disconnect_experiment", "test cm_msg before disconnect from experiment");
2844  //cm_msg_flush_buffer();
2845 
2846  /* wait on any transition thread */
2847  if (_trp.transition && !_trp.finished) {
2848  printf("Waiting for transition to finish...\n");
2849  do {
2850  ss_sleep(10);
2851  } while (!_trp.finished);
2852  }
2853 
2854  /* stop the watchdog thread */
2856 
2857  /* send shutdown notification */
2858  std::string client_name = rpc_get_name();
2859 
2860  std::string local_host_name;
2861 
2863  local_host_name = "localhost";
2864  else {
2865  local_host_name = ss_gethostname();
2866  //if (strchr(local_host_name, '.'))
2867  // *strchr(local_host_name, '.') = 0;
2868  }
2869 
2870  /* disconnect message not displayed */
2871  cm_msg(MLOG, "cm_disconnect_experiment", "Program %s on host %s stopped", client_name.c_str(), local_host_name.c_str());
2873 
2874  if (rpc_is_remote()) {
2875  if (rpc_is_connected()) {
2876  /* close open records */
2878 
2880  }
2881 
2884 
2886  } else {
2888 
2889  /* delete client info */
2891 
2892  if (hDB)
2894 
2895  //cm_msg(MERROR, "cm_disconnect_experiment", "test cm_msg before close all buffers, close all databases");
2896  //cm_msg_flush_buffer();
2897 
2901 
2903 
2904  //cm_msg(MERROR, "cm_disconnect_experiment", "test cm_msg after close all buffers, close all databases");
2905  //cm_msg_flush_buffer();
2906  }
2907 
2908  if (!rpc_is_mserver())
2910 
2911  /* free RPC list */
2913 
2914  //cm_msg(MERROR, "cm_disconnect_experiment", "test cm_msg before deleting the message ring buffer");
2915  //cm_msg_flush_buffer();
2916 
2917  /* last flush before we delete the message ring buffer */
2919 
2920  //cm_msg(MERROR, "cm_disconnect_experiment", "test cm_msg after disconnect is completed");
2921  //cm_msg_flush_buffer();
2922 
2923  return CM_SUCCESS;
2924 }
INT bm_close_all_buffers(void)
Definition: midas.cxx:7207
INT cm_stop_watchdog_thread()
Definition: midas.cxx:7334
static void rpc_client_shutdown()
Definition: midas.cxx:12599
INT cm_delete_client_info(HNDLE hDB, INT pid)
Definition: midas.cxx:1854
INT ss_sleep(INT millisec)
Definition: system.cxx:3567
int cm_msg_close_buffer(void)
Definition: midas.cxx:489
INT db_close_all_records()
Definition: odb.cxx:13518
INT db_close_all_databases(void)
Definition: odb.cxx:2351
INT rpc_deregister_functions()
Definition: midas.cxx:11837
bool rpc_is_connected(void)
Definition: midas.cxx:12750
INT rpc_server_shutdown(void)
Definition: midas.cxx:16150
bool rpc_is_mserver(void)
Definition: midas.cxx:12785
static TR_PARAM _trp
Definition: midas.cxx:304
std::atomic_bool finished
Definition: midas.cxx:300
INT transition
Definition: midas.cxx:293
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 5381 of file midas.cxx.

5400 {
5401  if (message[0] == 'O') {
5402  HNDLE hDB, hKey, hKeyRoot;
5403  INT index;
5404  index = 0;
5405  sscanf(message + 2, "%d %d %d %d", &hDB, &hKeyRoot, &hKey, &index);
5406  if (client_socket) {
5407  return db_update_record_mserver(hDB, hKeyRoot, hKey, index, client_socket);
5408  } else {
5409  return db_update_record_local(hDB, hKeyRoot, hKey, index);
5410  }
5411  }
5412 
5413  /* message == "B" means "resume event sender" */
5414  if (message[0] == 'B' && message[2] != ' ') {
5415  char str[NAME_LENGTH];
5416 
5417  //printf("cm_dispatch_ipc: message [%s], s=%d\n", message, s);
5418 
5419  strlcpy(str, message + 2, sizeof(str));
5420  if (strchr(str, ' '))
5421  *strchr(str, ' ') = 0;
5422 
5423  if (client_socket)
5424  return bm_notify_client(str, client_socket);
5425  else
5426  return bm_push_event(str);
5427  }
5428 
5429  //printf("cm_dispatch_ipc: message [%s] ignored\n", message);
5430 
5431  return CM_SUCCESS;
5432 }
static INT bm_push_event(const char *buffer_name)
Definition: midas.cxx:10885
static INT bm_notify_client(const char *buffer_name, int s)
Definition: midas.cxx:11015
INT db_update_record_local(INT hDB, INT hKeyRoot, INT hKey, int index)
Definition: odb.cxx:13556
INT db_update_record_mserver(INT hDB, INT hKeyRoot, INT hKey, int index, int client_socket)
Definition: odb.cxx:13603
INT index
Definition: mana.cxx:271
#define message(type, str)
Definition: midas_macro.h:262
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 5457 of file midas.cxx.

5485 {
5486  HNDLE hDB, hkey;
5487  KEY key;
5488  int status;
5489 
5491  if (status != DB_SUCCESS)
5492  return status;
5493 
5494  status = db_find_key(hDB, 0, odb_path_to_script, &hkey);
5495  if (status != DB_SUCCESS)
5496  return status;
5497 
5498  status = db_get_key(hDB, hkey, &key);
5499  if (status != DB_SUCCESS)
5500  return status;
5501 
5502  std::string command;
5503 
5504  if (key.type == TID_STRING) {
5505  int status = db_get_value_string(hDB, 0, odb_path_to_script, 0, &command, FALSE);
5506  if (status != DB_SUCCESS) {
5507  cm_msg(MERROR, "cm_exec_script", "Script ODB \"%s\" of type TID_STRING, db_get_value_string() error %d",
5508  odb_path_to_script, status);
5509  return status;
5510  }
5511  } else if (key.type == TID_KEY) {
5512  for (int i = 0;; i++) {
5513  HNDLE hsubkey;
5514  KEY subkey;
5515  db_enum_key(hDB, hkey, i, &hsubkey);
5516  if (!hsubkey)
5517  break;
5518  db_get_key(hDB, hsubkey, &subkey);
5519 
5520  if (i > 0)
5521  command += " ";
5522 
5523  if (subkey.type == TID_KEY) {
5524  cm_msg(MERROR, "cm_exec_script", "Script ODB \"%s/%s\" should not be TID_KEY", odb_path_to_script,
5525  subkey.name);
5526  return DB_TYPE_MISMATCH;
5527  } else {
5528  int size = subkey.item_size;
5529  char *buf = (char *) malloc(size);
5530  assert(buf != NULL);
5531  int status = db_get_data(hDB, hsubkey, buf, &size, subkey.type);
5532  if (status != DB_SUCCESS) {
5533  cm_msg(MERROR, "cm_exec_script", "Script ODB \"%s/%s\" of type %d, db_get_data() error %d",
5534  odb_path_to_script, subkey.name, subkey.type, status);
5535  free(buf);
5536  return status;
5537  }
5538  if (subkey.type == TID_STRING) {
5539  command += buf;
5540  } else {
5541  command += db_sprintf(buf, subkey.item_size, 0, subkey.type);
5542  }
5543  free(buf);
5544  }
5545  }
5546  } else {
5547  cm_msg(MERROR, "cm_exec_script", "Script ODB \"%s\" has invalid type %d, should be TID_STRING or TID_KEY",
5548  odb_path_to_script, key.type);
5549  return DB_TYPE_MISMATCH;
5550  }
5551 
5552  // printf("exec_script: %s\n", command.c_str());
5553 
5554  if (command.length() > 0) {
5555  cm_msg(MINFO, "cm_exec_script", "Executing script \"%s\" from ODB \"%s\"", command.c_str(), odb_path_to_script);
5556  ss_system(command.c_str());
5557  }
5558 
5559  return SUCCESS;
5560 }
#define DB_TYPE_MISMATCH
Definition: midas.h:651
#define TID_KEY
Definition: midas.h:356
INT ss_system(const char *command)
Definition: system.cxx:2087
INT db_get_key(HNDLE hDB, HNDLE hKey, KEY *key)
Definition: odb.cxx:6009
INT db_sprintf(char *string, const void *data, INT data_size, INT idx, DWORD type)
Definition: odb.cxx:10847
KEY key
Definition: mdump.cxx:37
Definition: midas.h:1032
DWORD type
Definition: midas.h:1033
char name[NAME_LENGTH]
Definition: midas.h:1035
INT item_size
Definition: midas.h:1038
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 5719 of file midas.cxx.

5719  {
5720  char str[256];
5721  INT n;
5722  int fh;
5723  int status = 0;
5724  static int check_cm_execute = 1;
5725  static int enable_cm_execute = 0;
5726 
5727  if (rpc_is_remote())
5728  return rpc_call(RPC_CM_EXECUTE, command, result, bufsize);
5729 
5730  if (check_cm_execute) {
5731  int status;
5732  int size;
5733  HNDLE hDB;
5734  check_cm_execute = 0;
5735 
5737  assert(status == DB_SUCCESS);
5738 
5739  size = sizeof(enable_cm_execute);
5740  status = db_get_value(hDB, 0, "/Experiment/Enable cm_execute", &enable_cm_execute, &size, TID_BOOL, TRUE);
5741  assert(status == DB_SUCCESS);
5742 
5743  //printf("enable_cm_execute %d\n", enable_cm_execute);
5744  }
5745 
5746  if (!enable_cm_execute) {
5747  char buf[32];
5748  strlcpy(buf, command, sizeof(buf));
5749  cm_msg(MERROR, "cm_execute", "cm_execute(%s...) is disabled by ODB \"/Experiment/Enable cm_execute\"", buf);
5750  return CM_WRONG_PASSWORD;
5751  }
5752 
5753  if (bufsize > 0) {
5754  strcpy(str, command);
5755  sprintf(str, "%s > %d.tmp", command, ss_getpid());
5756 
5757  status = system(str);
5758 
5759  sprintf(str, "%d.tmp", ss_getpid());
5760  fh = open(str, O_RDONLY, 0644);
5761  result[0] = 0;
5762  if (fh) {
5763  n = read(fh, result, bufsize - 1);
5764  result[MAX(0, n)] = 0;
5765  close(fh);
5766  }
5767  remove(str);
5768  } else {
5769  status = system(command);
5770  }
5771 
5772  if (status < 0) {
5773  cm_msg(MERROR, "cm_execute", "cm_execute(%s) error %d", command, status);
5774  return CM_SET_ERROR;
5775  }
5776 
5777  return CM_SUCCESS;
5778 }
#define CM_SET_ERROR
Definition: midas.h:589
#define MAX(a, b)
Definition: midas.h:515
#define RPC_CM_EXECUTE
Definition: mrpc.h:26
DWORD n[4]
Definition: mana.cxx:247
#define read(n, a, f)
Definition: midas_macro.h:242
static std::string remove(const std::string s, char c)
Definition: mjsonrpc.cxx:252
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 7484 of file midas.cxx.

7484  {
7485  INT status, i, size;
7486  HNDLE hDB, hKeyClient, hKey, hSubkey;
7487  char client_name[NAME_LENGTH];
7488 
7489  if (rpc_is_remote())
7490  return rpc_call(RPC_CM_EXIST, name, bUnique);
7491 
7492  cm_get_experiment_database(&hDB, &hKeyClient);
7493 
7494  status = db_find_key(hDB, 0, "System/Clients", &hKey);
7495  if (status != DB_SUCCESS)
7496  return DB_NO_KEY;
7497 
7499 
7500  /* loop over all clients */
7501  for (i = 0;; i++) {
7503  if (status == DB_NO_MORE_SUBKEYS)
7504  break;
7505 
7506  if (hSubkey == hKeyClient)
7507  continue;
7508 
7509  if (status == DB_SUCCESS) {
7510  /* get client name */
7511  size = sizeof(client_name);
7512  status = db_get_value(hDB, hSubkey, "Name", client_name, &size, TID_STRING, FALSE);
7513 
7514  if (status != DB_SUCCESS) {
7515  //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);
7516  continue;
7517  }
7518 
7519  if (equal_ustring(client_name, name)) {
7521  return CM_SUCCESS;
7522  }
7523 
7524  if (!bUnique) {
7525  client_name[strlen(name)] = 0; /* strip number */
7526  if (equal_ustring(client_name, name)) {
7528  return CM_SUCCESS;
7529  }
7530  }
7531  }
7532  }
7533 
7535 
7536  return CM_NO_CLIENT;
7537 }
#define DB_NO_KEY
Definition: midas.h:648
INT db_lock_database(HNDLE hDB)
Definition: odb.cxx:2446
INT db_unlock_database(HNDLE hDB)
Definition: odb.cxx:2565
#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 7675 of file midas.cxx.

7675  {
7676  const char *s = str;
7677  std::string r;
7678  for (; *s;) {
7679  if (*s == '$') {
7680  s++;
7681  std::string envname;
7682  for (; *s;) {
7683  if (*s == DIR_SEPARATOR)
7684  break;
7685  envname += *s;
7686  s++;
7687  }
7688  const char *e = getenv(envname.c_str());
7689  //printf("expanding [%s] at [%s] envname [%s] value [%s]\n", filename, s, envname.c_str(), e);
7690  if (!e) {
7691  //cm_msg(MERROR, "expand_env", "Env.variable \"%s\" cannot be expanded in \"%s\"", envname.c_str(), filename);
7692  r += '$';
7693  r += envname;
7694  } else {
7695  r += e;
7696  //if (r[r.length()-1] != DIR_SEPARATOR)
7697  //r += DIR_SEPARATOR_STR;
7698  }
7699  } else {
7700  r += *s;
7701  s++;
7702  }
7703  }
7704  return r;
7705 }
#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 2061 of file midas.cxx.

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

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

2151  {
2152  if (host_name)
2153  *host_name = "";
2154  if (exp_name)
2155  *exp_name = "";
2156 
2157  if (host_name && getenv("MIDAS_SERVER_HOST"))
2158  *host_name = getenv("MIDAS_SERVER_HOST");
2159 
2160  if (exp_name && getenv("MIDAS_EXPT_NAME"))
2161  *exp_name = getenv("MIDAS_EXPT_NAME");
2162 
2163  return CM_SUCCESS;
2164 }

◆ cm_get_experiment_database()

INT cm_get_experiment_database ( HNDLE hDB,
HNDLE hKeyClient 
)

dox Get the handle to the ODB from the currently connected experiment.

Attention
This function returns the handle of the online database (ODB) which can be used in future db_xxx() calls. The hkeyclient key handle can be used to access the client information in the ODB. If the client key handle is not needed, the parameter can be NULL.
HNDLE hDB, hkeyclient;
char name[32];
int size;
db_get_experiment_database(&hdb, &hkeyclient);
size = sizeof(name);
db_get_value(hdb, hkeyclient, "Name", name, &size, TID_STRING, TRUE);
printf("My name is %s\n", name);
HNDLE hdb
Definition: midas_macro.h:21
Parameters
hDBDatabase handle.
hKeyClientHandle for key where search starts, zero for root.
Returns
CM_SUCCESS

Definition at line 3005 of file midas.cxx.

3005  {
3006  if (_hDB) {
3007  //printf("cm_get_experiment_database %d %d\n", _hDB, _hKeyClient);
3008  if (hDB != NULL)
3009  *hDB = _hDB;
3010  if (hKeyClient != NULL)
3011  *hKeyClient = _hKeyClient;
3012  return CM_SUCCESS;
3013  } else {
3014  //printf("cm_get_experiment_database no init\n");
3015  if (hDB != NULL)
3016  *hDB = 0;
3017  if (hKeyClient != NULL)
3018  *hKeyClient = 0;
3019  return CM_DB_ERROR;
3020  }
3021 }
#define CM_DB_ERROR
Definition: midas.h:591
static HNDLE _hDB
Definition: midas.cxx:1459

◆ cm_get_experiment_name() [1/2]

std::string cm_get_experiment_name ( )

Return the experiment name

Returns
experiment name

Definition at line 1582 of file midas.cxx.

1582  {
1583  return _experiment_name;
1584 }
static std::string _experiment_name
Definition: midas.cxx:1460

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

1572  {
1573  strlcpy(name, _experiment_name.c_str(), name_length);
1574  return CM_SUCCESS;
1575 }
Here is the call graph for this function:
Here is the caller 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 3027 of file midas.cxx.

3047 {
3048  if (semaphore_alarm)
3049  *semaphore_alarm = _semaphore_alarm;
3050  if (semaphore_elog)
3051  *semaphore_elog = _semaphore_elog;
3052  if (semaphore_history)
3053  *semaphore_history = _semaphore_history;
3054  //if (semaphore_msg)
3055  // *semaphore_msg = _semaphore_msg;
3056  if (semaphore_msg)
3057  *semaphore_msg = -1;
3058 
3059  return CM_SUCCESS;
3060 }
INT _semaphore_alarm
Definition: midas.cxx:1464
INT _semaphore_elog
Definition: midas.cxx:1465
INT _semaphore_history
Definition: midas.cxx:1466
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 1832 of file midas.cxx.

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

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

1790  {
1791  return _exptab.filename;
1792 }
std::string filename
Definition: midas.cxx:1603

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

1785  {
1786  strlcpy(s, _exptab.filename.c_str(), size);
1787  return CM_SUCCESS;
1788 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_get_history_path()

std::string cm_get_history_path ( const char *  history_channel)

dox

Definition at line 5839 of file midas.cxx.

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

1539  {
1540  assert(_path_name.length() > 0);
1541  return _path_name;
1542 }
static std::string _path_name
Definition: midas.cxx:1462

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

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

◆ cm_get_path_string()

INT EXPRT cm_get_path_string ( std::string *  path)

Definition at line 1547 of file midas.cxx.

1547  {
1548  assert(path != NULL);
1549  assert(_path_name.length() > 0);
1550  *path = _path_name;
1551  return CM_SUCCESS;
1552 }

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

1486  {
1487  return GIT_REVISION;
1488 }
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 1478 of file midas.cxx.

1478  {
1479  return MIDAS_VERSION;
1480 }
#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 3332 of file midas.cxx.

3332  {
3333  if (rpc_is_remote())
3334  return rpc_call(RPC_CM_GET_WATCHDOG_INFO, hDB, client_name, timeout, last);
3335 
3336 #ifdef LOCAL_ROUTINES
3337  return db_get_watchdog_info(hDB, client_name, timeout, last);
3338 #else /* LOCAL_ROUTINES */
3339  return CM_SUCCESS;
3340 #endif /* LOCAL_ROUTINES */
3341 }
INT db_get_watchdog_info(HNDLE hDB, const char *client_name, DWORD *timeout, DWORD *last)
Definition: odb.cxx:3004
#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 3313 of file midas.cxx.

3313  {
3314  if (call_watchdog)
3315  *call_watchdog = FALSE;
3316  if (timeout)
3317  *timeout = _watchdog_timeout;
3318 
3319  return CM_SUCCESS;
3320 }
static INT _watchdog_timeout
Definition: midas.cxx:1463
Here is the caller graph for this function:

◆ cm_is_ctrlc_pressed()

BOOL cm_is_ctrlc_pressed ( void  )

Definition at line 5448 of file midas.cxx.

5448  {
5449  return _ctrlc_pressed;
5450 }
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 2580 of file midas.cxx.

2580  {
2581  assert(exp_names != NULL);
2582  exp_names->clear();
2583 
2584  if (_exptab.exptab.size() == 0) {
2585  int status = cm_read_exptab(&_exptab);
2586  if (status != CM_SUCCESS)
2587  return status;
2588  }
2589 
2590  for (unsigned i=0; i<_exptab.exptab.size(); i++) {
2591  exp_names->push_back(_exptab.exptab[i].name);
2592  }
2593 
2594  return CM_SUCCESS;
2595 }
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 2606 of file midas.cxx.

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

5575  {
5576  static DWORD alarm_last_checked_sec = 0;
5577  DWORD now_sec = ss_time();
5578 
5579  DWORD now_millitime = ss_millitime();
5580  static DWORD last_millitime = 0;
5581  DWORD tdiff_millitime = now_millitime - last_millitime;
5582  const DWORD kPeriod = 1000;
5583  if (last_millitime == 0) {
5584  last_millitime = now_millitime;
5585  tdiff_millitime = kPeriod; // make sure first time we come here we do something.
5586  }
5587 
5588  //printf("cm_periodic_tasks! tdiff_millitime %d\n", (int)tdiff_millitime);
5589 
5590  //if (now_millitime < last_millitime) {
5591  // printf("millitime wraparound 0x%08x -> 0x%08x\n", last_millitime, now_millitime);
5592  //}
5593 
5594  /* check alarms once every 10 seconds */
5595  if (now_sec - alarm_last_checked_sec > 10) {
5596  al_check();
5597  alarm_last_checked_sec = now_sec;
5598  }
5599 
5600  /* run periodic checks previously done by cm_watchdog */
5601 
5602  if (tdiff_millitime >= kPeriod) {
5603  BOOL wrong_interval = FALSE;
5604  if (tdiff_millitime > 60000)
5605  wrong_interval = TRUE;
5606 
5607  //printf("millitime %u, diff %u, wrong_interval %d\n", now_millitime, tdiff_millitime, wrong_interval);
5608 
5609  bm_cleanup("cm_periodic_tasks", now_millitime, wrong_interval);
5610  db_cleanup("cm_periodic_tasks", now_millitime, wrong_interval);
5611 
5613 
5614  last_millitime = now_millitime;
5615  }
5616 
5617  /* reap transition thread */
5618 
5620 
5621  return CM_SUCCESS;
5622 }
INT al_check()
Definition: alarm.cxx:561
INT bm_write_statistics_to_odb(void)
Definition: midas.cxx:7244
static void bm_cleanup(const char *who, DWORD actual_time, BOOL wrong_interval)
Definition: midas.cxx:6115
INT cm_transition_cleanup()
Definition: midas.cxx:5263
DWORD ss_time()
Definition: system.cxx:3401
void db_cleanup(const char *who, DWORD actual_time, BOOL wrong_interval)
Definition: odb.cxx:2817
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 1616 of file midas.cxx.

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

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

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

3466 {
3467  if (!_rpc_registered) {
3468  INT status;
3469  int size;
3470  HNDLE hDB, hKey;
3471  char name[NAME_LENGTH];
3472  char str[256];
3473  int port = 0;
3474 
3476 
3477  size = sizeof(name);
3478  status = db_get_value(hDB, hKey, "Name", &name, &size, TID_STRING, FALSE);
3479 
3480  if (status != DB_SUCCESS) {
3481  cm_msg(MERROR, "cm_register_server", "cannot get client name, db_get_value() status %d", status);
3482  return status;
3483  }
3484 
3485  strlcpy(str, "/Experiment/Security/RPC ports/", sizeof(str));
3486  strlcat(str, name, sizeof(str));
3487 
3488  size = sizeof(port);
3489  status = db_get_value(hDB, 0, str, &port, &size, TID_UINT32, TRUE);
3490 
3491  if (status != DB_SUCCESS) {
3492  cm_msg(MERROR, "cm_register_server", "cannot get RPC port number, db_get_value(%s) status %d", str, status);
3493  return status;
3494  }
3495 
3496  int lport = 0; // actual port number assigned to us by the OS
3497 
3498  status = rpc_register_server(port, &_rpc_listen_socket, &lport);
3499  if (status != RPC_SUCCESS) {
3500  cm_msg(MERROR, "cm_register_server", "error, rpc_register_server(port=%d) status %d", port, status);
3501  return status;
3502  }
3503 
3505 
3506  /* register MIDAS library functions */
3508 
3509  /* store port number in ODB */
3510 
3511  status = db_find_key(hDB, hKey, "Server Port", &hKey);
3512  if (status != DB_SUCCESS) {
3513  cm_msg(MERROR, "cm_register_server", "error, db_find_key(\"Server Port\") status %d", status);
3514  return status;
3515  }
3516 
3517  /* unlock database */
3519 
3520  /* set value */
3521  status = db_set_data(hDB, hKey, &lport, sizeof(INT), 1, TID_INT32);
3522  if (status != DB_SUCCESS) {
3523  cm_msg(MERROR, "cm_register_server", "error, db_set_data(\"Server Port\"=%d) status %d", port, status);
3524  return status;
3525  }
3526 
3527  /* lock database */
3529 
3531  }
3532 
3533  return CM_SUCCESS;
3534 }
static void init_rpc_hosts(HNDLE hDB)
Definition: midas.cxx:3400
INT db_set_data(HNDLE hDB, HNDLE hKey, const void *data, INT buf_size, INT num_values, DWORD type)
Definition: odb.cxx:7209
INT rpc_register_server(int port, int *plsock, int *pport)
Definition: midas.cxx:14505
static BOOL _rpc_registered
Definition: midas.cxx:260
static int _rpc_listen_socket
Definition: midas.cxx:261
size_t EXPRT strlcat(char *dst, const char *src, size_t size)
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:3589
INT cm_yield(INT millisec)
Definition: midas.cxx:5638
#define SS_ABORT
Definition: midas.h:683
#define RPC_SHUTDOWN
Definition: midas.h:713
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 3589 of file midas.cxx.

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

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

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

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

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

2933  {
2934  //printf("cm_set_experiment_database: hDB %d, hKeyClient %d\n", hDB, hKeyClient);
2935 
2936  _hDB = hDB;
2937  _hKeyClient = hKeyClient;
2938 
2939  //if (hDB == 0) {
2940  // rpc_set_server_option(RPC_ODB_HANDLE, 0);
2941  //}
2942 
2943  return CM_SUCCESS;
2944 }
Here is the caller graph for this function:

◆ cm_set_experiment_local()

int cm_set_experiment_local ( const char *  exp_name)

Definition at line 2168 of file midas.cxx.

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

1560  {
1562  return CM_SUCCESS;
1563 }
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 2952 of file midas.cxx.

2972 {
2973  _semaphore_alarm = semaphore_alarm;
2974  _semaphore_elog = semaphore_elog;
2975  _semaphore_history = semaphore_history;
2976  //_semaphore_msg = semaphore_msg;
2977 
2978  return CM_SUCCESS;
2979 }
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 1499 of file midas.cxx.

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

3719  {
3720  INT status;
3721  HNDLE hDB, hKey;
3722  char str[256];
3723 
3724  /* check for valid transition */
3726  cm_msg(MERROR, "cm_set_transition_sequence", "Invalid transition request \"%d\"", transition);
3727  return CM_INVALID_TRANSITION;
3728  }
3729 
3730  {
3731  std::lock_guard<std::mutex> guard(_trans_table_mutex);
3732 
3733  int count = 0;
3734  for (size_t i = 0; i < _trans_table.size(); i++) {
3735  if (_trans_table[i].transition == transition) {
3736  _trans_table[i].sequence_number = sequence_number;
3737  count++;
3738  }
3739  }
3740 
3741  if (count == 0) {
3742  cm_msg(MERROR, "cm_set_transition_sequence", "transition %s is not registered", cm_transition_name(transition).c_str());
3743  return CM_INVALID_TRANSITION;
3744  } else if (count > 1) {
3745  cm_msg(MERROR, "cm_set_transition_sequence", "cannot change sequence number, transition %s is registered %d times", cm_transition_name(transition).c_str(), count);
3746  return CM_INVALID_TRANSITION;
3747  }
3748 
3749  /* Change local sequence number for this transition type */
3750 
3751  for (size_t i = 0; i < _trans_table.size(); i++) {
3752  if (_trans_table[i].transition == transition) {
3753  _trans_table[i].sequence_number = sequence_number;
3754  }
3755  }
3756 
3757  // implicit unlock
3758  }
3759 
3761 
3762  /* unlock database */
3764 
3765  sprintf(str, "Transition %s", cm_transition_name(transition).c_str());
3766 
3767  /* set value */
3768  status = db_set_value(hDB, hKey, str, &sequence_number, sizeof(INT), 1, TID_INT32);
3769  if (status != DB_SUCCESS)
3770  return status;
3771 
3772  /* re-lock database */
3774 
3775  return CM_SUCCESS;
3776 
3777 }
double count
Definition: mdump.cxx:36
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 3279 of file midas.cxx.

3280 {
3281  /* set also local timeout to requested value (needed by cm_enable_watchdog()) */
3282  _watchdog_timeout = timeout;
3283 
3284  if (rpc_is_remote()) { // we are connected remotely
3285  return rpc_call(RPC_CM_SET_WATCHDOG_PARAMS, call_watchdog, timeout);
3286  } else if (rpc_is_mserver()) { // we are the mserver
3288  if (sa)
3289  sa->watchdog_timeout = timeout;
3290 
3291  /* write timeout value to client enty in ODB */
3292  HNDLE hDB, hKey;
3294 
3295  if (hDB) {
3297  db_set_value(hDB, hKey, "Link timeout", &timeout, sizeof(timeout), 1, TID_INT32);
3299  }
3300  return DB_SUCCESS;
3301  } else {
3302  return cm_set_watchdog_params_local(call_watchdog, timeout);
3303  }
3304 }
INT cm_set_watchdog_params_local(BOOL call_watchdog, DWORD timeout)
Definition: midas.cxx:3239
RPC_SERVER_ACCEPTION * rpc_get_mserver_acception()
Definition: midas.cxx:11480
#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 3239 of file midas.cxx.

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

7364  {
7365  INT status, return_status, i, size;
7366  HNDLE hDB, hKeyClient, hKey, hSubkey, hKeyTmp, hConn;
7367  KEY key;
7368  char client_name[NAME_LENGTH], remote_host[HOST_NAME_LENGTH];
7369  INT port;
7370  DWORD start_time;
7371  DWORD timeout;
7372  DWORD last;
7373 
7374  cm_get_experiment_database(&hDB, &hKeyClient);
7375 
7376  status = db_find_key(hDB, 0, "System/Clients", &hKey);
7377  if (status != DB_SUCCESS)
7378  return DB_NO_KEY;
7379 
7380  return_status = CM_NO_CLIENT;
7381 
7382  /* loop over all clients */
7383  for (i = 0;; i++) {
7385  if (status == DB_NO_MORE_SUBKEYS)
7386  break;
7387 
7388  /* don't shutdown ourselves */
7389  if (hSubkey == hKeyClient)
7390  continue;
7391 
7392  if (status == DB_SUCCESS) {
7393  db_get_key(hDB, hSubkey, &key);
7394 
7395  /* contact client */
7396  size = sizeof(client_name);
7397  status = db_get_value(hDB, hSubkey, "Name", client_name, &size, TID_STRING, FALSE);
7398  if (status != DB_SUCCESS)
7399  continue;
7400 
7401  if (!bUnique)
7402  client_name[strlen(name)] = 0; /* strip number */
7403 
7404  /* check if individual client */
7405  if (!equal_ustring("all", name) && !equal_ustring(client_name, name))
7406  continue;
7407 
7408  size = sizeof(port);
7409  db_get_value(hDB, hSubkey, "Server Port", &port, &size, TID_INT32, TRUE);
7410 
7411  size = sizeof(remote_host);
7412  db_get_value(hDB, hSubkey, "Host", remote_host, &size, TID_STRING, TRUE);
7413 
7414  cm_get_watchdog_info(hDB, name, &timeout, &last);
7415  if (timeout == 0)
7416  timeout = 5000;
7417 
7418  /* client found -> connect to its server port */
7419  status = rpc_client_connect(remote_host, port, client_name, &hConn);
7420  if (status != RPC_SUCCESS) {
7421  int client_pid = atoi(key.name);
7422  return_status = CM_NO_CLIENT;
7423  cm_msg(MERROR, "cm_shutdown", "Cannot connect to client \'%s\' on host \'%s\', port %d",
7424  client_name, remote_host, port);
7425 #ifdef SIGKILL
7426  cm_msg(MERROR, "cm_shutdown", "Killing and Deleting client \'%s\' pid %d", client_name,
7427  client_pid);
7428  kill(client_pid, SIGKILL);
7429  return_status = CM_SUCCESS;
7430  status = cm_delete_client_info(hDB, client_pid);
7431  if (status != CM_SUCCESS)
7432  cm_msg(MERROR, "cm_shutdown", "Cannot delete client info for client \'%s\', pid %d, status %d",
7433  name, client_pid, status);
7434 #endif
7435  } else {
7436  /* call disconnect with shutdown=TRUE */
7437  rpc_client_disconnect(hConn, TRUE);
7438 
7439  /* wait until client has shut down */
7440  start_time = ss_millitime();
7441  do {
7442  ss_sleep(100);
7443  status = db_find_key(hDB, hKey, key.name, &hKeyTmp);
7444  } while (status == DB_SUCCESS && (ss_millitime() - start_time < timeout));
7445 
7446  if (status == DB_SUCCESS) {
7447  int client_pid = atoi(key.name);
7448  return_status = CM_NO_CLIENT;
7449  cm_msg(MERROR, "cm_shutdown", "Client \'%s\' not responding to shutdown command", client_name);
7450 #ifdef SIGKILL
7451  cm_msg(MERROR, "cm_shutdown", "Killing and Deleting client \'%s\' pid %d", client_name,
7452  client_pid);
7453  kill(client_pid, SIGKILL);
7454  status = cm_delete_client_info(hDB, client_pid);
7455  if (status != CM_SUCCESS)
7456  cm_msg(MERROR, "cm_shutdown",
7457  "Cannot delete client info for client \'%s\', pid %d, status %d", name, client_pid,
7458  status);
7459 #endif
7460  return_status = CM_NO_CLIENT;
7461  } else {
7462  return_status = CM_SUCCESS;
7463  i--;
7464  }
7465  }
7466  }
7467 
7468  /* display any message created during each shutdown */
7470  }
7471 
7472  return return_status;
7473 }
INT cm_get_watchdog_info(HNDLE hDB, const char *client_name, DWORD *timeout, DWORD *last)
Definition: midas.cxx:3332
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 7319 of file midas.cxx.

7319  {
7320  /* watchdog does not run inside remote clients.
7321  * watchdog timeout timers are maintained by the mserver */
7322  if (rpc_is_remote())
7323  return CM_SUCCESS;
7324 #ifdef LOCAL_ROUTINES
7325  /* only start once */
7326  if (_watchdog_thread)
7327  return CM_SUCCESS;
7328  _watchdog_thread_run = true;
7330 #endif
7331  return CM_SUCCESS;
7332 }
static std::atomic< std::thread * > _watchdog_thread
Definition: midas.cxx:7287
static void xcm_watchdog_thread()
Definition: midas.cxx:7313
static std::atomic< bool > _watchdog_thread_run
Definition: midas.cxx:7285
INT thread(void *p)
Definition: odbedit.cxx:46
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 7334 of file midas.cxx.

7334  {
7335  /* watchdog does not run inside remote clients.
7336  * watchdog timeout timers are maintained by the mserver */
7337  if (rpc_is_remote())
7338  return CM_SUCCESS;
7339 #ifdef LOCAL_ROUTINES
7340  _watchdog_thread_run = false;
7341  while (_watchdog_thread_is_running) {
7342  //printf("waiting for watchdog thread to shut down\n");
7343  ss_sleep(10);
7344  }
7345  if (_watchdog_thread != NULL) {
7346  _watchdog_thread.load()->join();
7347  delete static_cast<std::thread *>(_watchdog_thread);
7348  _watchdog_thread = NULL;
7349  }
7350 #endif
7351  return CM_SUCCESS;
7352 }
static std::atomic< bool > _watchdog_thread_is_running
Definition: midas.cxx:7286
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 1371 of file midas.cxx.

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

7722  {
7723  printf("Test expand_end()\n");
7724  setenv("FOO", "foo", 1);
7725  setenv("BAR", "bar", 1);
7726  setenv("EMPTY", "", 1);
7727  unsetenv("UNDEF");
7728 
7729  bool ok = true;
7730 
7731  ok &= test_cm_expand_env1("aaa", "aaa");
7732  ok &= test_cm_expand_env1("$FOO", "foo");
7733  ok &= test_cm_expand_env1("/$FOO", "/foo");
7734  ok &= test_cm_expand_env1("/$FOO/", "/foo/");
7735  ok &= test_cm_expand_env1("$FOO/$BAR", "foo/bar");
7736  ok &= test_cm_expand_env1("$FOO1", "$FOO1");
7737  ok &= test_cm_expand_env1("1$FOO", "1foo");
7738  ok &= test_cm_expand_env1("$UNDEF", "$UNDEF");
7739  ok &= test_cm_expand_env1("/$UNDEF/", "/$UNDEF/");
7740 
7741  if (ok) {
7742  printf("test_expand_env: all tests passed!\n");
7743  } else {
7744  printf("test_expand_env: test FAILED!\n");
7745  }
7746 }
static bool test_cm_expand_env1(const char *str, const char *expected)
Definition: midas.cxx:7707
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 1436 of file midas.cxx.

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

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

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

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

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

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

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

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

7293  {
7295  //printf("cm_watchdog_thread started!\n");
7296  while (_watchdog_thread_run) {
7297  //printf("cm_watchdog_thread runs!\n");
7298  DWORD now = ss_millitime();
7301  int i;
7302  for (i = 0; i < 20; i++) {
7303  ss_sleep(100);
7304  if (!_watchdog_thread_run)
7305  break;
7306  }
7307  }
7308  //printf("cm_watchdog_thread stopped!\n");
7310  return 0;
7311 }
static void bm_update_last_activity(DWORD millitime)
Definition: midas.cxx:6080
INT db_update_last_activity(DWORD millitime)
Definition: odb.cxx:2682
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 5638 of file midas.cxx.

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

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

3349  {
3350  int status;
3351  int i, last;
3352  KEY key;
3353  int max_size;
3354  char *str;
3355 
3356 // if (index != -99)
3357 // cm_msg(MINFO, "load_rpc_hosts", "Reloading RPC hosts access control list via hotlink callback");
3358 
3359  status = db_get_key(hDB, hKey, &key);
3360 
3361  if (status != DB_SUCCESS)
3362  return;
3363 
3364  //printf("clear rpc hosts!\n");
3366 
3367  max_size = key.item_size;
3368  str = (char *) malloc(max_size);
3369 
3370  last = 0;
3371  for (i = 0; i < key.num_values; i++) {
3372  int size = max_size;
3374  if (status != DB_SUCCESS)
3375  break;
3376 
3377  if (strlen(str) < 1) // skip emties
3378  continue;
3379 
3380  if (str[0] == '#') // skip commented-out entries
3381  continue;
3382 
3383  //printf("add rpc hosts %d [%s]\n", i, str);
3385  last = i;
3386  }
3387 
3388  if (key.num_values - last < 10) {
3389  int new_size = last + 10;
3390  status = db_set_num_values(hDB, hKey, new_size);
3391  if (status != DB_SUCCESS) {
3392  cm_msg(MERROR, "load_rpc_hosts",
3393  "Cannot resize the RPC hosts access control list, db_set_num_values(%d) status %d", new_size, status);
3394  }
3395  }
3396 
3397  free(str);
3398 }
INT db_set_num_values(HNDLE hDB, HNDLE hKey, INT num_values)
Definition: odb.cxx:7496
INT rpc_add_allowed_host(const char *hostname)
Definition: midas.cxx:15202
INT rpc_clear_allowed_hosts()
Definition: midas.cxx:15177
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 12599 of file midas.cxx.

12600 {
12601  /* close all open connections */
12602 
12604 
12605  for (unsigned i = 0; i < _client_connections.size(); i++) {
12607  if (c && c->connected) {
12608  int index = c->index;
12609  // must unlock the array, otherwise we hang -
12610  // rpc_client_disconnect() will do rpc_call_client()
12611  // which needs to lock the array to convert handle
12612  // to connection pointer. Ouch! K.O. Dec 2020.
12613  _client_connections_mutex.unlock();
12616  }
12617  }
12618 
12619  for (unsigned i = 0; i < _client_connections.size(); i++) {
12621  //printf("client connection %d %p\n", i, c);
12622  if (c) {
12623  //printf("client connection %d %p connected %d\n", i, c, c->connected);
12624  if (!c->connected) {
12625  delete c;
12626  _client_connections[i] = NULL;
12627  }
12628  }
12629  }
12630 
12631  _client_connections_mutex.unlock();
12632 
12633  /* close server connection from other clients */
12634  for (unsigned i = 0; i < _server_acceptions.size(); i++) {
12635  if (_server_acceptions[i] && _server_acceptions[i]->recv_sock) {
12636  send(_server_acceptions[i]->recv_sock, "EXIT", 5, 0);
12637  _server_acceptions[i]->close();
12638  }
12639  }
12640 }
static std::mutex _client_connections_mutex
Definition: midas.cxx:11462
static std::vector< RPC_CLIENT_CONNECTION * > _client_connections
Definition: midas.cxx:11463
static std::vector< RPC_SERVER_ACCEPTION * > _server_acceptions
Definition: midas.cxx:11469
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 7707 of file midas.cxx.

7707  {
7708  std::string s = cm_expand_env(str);
7709  printf("test_expand_env: [%s] -> [%s] expected [%s]",
7710  str,
7711  s.c_str(),
7712  expected);
7713  if (s != expected) {
7714  printf(", MISMATCH!\n");
7715  return false;
7716  }
7717 
7718  printf("\n");
7719  return true;
7720 }
std::string cm_expand_env(const char *str)
Definition: midas.cxx:7675
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 3972 of file midas.cxx.

3972  {
3973  return arg1->sequence_number < arg2->sequence_number;
3974 }
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 3992 of file midas.cxx.

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

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

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

7941 {
7942  int status;
7943 
7944  // NB: locking order: 1st buffer mutex, 2nd buffer semaphore. Unlock in reverse order.
7945 
7946  //if (pbuf->locked) {
7947  // fprintf(stderr, "double lock, abort!\n");
7948  // abort();
7949  //}
7950 
7951  status = bm_lock_buffer_mutex(pbuf);
7952 
7953  if (status != BM_SUCCESS)
7954  return status;
7955 
7956  status = ss_semaphore_wait_for(pbuf->semaphore, 1000);
7957 
7958  if (status != SS_SUCCESS) {
7959  fprintf(stderr, "bm_lock_buffer: Lock buffer \"%s\" is taking longer than 1 second!\n", pbuf->buffer_name);
7960 
7961  status = ss_semaphore_wait_for(pbuf->semaphore, 10000);
7962 
7963  if (status != SS_SUCCESS) {
7964  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);
7965 
7966  if (pbuf->buffer_header) {
7967  for (int i=0; i<MAX_CLIENTS; i++) {
7968  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);
7969  }
7970  }
7971 
7973 
7974  if (status != SS_SUCCESS) {
7975  fprintf(stderr, "bm_lock_buffer: Error: Cannot lock buffer \"%s\", ss_semaphore_wait_for() status %d, aborting...\n", pbuf->buffer_name, status);
7976  cm_msg(MERROR, "bm_lock_buffer", "Cannot lock buffer \"%s\", ss_semaphore_wait_for() status %d, aborting...", pbuf->buffer_name, status);
7977  abort();
7978  /* DOES NOT RETURN */
7979  }
7980  }
7981  }
7982 
7983  // protect against double lock
7984  assert(!pbuf->locked);
7985  pbuf->locked = TRUE;
7986 
7987 #if 0
7988  int x = MAX_CLIENTS - 1;
7989  if (pbuf->buffer_header->client[x].unused1 != 0) {
7990  printf("lllock [%s] unused1 %d pid %d\n", pbuf->buffer_name, pbuf->buffer_header->client[x].unused1, getpid());
7991  }
7992  //assert(pbuf->buffer_header->client[x].unused1 == 0);
7993  pbuf->buffer_header->client[x].unused1 = getpid();
7994 #endif
7995 
7996  pbuf->count_lock++;
7997 
7998  return BM_SUCCESS;
7999 }
static int _bm_lock_timeout
Definition: midas.cxx:5915
static int bm_lock_buffer_mutex(BUFFER *pbuf)
Definition: midas.cxx:7911
INT ss_semaphore_wait_for(HNDLE semaphore_handle, INT timeout)
Definition: system.cxx:2600
#define MAX_CLIENTS
Definition: midas.h:281
INT unused1
Definition: midas.h:950
HNDLE semaphore
Definition: midas.h:1009
BOOL locked
Definition: midas.h:1013
int count_lock
Definition: midas.h:1017
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 8002 of file midas.cxx.

8002  {
8003  // NB: locking order: 1st buffer mutex, 2nd buffer semaphore. Unlock in reverse order.
8004 
8005 #if 0
8006  int x = MAX_CLIENTS-1;
8007  if (pbuf->attached) {
8008  if (pbuf->buffer_header->client[x].unused1 != getpid()) {
8009  printf("unlock [%s] unused1 %d pid %d\n", pbuf->buffer_header->name, pbuf->buffer_header->client[x].unused1, getpid());
8010  }
8011  pbuf->buffer_header->client[x].unused1 = 0;
8012  } else {
8013  printf("unlock [??????] unused1 ????? pid %d\n", getpid());
8014  }
8015 #endif
8016 
8017  // protect against double unlock
8018  assert(pbuf->locked);
8019  pbuf->locked = FALSE;
8020 
8022  pbuf->buffer_mutex.unlock();
8023 }
INT ss_semaphore_release(HNDLE semaphore_handle)
Definition: system.cxx:2720
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 7313 of file midas.cxx.

7313  {
7314  cm_watchdog_thread(NULL);
7315 }
INT cm_watchdog_thread(void *unused)
Definition: midas.cxx:7293
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 5435 of file midas.cxx.

◆ _deferred_transition_mask

DWORD _deferred_transition_mask
static

Definition at line 3815 of file midas.cxx.

◆ _exptab

exptab_struct _exptab
static

Definition at line 1607 of file midas.cxx.

◆ _requested_transition

INT _requested_transition
static

dox

Definition at line 3814 of file midas.cxx.

◆ _watchdog_thread

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

Definition at line 7287 of file midas.cxx.

◆ _watchdog_thread_is_running

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

Definition at line 7286 of file midas.cxx.

◆ _watchdog_thread_run

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

Definition at line 7285 of file midas.cxx.