Data Structures | |
struct | TR_CLIENT |
Functions | |
INT | cm_synchronize (DWORD *seconds) |
INT | cm_asctime (char *str, INT buf_size) |
INT | cm_time (DWORD *t) |
char * | cm_get_version () |
int | cm_get_revision () |
INT | cm_set_path (char *path) |
INT | cm_get_path (char *path) |
INT | cm_scan_experiments (void) |
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, char *host_name, char *client_name, INT hw_type, char *password, DWORD watchdog_timeout) |
INT | cm_get_client_info (char *client_name) |
INT | cm_get_environment (char *host_name, int host_name_size, char *exp_name, int exp_name_size) |
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 *exp_name, const char *client_name, void(*func)(char *), INT odb_size, DWORD watchdog_timeout) |
INT | cm_list_experiments (const char *host_name, char exp_name[MAX_EXPERIMENT][NAME_LENGTH]) |
INT | cm_select_experiment (const char *host_name, char *exp_name) |
INT | cm_connect_client (char *client_name, HNDLE *hConn) |
INT | cm_disconnect_client (HNDLE hConn, BOOL bShutdown) |
INT | cm_disconnect_experiment (void) |
INT | cm_set_experiment_database (HNDLE hDB, HNDLE hKeyClient) |
INT | cm_get_experiment_database (HNDLE *hDB, HNDLE *hKeyClient) |
static int | bm_validate_client_index (const BUFFER *buf) |
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, char *client_name, DWORD *timeout, DWORD *last) |
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_register_deferred_transition (INT transition, BOOL(*func)(INT, BOOL)) |
INT | cm_check_deferred_transition () |
int | tr_compare (const void *arg1, const void *arg2) |
INT | cm_transition1 (INT transition, INT run_number, char *errstr, INT errstr_size, INT async_flag, INT debug_flag) |
INT | cm_transition (INT transition, INT run_number, char *errstr, INT errstr_size, INT async_flag, INT debug_flag) |
INT | cm_yield (INT millisec) |
INT | cm_execute (const char *command, char *result, INT bufsize) |
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) |
static int bm_validate_client_index | ( | const BUFFER * | buf | ) | [static] |
dox
Definition at line 2506 of file midas.c.
Referenced by bm_cleanup(), bm_close_buffer(), bm_empty_buffers(), bm_flush_cache(), bm_push_event(), bm_receive_event(), bm_remove_event_request(), bm_send_event(), bm_skip_event(), cm_cleanup(), and cm_set_watchdog_params().
02507 { 02508 int badindex = 0; 02509 BUFFER_CLIENT *bcl = buf->buffer_header->client; 02510 02511 if (buf->client_index < 0) 02512 badindex = 1; 02513 else if (buf->client_index > buf->buffer_header->max_client_index) 02514 badindex = 1; 02515 else { 02516 bcl = &(buf->buffer_header->client[buf->client_index]); 02517 if (bcl->name[0] == 0) 02518 badindex = 1; 02519 else if (bcl->pid != ss_getpid()) 02520 badindex = 1; 02521 } 02522 02523 #if 0 02524 printf 02525 ("bm_validate_client_index: badindex=%d, buf=%p, client_index=%d, max_client_index=%d, client_name=\'%s\', client_pid=%d, pid=%d\n", 02526 badindex, buf, buf->client_index, buf->buffer_header->max_client_index, 02527 buf->buffer_header->client[buf->client_index].name, buf->buffer_header->client[buf->client_index].pid, 02528 ss_getpid()); 02529 #endif 02530 02531 if (badindex) { 02532 static int prevent_recursion = 1; 02533 if (prevent_recursion) { 02534 prevent_recursion = 0; 02535 cm_msg(MERROR, "bm_validate_client_index", 02536 "Invalid client index %d in buffer \'%s\'. Client name \'%s\', pid %d should be %d", 02537 buf->client_index, buf->buffer_header->name, bcl->name, bcl->pid, ss_getpid()); 02538 cm_msg(MERROR, "bm_validate_client_index", 02539 "Maybe this client was removed by a timeout. Cannot continue, exiting."); 02540 } 02541 exit(1); 02542 } 02543 02544 return buf->client_index; 02545 }
Get time from MIDAS server and set local time.
str | return time string | |
buf_size | Maximum size of str |
Definition at line 1135 of file midas.c.
Referenced by al_trigger_alarm(), cm_transition1(), and rpc_server_dispatch().
01136 { 01137 /* if connected to server, get time from there */ 01138 if (rpc_is_remote()) 01139 return rpc_call(RPC_CM_ASCTIME, str, buf_size); 01140 01141 /* return local time */ 01142 strcpy(str, ss_asctime()); 01143 01144 return CM_SUCCESS; 01145 }
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.
hDB | Handle to online database | |
hKeyClient | Handle to client key |
Definition at line 1413 of file midas.c.
Referenced by cm_set_client_info(), cm_transition1(), and rpc_server_dispatch().
01414 { 01415 if (rpc_is_remote()) 01416 return rpc_call(RPC_CM_CHECK_CLIENT, hDB, hKeyClient); 01417 01418 #ifdef LOCAL_ROUTINES 01419 { 01420 KEY key; 01421 DATABASE_HEADER *pheader; 01422 DATABASE_CLIENT *pclient; 01423 INT i, client_pid, status, dead = 0, found = 0; 01424 char name[NAME_LENGTH]; 01425 01426 db_get_key(hDB, hKeyClient, &key); 01427 client_pid = atoi(key.name); 01428 01429 i = sizeof(name); 01430 db_get_value(hDB, hKeyClient, "Name", name, &i, TID_STRING, TRUE); 01431 01432 db_lock_database(hDB); 01433 if (_database[hDB - 1].attached) { 01434 pheader = _database[hDB - 1].database_header; 01435 pclient = pheader->client; 01436 01437 /* loop through clients */ 01438 for (i = 0; i < pheader->max_client_index; i++, pclient++) 01439 if (pclient->pid == client_pid) { 01440 found = 1; 01441 break; 01442 } 01443 #ifdef OS_UNIX 01444 #ifdef ESRCH 01445 if (found) { /* check that the client is still running: PID still exists */ 01446 /* Only enable this for systems that define ESRCH and hope that they also support kill(pid,0) */ 01447 errno = 0; 01448 kill(client_pid, 0); 01449 if (errno == ESRCH) { 01450 cm_msg(MERROR, "cm_check_client", 01451 "Removing client \'%s\', pid %d, index %d because this pid no longer exists", 01452 pclient->name, client_pid, i); 01453 dead = 1; 01454 } 01455 } 01456 #endif 01457 #endif 01458 01459 if (!found || dead) { 01460 /* client not found : delete ODB stucture */ 01461 db_unlock_database(hDB); 01462 01463 status = cm_delete_client_info(hDB, client_pid); 01464 if (status != CM_SUCCESS) 01465 cm_msg(MERROR, "cm_check_client", 01466 "Cannot delete client info for client \'%s\', pid %d, status %d", name, client_pid, 01467 status); 01468 else 01469 cm_msg(MINFO, "cm_check_client", 01470 "Deleted entry \'/System/Clients/%d\' for client \'%s\'", client_pid, name); 01471 01472 return CM_NO_CLIENT; 01473 } 01474 } 01475 01476 db_unlock_database(hDB); 01477 } 01478 #endif /*LOCAL_ROUTINES */ 01479 01480 return CM_SUCCESS; 01481 }
INT cm_check_deferred_transition | ( | ) |
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.
Definition at line 3119 of file midas.c.
03120 { 03121 INT i, status; 03122 char str[256]; 03123 static BOOL first; 03124 03125 if (_requested_transition == 0) 03126 first = TRUE; 03127 03128 if (_requested_transition & _deferred_transition_mask) { 03129 for (i = 0; _deferred_trans_table[i].transition; i++) 03130 if (_deferred_trans_table[i].transition == _requested_transition) 03131 break; 03132 03133 if (_deferred_trans_table[i].transition == _requested_transition) { 03134 if (((BOOL(*)(INT, BOOL)) _deferred_trans_table[i].func) (_requested_transition, first)) { 03135 status = cm_transition(_requested_transition | TR_DEFERRED, 0, str, sizeof(str), SYNC, FALSE); 03136 if (status != CM_SUCCESS) 03137 cm_msg(MERROR, "cm_check_deferred_transition", "Cannot perform deferred transition: %s", str); 03138 03139 /* bypass hotlink and set _requested_transition directly to zero */ 03140 _requested_transition = 0; 03141 03142 return status; 03143 } 03144 first = FALSE; 03145 } 03146 } 03147 03148 return SUCCESS; 03149 }
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:
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.
client_name | Client name, if zero check all clients | |
ignore_timeout | If TRUE, ignore a possible increased timeout defined by each client. |
Definition at line 5033 of file midas.c.
Referenced by cm_transition1(), command_loop(), main(), and rpc_server_dispatch().
05034 { 05035 if (rpc_is_remote()) 05036 return rpc_call(RPC_CM_CLEANUP, client_name); 05037 05038 #ifdef LOCAL_ROUTINES 05039 { 05040 BUFFER_HEADER *pheader = NULL; 05041 BUFFER_CLIENT *pbclient; 05042 DATABASE_HEADER *pdbheader; 05043 DATABASE_CLIENT *pdbclient; 05044 KEY *pkey; 05045 INT client_pid; 05046 INT i, j, k, status, nc; 05047 BOOL bDeleted; 05048 char str[256]; 05049 DWORD interval; 05050 DWORD now = ss_millitime(); 05051 05052 /* check buffers */ 05053 for (i = 0; i < _buffer_entries; i++) 05054 if (_buffer[i].attached) { 05055 /* update the last_activity entry to show that we are alive */ 05056 pheader = _buffer[i].buffer_header; 05057 pbclient = pheader->client; 05058 pbclient[bm_validate_client_index(&_buffer[i])].last_activity = ss_millitime(); 05059 05060 /* now check other clients */ 05061 for (j = 0; j < pheader->max_client_index; j++, pbclient++) 05062 if (j != _buffer[i].client_index && pbclient->pid && 05063 (client_name == NULL || client_name[0] == 0 05064 || strncmp(pbclient->name, client_name, strlen(client_name)) == 0)) { 05065 if (ignore_timeout) 05066 interval = 2 * WATCHDOG_INTERVAL; 05067 else 05068 interval = pbclient->watchdog_timeout; 05069 05070 /* If client process has no activity, clear its buffer entry. */ 05071 if (interval > 0 05072 && now > pbclient->last_activity && now - pbclient->last_activity > interval) { 05073 bm_lock_buffer(i + 1); 05074 str[0] = 0; 05075 05076 /* now make again the check with the buffer locked */ 05077 if (interval > 0 05078 && now > pbclient->last_activity && now - pbclient->last_activity > interval) { 05079 sprintf(str, 05080 "Client \'%s\' on \'%s\' removed by cm_cleanup (idle %1.1lfs,TO %1.0lfs)", 05081 pbclient->name, pheader->name, 05082 (ss_millitime() - pbclient->last_activity) / 1000.0, interval / 1000.0); 05083 05084 bm_remove_client_locked(pheader, j); 05085 } 05086 05087 bm_unlock_buffer(i + 1); 05088 05089 /* display info message after unlocking buffer */ 05090 if (str[0]) 05091 cm_msg(MINFO, "cm_cleanup", str); 05092 05093 /* go again through whole list */ 05094 j = 0; 05095 } 05096 } 05097 } 05098 05099 /* check online databases */ 05100 for (i = 0; i < _database_entries; i++) 05101 if (_database[i].attached) { 05102 /* update the last_activity entry to show that we are alive */ 05103 db_lock_database(i + 1); 05104 05105 pdbheader = _database[i].database_header; 05106 pdbclient = pdbheader->client; 05107 pdbclient[_database[i].client_index].last_activity = ss_millitime(); 05108 05109 /* now check other clients */ 05110 for (j = 0; j < pdbheader->max_client_index; j++, pdbclient++) 05111 if (j != _database[i].client_index && pdbclient->pid && 05112 (client_name == NULL || client_name[0] == 0 05113 || strncmp(pdbclient->name, client_name, strlen(client_name)) == 0)) { 05114 client_pid = pdbclient->pid; 05115 if (ignore_timeout) 05116 interval = 2 * WATCHDOG_INTERVAL; 05117 else 05118 interval = pdbclient->watchdog_timeout; 05119 05120 /* If client process has no activity, clear its buffer entry. */ 05121 05122 if (interval > 0 && ss_millitime() - pdbclient->last_activity > interval) { 05123 bDeleted = FALSE; 05124 str[0] = 0; 05125 05126 /* now make again the check with the buffer locked */ 05127 if (interval > 0 && ss_millitime() - pdbclient->last_activity > interval) { 05128 sprintf(str, 05129 "Client \'%s\' on \'%s\' removed by cm_cleanup (idle %1.1lfs,TO %1.0lfs)", 05130 pdbclient->name, pdbheader->name, 05131 (ss_millitime() - pdbclient->last_activity) / 1000.0, interval / 1000.0); 05132 05133 /* decrement notify_count for open records and clear exclusive mode */ 05134 for (k = 0; k < pdbclient->max_index; k++) 05135 if (pdbclient->open_record[k].handle) { 05136 pkey = (KEY *) ((char *) pdbheader + pdbclient->open_record[k].handle); 05137 if (pkey->notify_count > 0) 05138 pkey->notify_count--; 05139 05140 if (pdbclient->open_record[k].access_mode & MODE_WRITE) 05141 db_set_mode(i + 1, pdbclient->open_record[k].handle, 05142 (WORD) (pkey->access_mode & ~MODE_EXCLUSIVE), 2); 05143 } 05144 05145 /* clear entry from client structure in buffer header */ 05146 memset(&(pdbheader->client[j]), 0, sizeof(DATABASE_CLIENT)); 05147 05148 /* calculate new max_client_index entry */ 05149 for (k = MAX_CLIENTS - 1; k >= 0; k--) 05150 if (pdbheader->client[k].pid != 0) 05151 break; 05152 pdbheader->max_client_index = k + 1; 05153 05154 /* count new number of clients */ 05155 for (k = MAX_CLIENTS - 1, nc = 0; k >= 0; k--) 05156 if (pheader->client[k].pid != 0) 05157 nc++; 05158 pdbheader->num_clients = nc; 05159 05160 bDeleted = TRUE; 05161 } 05162 05163 05164 /* delete client entry after unlocking db */ 05165 if (bDeleted) { 05166 db_unlock_database(i + 1); 05167 05168 /* display info message after unlocking buffer */ 05169 cm_msg(MINFO, "cm_cleanup", str); 05170 05171 status = cm_delete_client_info(i + 1, client_pid); 05172 if (status != CM_SUCCESS) 05173 cm_msg(MERROR, "cm_cleanup", "cannot delete client info"); 05174 05175 /* re-lock database */ 05176 db_lock_database(i + 1); 05177 pdbheader = _database[i].database_header; 05178 pdbclient = pdbheader->client; 05179 05180 /* go again though whole list */ 05181 j = 0; 05182 } 05183 } 05184 } 05185 05186 db_unlock_database(i + 1); 05187 } 05188 05189 } 05190 #endif /* LOCAL_ROUTINES */ 05191 05192 return CM_SUCCESS; 05193 }
INT cm_connect_client | ( | char * | client_name, | |
HNDLE * | hConn | |||
) |
Connect to a MIDAS client of the current experiment
For internal use only.
client_name | Name of client to connect to. This name is set by the other client via the cm_connect_experiment call. | |
hConn | Connection handle |
Definition at line 2220 of file midas.c.
Referenced by command_loop(), do_jrpc_rev0(), interprete(), and show_cnaf_page().
02221 { 02222 HNDLE hDB, hKeyRoot, hSubkey, hKey; 02223 INT status, i, length, port; 02224 char name[NAME_LENGTH], host_name[HOST_NAME_LENGTH]; 02225 02226 /* find client entry in ODB */ 02227 cm_get_experiment_database(&hDB, &hKey); 02228 02229 status = db_find_key(hDB, 0, "System/Clients", &hKeyRoot); 02230 if (status != DB_SUCCESS) 02231 return status; 02232 02233 i = 0; 02234 do { 02235 /* search for client with specific name */ 02236 status = db_enum_key(hDB, hKeyRoot, i++, &hSubkey); 02237 if (status == DB_NO_MORE_SUBKEYS) 02238 return CM_NO_CLIENT; 02239 02240 status = db_find_key(hDB, hSubkey, "Name", &hKey); 02241 if (status != DB_SUCCESS) 02242 return status; 02243 02244 length = NAME_LENGTH; 02245 status = db_get_data(hDB, hKey, name, &length, TID_STRING); 02246 if (status != DB_SUCCESS) 02247 return status; 02248 02249 if (equal_ustring(name, client_name)) { 02250 status = db_find_key(hDB, hSubkey, "Server Port", &hKey); 02251 if (status != DB_SUCCESS) 02252 return status; 02253 02254 length = sizeof(INT); 02255 status = db_get_data(hDB, hKey, &port, &length, TID_INT); 02256 if (status != DB_SUCCESS) 02257 return status; 02258 02259 status = db_find_key(hDB, hSubkey, "Host", &hKey); 02260 if (status != DB_SUCCESS) 02261 return status; 02262 02263 length = sizeof(host_name); 02264 status = db_get_data(hDB, hKey, host_name, &length, TID_STRING); 02265 if (status != DB_SUCCESS) 02266 return status; 02267 02268 /* client found -> connect to its server port */ 02269 return rpc_client_connect(host_name, port, client_name, hConn); 02270 } 02271 02272 02273 } while (TRUE); 02274 }
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.
#include <stdio.h> #include <midas.h> main(int argc, char *argv[]) { INT status, i; char host_name[256],exp_name[32]; // get default values from environment cm_get_environment(host_name, exp_name); // 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 { usage: printf("usage: test [-h Hostname] [-e Experiment]\n\n"); return 1; } } } status = cm_connect_experiment(host_name, exp_name, "Test", NULL); if (status != CM_SUCCESS) return 1; ...do operations... cm_disconnect_experiment(); }
host_name | Specifies host to connect to. Must be a valid IP host name. The string can be empty ("") if to connect to the local computer. | |
exp_name | Specifies 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_name | Client name of the calling program as it can be seen by others (like the scl command in ODBEdit). | |
func | Callback 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. |
Definition at line 1842 of file midas.c.
Referenced by main().
01843 { 01844 INT status; 01845 char str[256]; 01846 01847 status = 01848 cm_connect_experiment1(host_name, exp_name, client_name, func, DEFAULT_ODB_SIZE, 01849 DEFAULT_WATCHDOG_TIMEOUT); 01850 if (status != CM_SUCCESS) { 01851 cm_get_error(status, str); 01852 puts(str); 01853 } 01854 01855 return status; 01856 }
INT cm_connect_experiment1 | ( | const char * | host_name, | |
const char * | 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.
For internal use only.
Definition at line 1864 of file midas.c.
Referenced by cm_connect_experiment(), and main().
01866 { 01867 INT status, i, semaphore_elog, semaphore_alarm, semaphore_history, semaphore_msg, size; 01868 char local_host_name[HOST_NAME_LENGTH]; 01869 char client_name1[NAME_LENGTH]; 01870 char password[NAME_LENGTH], str[256], exp_name1[NAME_LENGTH]; 01871 HNDLE hDB, hKeyClient; 01872 BOOL call_watchdog; 01873 RUNINFO_STR(runinfo_str); 01874 01875 if (_hKeyClient) 01876 cm_disconnect_experiment(); 01877 01878 rpc_set_name(client_name); 01879 01880 /* check for local host */ 01881 if (equal_ustring(host_name, "local")) 01882 host_name = NULL; 01883 01884 #ifdef OS_WINNT 01885 { 01886 WSADATA WSAData; 01887 01888 /* Start windows sockets */ 01889 if (WSAStartup(MAKEWORD(1, 1), &WSAData) != 0) 01890 return RPC_NET_ERROR; 01891 } 01892 #endif 01893 01894 /* search for experiment name in exptab */ 01895 if (exp_name == NULL) 01896 exp_name = ""; 01897 01898 strcpy(exp_name1, exp_name); 01899 if (exp_name1[0] == 0) { 01900 status = cm_select_experiment(host_name, exp_name1); 01901 if (status != CM_SUCCESS) 01902 return status; 01903 } 01904 01905 /* connect to MIDAS server */ 01906 if (host_name && host_name[0]) { 01907 status = rpc_server_connect(host_name, exp_name1); 01908 if (status != RPC_SUCCESS) 01909 return status; 01910 01911 /* register MIDAS library functions */ 01912 status = rpc_register_functions(rpc_get_internal_list(1), NULL); 01913 if (status != RPC_SUCCESS) 01914 return status; 01915 } else { 01916 /* lookup path for *SHM files and save it */ 01917 status = cm_scan_experiments(); 01918 if (status != CM_SUCCESS) 01919 return status; 01920 01921 for (i = 0; i < MAX_EXPERIMENT && exptab[i].name[0]; i++) 01922 if (equal_ustring(exp_name1, exptab[i].name)) 01923 break; 01924 01925 /* return if experiment not defined */ 01926 if (i == MAX_EXPERIMENT || exptab[i].name[0] == 0) { 01927 /* message should be displayed by application 01928 sprintf(str, "Experiment %s not defined in exptab\r", exp_name1); 01929 cm_msg(MERROR, str); 01930 */ 01931 return CM_UNDEF_EXP; 01932 } 01933 01934 cm_set_path(exptab[i].directory); 01935 01936 /* create alarm and elog semaphores */ 01937 status = ss_semaphore_create("ALARM", &semaphore_alarm); 01938 if (status != SS_CREATED && status != SS_SUCCESS) { 01939 cm_msg(MERROR, "cm_connect_experiment", "Cannot create alarm semaphore"); 01940 return status; 01941 } 01942 status = ss_semaphore_create("ELOG", &semaphore_elog); 01943 if (status != SS_CREATED && status != SS_SUCCESS) { 01944 cm_msg(MERROR, "cm_connect_experiment", "Cannot create elog semaphore"); 01945 return status; 01946 } 01947 status = ss_semaphore_create("HISTORY", &semaphore_history); 01948 if (status != SS_CREATED && status != SS_SUCCESS) { 01949 cm_msg(MERROR, "cm_connect_experiment", "Cannot create history semaphore"); 01950 return status; 01951 } 01952 status = ss_semaphore_create("MSG", &semaphore_msg); 01953 if (status != SS_CREATED && status != SS_SUCCESS) { 01954 cm_msg(MERROR, "cm_connect_experiment", "Cannot create message semaphore"); 01955 return status; 01956 } 01957 01958 cm_set_experiment_semaphore(semaphore_alarm, semaphore_elog, semaphore_history, semaphore_msg); 01959 } 01960 01961 /* open ODB */ 01962 if (odb_size == 0) 01963 odb_size = DEFAULT_ODB_SIZE; 01964 01965 status = db_open_database("ODB", odb_size, &hDB, client_name); 01966 if (status != DB_SUCCESS && status != DB_CREATED) { 01967 cm_msg(MERROR, "cm_connect_experiment1", "cannot open database"); 01968 return status; 01969 } 01970 01971 /* now setup client info */ 01972 gethostname(local_host_name, sizeof(local_host_name)); 01973 01974 /* check watchdog timeout */ 01975 if (watchdog_timeout == 0) 01976 watchdog_timeout = DEFAULT_WATCHDOG_TIMEOUT; 01977 01978 strcpy(client_name1, client_name); 01979 password[0] = 0; 01980 status = cm_set_client_info(hDB, &hKeyClient, local_host_name, 01981 client_name1, rpc_get_option(0, RPC_OHW_TYPE), password, watchdog_timeout); 01982 01983 if (status == CM_WRONG_PASSWORD) { 01984 if (func == NULL) 01985 strcpy(str, ss_getpass("Password: ")); 01986 else 01987 func(str); 01988 01989 /* re-open database */ 01990 status = db_open_database("ODB", odb_size, &hDB, client_name); 01991 if (status != DB_SUCCESS && status != DB_CREATED) { 01992 cm_msg(MERROR, "cm_connect_experiment1", "cannot open database"); 01993 return status; 01994 } 01995 01996 strcpy(password, ss_crypt(str, "mi")); 01997 status = cm_set_client_info(hDB, &hKeyClient, local_host_name, 01998 client_name1, rpc_get_option(0, RPC_OHW_TYPE), password, watchdog_timeout); 01999 if (status != CM_SUCCESS) { 02000 /* disconnect */ 02001 if (rpc_is_remote()) 02002 rpc_server_disconnect(); 02003 02004 return status; 02005 } 02006 } 02007 02008 cm_set_experiment_database(hDB, hKeyClient); 02009 02010 /* set experiment name in ODB */ 02011 db_set_value(hDB, 0, "/Experiment/Name", exp_name1, NAME_LENGTH, 1, TID_STRING); 02012 02013 /* set data dir in ODB */ 02014 cm_get_path(str); 02015 size = sizeof(str); 02016 db_get_value(hDB, 0, "/Logger/Data dir", str, &size, TID_STRING, TRUE); 02017 02018 /* check /runinfo structure */ 02019 status = db_check_record(hDB, 0, "/Runinfo", strcomb(runinfo_str), TRUE); 02020 if (status == DB_STRUCT_MISMATCH) { 02021 cm_msg(MERROR, "cm_connect_experiment1", "Aborting on mismatching /Runinfo structure"); 02022 cm_disconnect_experiment(); 02023 abort(); 02024 } 02025 02026 /* register server to be able to be called by other clients */ 02027 status = cm_register_server(); 02028 if (status != CM_SUCCESS) 02029 return status; 02030 02031 /* set watchdog timeout */ 02032 cm_get_watchdog_params(&call_watchdog, &watchdog_timeout); 02033 size = sizeof(watchdog_timeout); 02034 sprintf(str, "/Programs/%s/Watchdog Timeout", client_name); 02035 db_get_value(hDB, 0, str, &watchdog_timeout, &size, TID_INT, TRUE); 02036 cm_set_watchdog_params(call_watchdog, watchdog_timeout); 02037 02038 /* send startup notification */ 02039 if (strchr(local_host_name, '.')) 02040 *strchr(local_host_name, '.') = 0; 02041 02042 /* startup message is not displayed */ 02043 _message_print = NULL; 02044 02045 cm_msg(MINFO, "cm_connect_experiment", "Program %s on host %s started", client_name, local_host_name); 02046 02047 /* enable system and user messages to stdout as default */ 02048 cm_set_msg_print(MT_ALL, MT_ALL, puts); 02049 02050 /* call cm_check_connect when exiting */ 02051 atexit((void (*)(void)) cm_check_connect); 02052 02053 /* register ctrl-c handler */ 02054 ss_ctrlc_handler(cm_ctrlc_handler); 02055 02056 return CM_SUCCESS; 02057 }
Delete client info from database
hDB | Database handle | |
pid | PID of entry to delete, zero for this process. |
Definition at line 1362 of file midas.c.
Referenced by cm_check_client(), cm_disconnect_experiment(), and cm_shutdown().
01363 { 01364 #ifdef LOCAL_ROUTINES 01365 01366 /* only do it if local */ 01367 if (!rpc_is_remote()) { 01368 INT status; 01369 HNDLE hKey; 01370 char str[256]; 01371 01372 if (!pid) 01373 pid = ss_getpid(); 01374 01375 /* don't delete info from a closed database */ 01376 if (_database_entries == 0) 01377 return CM_SUCCESS; 01378 01379 /* make operation atomic by locking database */ 01380 db_lock_database(hDB); 01381 01382 sprintf(str, "System/Clients/%0d", pid); 01383 status = db_find_key1(hDB, 0, str, &hKey); 01384 if (status != DB_SUCCESS) { 01385 db_unlock_database(hDB); 01386 return status; 01387 } 01388 01389 /* unlock client entry and delete it without locking DB */ 01390 db_set_mode(hDB, hKey, MODE_READ | MODE_WRITE | MODE_DELETE, 2); 01391 db_delete_key1(hDB, hKey, 1, TRUE); 01392 01393 db_unlock_database(hDB); 01394 01395 /* touch notify key to inform others */ 01396 status = 0; 01397 db_set_value(hDB, 0, "/System/Client Notify", &status, sizeof(status), 1, TID_INT); 01398 } 01399 #endif /*LOCAL_ROUTINES */ 01400 01401 return CM_SUCCESS; 01402 }
Definition at line 2939 of file midas.c.
02940 { 02941 INT status, i; 02942 HNDLE hDB, hKey, hKeyTrans; 02943 char str[256]; 02944 02945 /* check for valid transition */ 02946 if (transition != TR_START && transition != TR_STOP && transition != TR_PAUSE && transition != TR_RESUME) { 02947 cm_msg(MERROR, "cm_deregister_transition", "Invalid transition request \"%d\"", transition); 02948 return CM_INVALID_TRANSITION; 02949 } 02950 02951 cm_get_experiment_database(&hDB, &hKey); 02952 02953 /* remove existing transition request */ 02954 for (i = 0; i < MAX_TRANSITIONS; i++) 02955 if (_trans_table[i].transition == transition) 02956 break; 02957 02958 if (i == MAX_TRANSITIONS) { 02959 cm_msg(MERROR, "cm_register_transition", 02960 "Cannot de-register transition registration, request not found"); 02961 return CM_INVALID_TRANSITION; 02962 } 02963 02964 _trans_table[i].transition = 0; 02965 _trans_table[i].func = NULL; 02966 _trans_table[i].sequence_number = 0; 02967 02968 for (i = 0;; i++) 02969 if (trans_name[i].name[0] == 0 || trans_name[i].transition == transition) 02970 break; 02971 02972 sprintf(str, "Transition %s", trans_name[i].name); 02973 02974 /* unlock database */ 02975 db_set_mode(hDB, hKey, MODE_READ | MODE_WRITE | MODE_DELETE, TRUE); 02976 02977 /* set value */ 02978 status = db_find_key(hDB, hKey, str, &hKeyTrans); 02979 if (hKeyTrans) { 02980 status = db_delete_key(hDB, hKeyTrans, FALSE); 02981 if (status != DB_SUCCESS) 02982 return status; 02983 } 02984 02985 /* re-lock database */ 02986 db_set_mode(hDB, hKey, MODE_READ, TRUE); 02987 02988 return CM_SUCCESS; 02989 }
Disconnect from a MIDAS client
hConn | Connection handle obtained via cm_connect_client() | |
bShutdown | If TRUE, disconnect from client and shut it down (exit the client program) by sending a RPC_SHUTDOWN message |
Definition at line 2286 of file midas.c.
Referenced by command_loop(), do_jrpc_rev0(), interprete(), and show_cnaf_page().
INT cm_disconnect_experiment | ( | void | ) |
Disconnect from a MIDAS experiment.
Definition at line 2300 of file midas.c.
Referenced by cm_connect_experiment1(), cmd_idle(), ctrlc_odbedit(), main(), register_equipment(), server_loop(), show_status_page(), and usage().
02301 { 02302 HNDLE hDB, hKey; 02303 char local_host_name[HOST_NAME_LENGTH], client_name[80]; 02304 02305 /* send shutdown notification */ 02306 rpc_get_name(client_name); 02307 gethostname(local_host_name, sizeof(local_host_name)); 02308 if (strchr(local_host_name, '.')) 02309 *strchr(local_host_name, '.') = 0; 02310 02311 /* disconnect message not displayed */ 02312 _message_print = NULL; 02313 02314 cm_msg(MINFO, "cm_disconnect_experiment", "Program %s on host %s stopped", client_name, local_host_name); 02315 02316 if (rpc_is_remote()) { 02317 /* close open records */ 02318 db_close_all_records(); 02319 02320 rpc_client_disconnect(-1, FALSE); 02321 rpc_server_disconnect(); 02322 } else { 02323 rpc_client_disconnect(-1, FALSE); 02324 02325 #ifdef LOCAL_ROUTINES 02326 ss_alarm(0, cm_watchdog); 02327 _watchdog_last_called = 0; 02328 #endif /* LOCAL_ROUTINES */ 02329 02330 /* delete client info */ 02331 cm_get_experiment_database(&hDB, &hKey); 02332 02333 if (hDB) 02334 cm_delete_client_info(hDB, 0); 02335 02336 bm_close_all_buffers(); 02337 db_close_all_databases(); 02338 } 02339 02340 if (rpc_get_server_option(RPC_OSERVER_TYPE) == ST_REMOTE) 02341 rpc_server_shutdown(); 02342 02343 /* free RPC list */ 02344 rpc_deregister_functions(); 02345 02346 cm_set_experiment_database(0, 0); 02347 02348 _msg_buffer = 0; 02349 02350 /* free memory buffers */ 02351 if (_event_buffer_size > 0) { 02352 M_FREE(_event_buffer); 02353 _event_buffer_size = 0; 02354 } 02355 02356 if (_net_recv_buffer_size > 0) { 02357 M_FREE(_net_recv_buffer); 02358 _net_recv_buffer_size = 0; 02359 _net_recv_buffer_size_odb = 0; 02360 } 02361 02362 if (_net_send_buffer_size > 0) { 02363 M_FREE(_net_send_buffer); 02364 _net_send_buffer_size = 0; 02365 } 02366 02367 if (_tcp_buffer != NULL) { 02368 M_FREE(_tcp_buffer); 02369 _tcp_buffer = NULL; 02370 } 02371 02372 return CM_SUCCESS; 02373 }
Executes command via system() call
command | Command string to execute | |
result | stdout of command | |
bufsize | string size in byte |
Definition at line 4032 of file midas.c.
Referenced by command_loop(), and rpc_server_dispatch().
04033 { 04034 char str[256]; 04035 INT n; 04036 int fh; 04037 04038 if (rpc_is_remote()) 04039 return rpc_call(RPC_CM_EXECUTE, command, result, bufsize); 04040 04041 if (bufsize > 0) { 04042 strcpy(str, command); 04043 sprintf(str, "%s > %d.tmp", command, ss_getpid()); 04044 04045 system(str); 04046 04047 sprintf(str, "%d.tmp", ss_getpid()); 04048 fh = open(str, O_RDONLY, 0644); 04049 result[0] = 0; 04050 if (fh) { 04051 n = read(fh, result, bufsize - 1); 04052 result[MAX(0, n)] = 0; 04053 close(fh); 04054 } 04055 remove(str); 04056 } else 04057 system(command); 04058 04059 return CM_SUCCESS; 04060 }
Check if a MIDAS client exists in current experiment
name | Client name | |
bUnique | If true, look for the exact client name. If false, look for namexxx where xxx is a any number |
Definition at line 4955 of file midas.c.
Referenced by al_check(), interprete(), main(), rpc_server_dispatch(), show_programs_page(), and show_status_page().
04956 { 04957 INT status, i, size; 04958 HNDLE hDB, hKeyClient, hKey, hSubkey; 04959 char client_name[NAME_LENGTH]; 04960 04961 if (rpc_is_remote()) 04962 return rpc_call(RPC_CM_EXIST, name, bUnique); 04963 04964 cm_get_experiment_database(&hDB, &hKeyClient); 04965 04966 status = db_find_key(hDB, 0, "System/Clients", &hKey); 04967 if (status != DB_SUCCESS) 04968 return DB_NO_KEY; 04969 04970 /* loop over all clients */ 04971 for (i = 0;; i++) { 04972 status = db_enum_key(hDB, hKey, i, &hSubkey); 04973 if (status == DB_NO_MORE_SUBKEYS) 04974 break; 04975 04976 if (hSubkey == hKeyClient) 04977 continue; 04978 04979 if (status == DB_SUCCESS) { 04980 /* get client name */ 04981 size = sizeof(client_name); 04982 db_get_value(hDB, hSubkey, "Name", client_name, &size, TID_STRING, TRUE); 04983 04984 if (equal_ustring(client_name, name)) 04985 return CM_SUCCESS; 04986 04987 if (!bUnique) { 04988 client_name[strlen(name)] = 0; /* strip number */ 04989 if (equal_ustring(client_name, name)) 04990 return CM_SUCCESS; 04991 } 04992 } 04993 } 04994 04995 return CM_NO_CLIENT; 04996 }
INT cm_get_client_info | ( | char * | client_name | ) |
Get info about the current client
*client_name | Client name. |
Definition at line 1669 of file midas.c.
Referenced by bm_open_buffer(), and debug_print().
01670 { 01671 INT status, length; 01672 HNDLE hDB, hKey; 01673 01674 /* get root key of client */ 01675 cm_get_experiment_database(&hDB, &hKey); 01676 if (!hDB) { 01677 client_name[0] = 0; 01678 return CM_UNDEF_EXP; 01679 } 01680 01681 status = db_find_key(hDB, hKey, "Name", &hKey); 01682 if (status != DB_SUCCESS) 01683 return status; 01684 01685 length = NAME_LENGTH; 01686 status = db_get_data(hDB, hKey, client_name, &length, TID_STRING); 01687 if (status != DB_SUCCESS) 01688 return status; 01689 01690 return CM_SUCCESS; 01691 }
INT cm_get_environment | ( | char * | host_name, | |
int | host_name_size, | |||
char * | exp_name, | |||
int | exp_name_size | |||
) |
Returns MIDAS environment variables.
#include <stdio.h> #include <midas.h> main(int argc, char *argv[]) { INT status, i; char host_name[256],exp_name[32]; // get default values from environment cm_get_environment(host_name, exp_name); // 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 { usage: printf("usage: test [-h Hostname] [-e Experiment]\n\n"); return 1; } } } status = cm_connect_experiment(host_name, exp_name, "Test", NULL); if (status != CM_SUCCESS) return 1; ...do anyting... cm_disconnect_experiment(); }
host_name | Contents of MIDAS_SERVER_HOST environment variable. | |
host_name_size | string length | |
exp_name | Contents of MIDAS_EXPT_NAME environment variable. | |
exp_name_size | string length |
Definition at line 1745 of file midas.c.
Referenced by main().
01746 { 01747 host_name[0] = exp_name[0] = 0; 01748 01749 if (getenv("MIDAS_SERVER_HOST")) 01750 strlcpy(host_name, getenv("MIDAS_SERVER_HOST"), host_name_size); 01751 01752 if (getenv("MIDAS_EXPT_NAME")) 01753 strlcpy(exp_name, getenv("MIDAS_EXPT_NAME"), exp_name_size); 01754 01755 return CM_SUCCESS; 01756 }
INT cm_get_experiment_database | ( | HNDLE * | hDB, | |
HNDLE * | hKeyClient | |||
) |
Get the handle to the ODB from the currently connected experiment.
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);
hDB | Database handle. | |
hKeyClient | Handle for key where search starts, zero for root. |
Definition at line 2449 of file midas.c.
Referenced by add_data_dir(), al_check(), al_reset_alarm(), al_trigger_alarm(), ana_end_of_run(), analyzer_init(), assemble_prompt(), bm_open_buffer(), check_web_password(), cm_connect_client(), cm_deregister_transition(), cm_disconnect_experiment(), cm_exist(), cm_get_client_info(), cm_msg_log(), cm_msg_log1(), cm_msg_retrieve(), cm_register_deferred_transition(), cm_register_transition(), cm_set_transition_sequence(), cm_set_watchdog_params(), cm_shutdown(), cm_transition1(), cmd_dir(), command_loop(), do_jrpc_rev0(), el_submit(), evaluate_src(), exec_script(), export_hist(), frontend_init(), gen_odb_attachment(), generate_hist_graph(), get_elog_url(), get_event_id(), get_variable_id(), get_variable_id_tags(), MidasHistory::GetEventsFromEquipment(), MidasHistory::GetEventsFromOdbEvents(), MidasHistory::GetEventsFromOdbTags(), MidasHistory::GetTagsFromEquipment(), MidasHistory::GetTagsFromOdb(), MidasHistory::hs_connect(), MidasHistory::hs_get_events(), interprete(), is_editable(), main(), set_history_path(), show_alarm_page(), show_cnaf_page(), show_config_page(), show_create_page(), show_custom_gif(), show_custom_page(), show_delete_page(), show_elog_delete(), show_elog_new(), show_elog_page(), show_elog_query(), show_elog_submit_query(), show_find_page(), show_form_query(), show_hist_config_page(), show_hist_page(), show_messages_page(), show_odb_page(), show_odb_tag(), show_programs_page(), show_query_page(), show_rawfile(), show_sc_page(), show_set_page(), show_start_page(), show_status_page(), submit_elog(), and submit_form().
02450 { 02451 if (_hDB) { 02452 if (hDB != NULL) 02453 *hDB = _hDB; 02454 if (hKeyClient != NULL) 02455 *hKeyClient = _hKeyClient; 02456 } else { 02457 if (hDB != NULL) 02458 *hDB = rpc_get_server_option(RPC_ODB_HANDLE); 02459 if (hKeyClient != NULL) 02460 *hKeyClient = rpc_get_server_option(RPC_CLIENT_HANDLE); 02461 } 02462 02463 return CM_SUCCESS; 02464 }
INT cm_get_path | ( | char * | path | ) |
Return the path name previously set with cm_set_path.
path | Pathname |
Definition at line 1233 of file midas.c.
Referenced by cm_connect_experiment1(), cm_msg_log(), cm_msg_log1(), cm_msg_retrieve(), command_loop(), list_filename(), and logger_init().
01234 { 01235 strcpy(path, _path_name); 01236 01237 return CM_SUCCESS; 01238 }
int cm_get_revision | ( | ) |
Return svn revision number of current MIDAS library as a string
Definition at line 1202 of file midas.c.
Referenced by command_loop().
01203 { 01204 return atoi(svn_revision + 6); 01205 }
char* cm_get_version | ( | ) |
Return version number of current MIDAS library as a string
Definition at line 1193 of file midas.c.
Referenced by command_loop().
01194 { 01195 return MIDAS_VERSION; 01196 }
Return watchdog information about specific client
hDB | ODB handle | |
client_name | ODB client name | |
timeout | Timeout for this application in seconds | |
last | Last time watchdog was called in msec |
Definition at line 2715 of file midas.c.
Referenced by command_loop(), and rpc_server_dispatch().
02716 { 02717 if (rpc_is_remote()) 02718 return rpc_call(RPC_CM_GET_WATCHDOG_INFO, hDB, client_name, timeout, last); 02719 02720 #ifdef LOCAL_ROUTINES 02721 { 02722 DATABASE_HEADER *pheader; 02723 DATABASE_CLIENT *pclient; 02724 INT i; 02725 02726 if (hDB > _database_entries || hDB <= 0) { 02727 cm_msg(MERROR, "cm_get_watchdog_info", "invalid database handle"); 02728 return DB_INVALID_HANDLE; 02729 } 02730 02731 if (!_database[hDB - 1].attached) { 02732 cm_msg(MERROR, "cm_get_watchdog_info", "invalid database handle"); 02733 return DB_INVALID_HANDLE; 02734 } 02735 02736 /* lock database */ 02737 db_lock_database(hDB); 02738 02739 pheader = _database[hDB - 1].database_header; 02740 pclient = pheader->client; 02741 02742 /* find client */ 02743 for (i = 0; i < pheader->max_client_index; i++, pclient++) 02744 if (pclient->pid && equal_ustring(pclient->name, client_name)) { 02745 *timeout = pclient->watchdog_timeout; 02746 *last = ss_millitime() - pclient->last_activity; 02747 db_unlock_database(hDB); 02748 return CM_SUCCESS; 02749 } 02750 02751 *timeout = *last = 0; 02752 02753 db_unlock_database(hDB); 02754 02755 return CM_NO_CLIENT; 02756 } 02757 #else /* LOCAL_ROUTINES */ 02758 return CM_SUCCESS; 02759 #endif /* LOCAL_ROUTINES */ 02760 }
Return the current watchdog parameters
call_watchdog | Call the cm_watchdog routine periodically | |
timeout | Timeout for this application in seconds |
Definition at line 2695 of file midas.c.
Referenced by bm_open_buffer(), cm_connect_experiment1(), cm_set_client_info(), db_open_database(), lazy_copy(), lazy_main(), log_callback(), and log_write().
02696 { 02697 if (call_watchdog) 02698 *call_watchdog = _call_watchdog; 02699 if (timeout) 02700 *timeout = _watchdog_timeout; 02701 02702 return CM_SUCCESS; 02703 }
INT cm_list_experiments | ( | const char * | host_name, | |
char | exp_name[MAX_EXPERIMENT][NAME_LENGTH] | |||
) |
Connect to a MIDAS server and return all defined experiments in *exp_name[MAX_EXPERIMENTS]
host_name | Internet host name. | |
exp_name | list of experiment names |
Definition at line 2067 of file midas.c.
Referenced by cm_select_experiment().
02068 { 02069 INT i, status; 02070 struct sockaddr_in bind_addr; 02071 INT sock; 02072 char str[MAX_EXPERIMENT * NAME_LENGTH]; 02073 struct hostent *phe; 02074 int port = MIDAS_TCP_PORT; 02075 char hname[256]; 02076 char *s; 02077 02078 if (host_name == NULL || host_name[0] == 0 || equal_ustring(host_name, "local")) { 02079 status = cm_scan_experiments(); 02080 if (status != CM_SUCCESS) 02081 return status; 02082 02083 for (i = 0; i < MAX_EXPERIMENT; i++) 02084 strcpy(exp_name[i], exptab[i].name); 02085 02086 return CM_SUCCESS; 02087 } 02088 #ifdef OS_WINNT 02089 { 02090 WSADATA WSAData; 02091 02092 /* Start windows sockets */ 02093 if (WSAStartup(MAKEWORD(1, 1), &WSAData) != 0) 02094 return RPC_NET_ERROR; 02095 } 02096 #endif 02097 02098 /* create a new socket for connecting to remote server */ 02099 sock = socket(AF_INET, SOCK_STREAM, 0); 02100 if (sock == -1) { 02101 cm_msg(MERROR, "cm_list_experiments", "cannot create socket"); 02102 return RPC_NET_ERROR; 02103 } 02104 02105 /* extract port number from host_name */ 02106 strlcpy(hname, host_name, sizeof(hname)); 02107 s = strchr(hname, ':'); 02108 if (s) { 02109 *s = 0; 02110 port = strtoul(s + 1, NULL, 0); 02111 } 02112 02113 /* connect to remote node */ 02114 memset(&bind_addr, 0, sizeof(bind_addr)); 02115 bind_addr.sin_family = AF_INET; 02116 bind_addr.sin_addr.s_addr = 0; 02117 bind_addr.sin_port = htons(port); 02118 02119 #ifdef OS_VXWORKS 02120 { 02121 INT host_addr; 02122 02123 host_addr = hostGetByName(hname); 02124 memcpy((char *) &(bind_addr.sin_addr), &host_addr, 4); 02125 } 02126 #else 02127 phe = gethostbyname(hname); 02128 if (phe == NULL) { 02129 cm_msg(MERROR, "cm_list_experiments", "cannot resolve host name \'%s\'", hname); 02130 return RPC_NET_ERROR; 02131 } 02132 memcpy((char *) &(bind_addr.sin_addr), phe->h_addr, phe->h_length); 02133 #endif 02134 02135 #ifdef OS_UNIX 02136 do { 02137 status = connect(sock, (void *) &bind_addr, sizeof(bind_addr)); 02138 02139 /* don't return if an alarm signal was cought */ 02140 } while (status == -1 && errno == EINTR); 02141 #else 02142 status = connect(sock, (struct sockaddr *) &bind_addr, sizeof(bind_addr)); 02143 #endif 02144 02145 if (status != 0) { 02146 /* cm_msg(MERROR, "cannot connect"); message should be displayed by application */ 02147 return RPC_NET_ERROR; 02148 } 02149 02150 /* request experiment list */ 02151 send(sock, "I", 2, 0); 02152 02153 for (i = 0; i < MAX_EXPERIMENT; i++) { 02154 exp_name[i][0] = 0; 02155 status = recv_string(sock, str, sizeof(str), _rpc_connect_timeout); 02156 02157 if (status < 0) 02158 return RPC_NET_ERROR; 02159 02160 if (status == 0) 02161 break; 02162 02163 strcpy(exp_name[i], str); 02164 } 02165 02166 exp_name[i][0] = 0; 02167 closesocket(sock); 02168 02169 return CM_SUCCESS; 02170 }
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.
transition | One of TR_xxx | |
(*func) | Function which gets called whenever a transition is requested. If it returns FALSE, the transition is not performed. |
Definition at line 3062 of file midas.c.
03063 { 03064 INT status, i, size; 03065 char tr_key_name[256]; 03066 HNDLE hDB, hKey; 03067 03068 cm_get_experiment_database(&hDB, &hKey); 03069 03070 for (i = 0; _deferred_trans_table[i].transition; i++) 03071 if (_deferred_trans_table[i].transition == transition) 03072 _deferred_trans_table[i].func = (int (*)(int, char *)) func; 03073 03074 /* set new transition mask */ 03075 _deferred_transition_mask |= transition; 03076 03077 for (i = 0;; i++) 03078 if (trans_name[i].name[0] == 0 || trans_name[i].transition == transition) 03079 break; 03080 03081 sprintf(tr_key_name, "Transition %s DEFERRED", trans_name[i].name); 03082 03083 /* unlock database */ 03084 db_set_mode(hDB, hKey, MODE_READ | MODE_WRITE, TRUE); 03085 03086 /* set value */ 03087 i = 0; 03088 status = db_set_value(hDB, hKey, tr_key_name, &i, sizeof(INT), 1, TID_INT); 03089 if (status != DB_SUCCESS) 03090 return status; 03091 03092 /* re-lock database */ 03093 db_set_mode(hDB, hKey, MODE_READ, TRUE); 03094 03095 /* hot link requested transition */ 03096 size = sizeof(_requested_transition); 03097 db_get_value(hDB, 0, "/Runinfo/Requested Transition", &_requested_transition, &size, TID_INT, TRUE); 03098 db_find_key(hDB, 0, "/Runinfo/Requested Transition", &hKey); 03099 status = db_open_record(hDB, hKey, &_requested_transition, sizeof(INT), MODE_READ, NULL, NULL); 03100 if (status != DB_SUCCESS) { 03101 cm_msg(MERROR, "cm_register_deferred_transition", "Cannot hotlink /Runinfo/Requested Transition"); 03102 return status; 03103 } 03104 03105 return CM_SUCCESS; 03106 }
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.
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; } main() { ... cm_register_transition(TR_START, start, 500); do { status = cm_yield(1000); } while (status != RPC_SHUTDOWN && status != SS_ABORT); ... }
transition | Transition to register for (see State Codes & Transition Codes) | |
func | Callback function. | |
sequence_number | Sequence number for that transition (1..1000) |
Definition at line 2874 of file midas.c.
Referenced by main().
02875 { 02876 INT status, i; 02877 HNDLE hDB, hKey, hKeyTrans; 02878 KEY key; 02879 char str[256]; 02880 02881 /* check for valid transition */ 02882 if (transition != TR_START && transition != TR_STOP && transition != TR_PAUSE && transition != TR_RESUME 02883 && transition != TR_STARTABORT) { 02884 cm_msg(MERROR, "cm_register_transition", "Invalid transition request \"%d\"", transition); 02885 return CM_INVALID_TRANSITION; 02886 } 02887 02888 cm_get_experiment_database(&hDB, &hKey); 02889 02890 rpc_register_function(RPC_RC_TRANSITION, rpc_transition_dispatch); 02891 02892 /* register new transition request */ 02893 02894 /* find empty slot */ 02895 for (i = 0; i < MAX_TRANSITIONS; i++) 02896 if (!_trans_table[i].transition) 02897 break; 02898 02899 if (i == MAX_TRANSITIONS) { 02900 cm_msg(MERROR, "cm_register_transition", 02901 "To many transition registrations. Please increase MAX_TRANSITIONS and recompile"); 02902 return CM_TOO_MANY_REQUESTS; 02903 } 02904 02905 _trans_table[i].transition = transition; 02906 _trans_table[i].func = func; 02907 _trans_table[i].sequence_number = sequence_number; 02908 02909 for (i = 0;; i++) 02910 if (trans_name[i].name[0] == 0 || trans_name[i].transition == transition) 02911 break; 02912 02913 sprintf(str, "Transition %s", trans_name[i].name); 02914 02915 /* unlock database */ 02916 db_set_mode(hDB, hKey, MODE_READ | MODE_WRITE | MODE_DELETE, TRUE); 02917 02918 /* set value */ 02919 status = db_find_key(hDB, hKey, str, &hKeyTrans); 02920 if (!hKeyTrans) { 02921 status = db_set_value(hDB, hKey, str, &sequence_number, sizeof(INT), 1, TID_INT); 02922 if (status != DB_SUCCESS) 02923 return status; 02924 } else { 02925 status = db_get_key(hDB, hKeyTrans, &key); 02926 if (status != DB_SUCCESS) 02927 return status; 02928 status = db_set_data_index(hDB, hKeyTrans, &sequence_number, sizeof(INT), key.num_values, TID_INT); 02929 if (status != DB_SUCCESS) 02930 return status; 02931 } 02932 02933 /* re-lock database */ 02934 db_set_mode(hDB, hKey, MODE_READ, TRUE); 02935 02936 return CM_SUCCESS; 02937 }
INT cm_scan_experiments | ( | void | ) |
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.
Definition at line 1269 of file midas.c.
Referenced by cm_connect_experiment1(), and cm_list_experiments().
01270 { 01271 INT i; 01272 FILE *f; 01273 char str[MAX_STRING_LENGTH], alt_str[MAX_STRING_LENGTH], *pdir; 01274 01275 for (i = 0; i < MAX_EXPERIMENT; i++) 01276 exptab[i].name[0] = 0; 01277 01278 /* MIDAS_DIR overrides exptab */ 01279 if (getenv("MIDAS_DIR")) { 01280 strlcpy(str, getenv("MIDAS_DIR"), sizeof(str)); 01281 01282 strcpy(exptab[0].name, "Default"); 01283 strlcpy(exptab[0].directory, getenv("MIDAS_DIR"), sizeof(exptab[0].directory)); 01284 exptab[0].user[0] = 0; 01285 01286 return CM_SUCCESS; 01287 } 01288 01289 /* default directory for different OSes */ 01290 #if defined (OS_WINNT) 01291 if (getenv("SystemRoot")) 01292 strlcpy(str, getenv("SystemRoot"), sizeof(str)); 01293 else if (getenv("windir")) 01294 strlcpy(str, getenv("windir"), sizeof(str)); 01295 else 01296 strcpy(str, ""); 01297 01298 strcpy(alt_str, str); 01299 strcat(str, "\\system32\\exptab"); 01300 strcat(alt_str, "\\system\\exptab"); 01301 #elif defined (OS_UNIX) 01302 strcpy(str, "/etc/exptab"); 01303 strcpy(alt_str, "/exptab"); 01304 #else 01305 strcpy(str, "exptab"); 01306 strcpy(alt_str, "exptab"); 01307 #endif 01308 01309 /* MIDAS_EXPTAB overrides default directory */ 01310 if (getenv("MIDAS_EXPTAB")) { 01311 strlcpy(str, getenv("MIDAS_EXPTAB"), sizeof(str)); 01312 strlcpy(alt_str, getenv("MIDAS_EXPTAB"), sizeof(alt_str)); 01313 } 01314 01315 /* read list of available experiments */ 01316 f = fopen(str, "r"); 01317 if (f == NULL) { 01318 f = fopen(alt_str, "r"); 01319 if (f == NULL) 01320 return CM_UNDEF_ENVIRON; 01321 } 01322 01323 i = 0; 01324 if (f != NULL) { 01325 do { 01326 str[0] = 0; 01327 if (fgets(str, 100, f) == NULL) 01328 break; 01329 if (str[0] && str[0] != '#' && str[0] != ' ' && str[0] != '\t' 01330 && (strchr(str, ' ') || strchr(str, '\t'))) { 01331 sscanf(str, "%s %s %s", exptab[i].name, exptab[i].directory, exptab[i].user); 01332 01333 /* check for trailing directory separator */ 01334 pdir = exptab[i].directory; 01335 if (pdir[strlen(pdir) - 1] != DIR_SEPARATOR) 01336 strcat(pdir, DIR_SEPARATOR_STR); 01337 01338 i++; 01339 } 01340 } while (!feof(f)); 01341 fclose(f); 01342 } 01343 01344 /* 01345 for (j=0 ; j<i ; j++) 01346 { 01347 sprintf(str, "Scanned experiment %s", exptab[j].name); 01348 cm_msg(MINFO, str); 01349 } 01350 */ 01351 01352 return CM_SUCCESS; 01353 }
INT cm_select_experiment | ( | const char * | host_name, | |
char * | exp_name | |||
) |
Connect to a MIDAS server and select an experiment from the experiments available on this server
For internal use only.
host_name | Internet host name. | |
exp_name | list of experiment names |
Definition at line 2181 of file midas.c.
Referenced by cm_connect_experiment1().
02182 { 02183 INT status, i; 02184 char expts[MAX_EXPERIMENT][NAME_LENGTH]; 02185 char str[32]; 02186 02187 /* retrieve list of experiments and make selection */ 02188 status = cm_list_experiments(host_name, expts); 02189 if (status != CM_SUCCESS) 02190 return status; 02191 02192 if (expts[1][0]) { 02193 if (host_name[0]) 02194 printf("Available experiments on server %s:\n", host_name); 02195 else 02196 printf("Available experiments on local computer:\n"); 02197 02198 for (i = 0; expts[i][0]; i++) 02199 printf("%d : %s\n", i, expts[i]); 02200 printf("Select number: "); 02201 ss_gets(str, 32); 02202 i = atoi(str); 02203 strcpy(exp_name, expts[i]); 02204 } else 02205 strcpy(exp_name, expts[0]); 02206 02207 return CM_SUCCESS; 02208 }
INT cm_set_client_info | ( | HNDLE | hDB, | |
HNDLE * | hKeyClient, | |||
char * | host_name, | |||
char * | client_name, | |||
INT | hw_type, | |||
char * | password, | |||
DWORD | watchdog_timeout | |||
) |
Set client information in online database and return handle
hDB | Handle to online database | |
hKeyClient | returned key | |
host_name | server name | |
client_name | Name of this program as it will be seen by other clients. | |
hw_type | Type of byte order | |
password | MIDAS password | |
watchdog_timeout | Default watchdog timeout, can be overwritten by ODB setting /programs/<name>/Watchdog timeout |
Definition at line 1497 of file midas.c.
Referenced by cm_connect_experiment1(), and rpc_server_dispatch().
01499 { 01500 if (rpc_is_remote()) 01501 return rpc_call(RPC_CM_SET_CLIENT_INFO, hDB, hKeyClient, 01502 host_name, client_name, hw_type, password, watchdog_timeout); 01503 01504 #ifdef LOCAL_ROUTINES 01505 { 01506 INT status, pid, data, i, idx, size; 01507 HNDLE hKey, hSubkey; 01508 char str[256], name[NAME_LENGTH], orig_name[NAME_LENGTH], pwd[NAME_LENGTH]; 01509 BOOL call_watchdog, allow; 01510 PROGRAM_INFO_STR(program_info_str); 01511 01512 /* check security if password is present */ 01513 status = db_find_key(hDB, 0, "/Experiment/Security/Password", &hKey); 01514 if (hKey) { 01515 /* get password */ 01516 size = sizeof(pwd); 01517 db_get_data(hDB, hKey, pwd, &size, TID_STRING); 01518 01519 /* first check allowed hosts list */ 01520 allow = FALSE; 01521 db_find_key(hDB, 0, "/Experiment/Security/Allowed hosts", &hKey); 01522 if (hKey && db_find_key(hDB, hKey, host_name, &hKey) == DB_SUCCESS) 01523 allow = TRUE; 01524 01525 /* check allowed programs list */ 01526 db_find_key(hDB, 0, "/Experiment/Security/Allowed programs", &hKey); 01527 if (hKey && db_find_key(hDB, hKey, client_name, &hKey) == DB_SUCCESS) 01528 allow = TRUE; 01529 01530 /* now check password */ 01531 if (!allow && strcmp(password, pwd) != 0) { 01532 if (password[0]) 01533 cm_msg(MINFO, "cm_set_client_info", "Wrong password for host %s", host_name); 01534 db_close_all_databases(); 01535 bm_close_all_buffers(); 01536 _msg_buffer = 0; 01537 return CM_WRONG_PASSWORD; 01538 } 01539 } 01540 01541 /* make following operation atomic by locking database */ 01542 db_lock_database(hDB); 01543 01544 /* check if entry with this pid exists already */ 01545 pid = ss_getpid(); 01546 01547 sprintf(str, "System/Clients/%0d", pid); 01548 status = db_find_key(hDB, 0, str, &hKey); 01549 if (status == DB_SUCCESS) { 01550 db_set_mode(hDB, hKey, MODE_READ | MODE_WRITE | MODE_DELETE, TRUE); 01551 db_delete_key(hDB, hKey, TRUE); 01552 } 01553 01554 if (strlen(client_name) >= NAME_LENGTH) 01555 client_name[NAME_LENGTH] = 0; 01556 01557 strcpy(name, client_name); 01558 strcpy(orig_name, client_name); 01559 01560 /* check if client name already exists */ 01561 status = db_find_key(hDB, 0, "System/Clients", &hKey); 01562 01563 for (idx = 1; status != DB_NO_MORE_SUBKEYS; idx++) { 01564 for (i = 0;; i++) { 01565 status = db_enum_key(hDB, hKey, i, &hSubkey); 01566 if (status == DB_NO_MORE_SUBKEYS) 01567 break; 01568 01569 if (status == DB_SUCCESS) { 01570 size = sizeof(str); 01571 status = db_get_value(hDB, hSubkey, "Name", str, &size, TID_STRING, TRUE); 01572 } 01573 01574 /* check if client is living */ 01575 if (cm_check_client(hDB, hSubkey) == CM_NO_CLIENT) 01576 continue; 01577 01578 if (equal_ustring(str, name)) { 01579 sprintf(name, "%s%d", client_name, idx); 01580 break; 01581 } 01582 } 01583 } 01584 01585 /* set name */ 01586 sprintf(str, "System/Clients/%0d/Name", pid); 01587 status = db_set_value(hDB, 0, str, name, NAME_LENGTH, 1, TID_STRING); 01588 if (status != DB_SUCCESS) { 01589 db_unlock_database(hDB); 01590 cm_msg(MERROR, "cm_set_client_info", "cannot set client name"); 01591 return status; 01592 } 01593 01594 /* copy new client name */ 01595 strcpy(client_name, name); 01596 db_set_client_name(hDB, client_name); 01597 01598 /* set also as rpc name */ 01599 rpc_set_name(client_name); 01600 01601 /* use /system/clients/PID as root */ 01602 sprintf(str, "System/Clients/%0d", pid); 01603 db_find_key(hDB, 0, str, &hKey); 01604 01605 /* set host name */ 01606 status = db_set_value(hDB, hKey, "Host", host_name, HOST_NAME_LENGTH, 1, TID_STRING); 01607 if (status != DB_SUCCESS) { 01608 db_unlock_database(hDB); 01609 return status; 01610 } 01611 01612 /* set computer id */ 01613 status = db_set_value(hDB, hKey, "Hardware type", &hw_type, sizeof(hw_type), 1, TID_INT); 01614 if (status != DB_SUCCESS) { 01615 db_unlock_database(hDB); 01616 return status; 01617 } 01618 01619 /* set server port */ 01620 data = 0; 01621 status = db_set_value(hDB, hKey, "Server Port", &data, sizeof(INT), 1, TID_INT); 01622 if (status != DB_SUCCESS) { 01623 db_unlock_database(hDB); 01624 return status; 01625 } 01626 01627 /* lock client entry */ 01628 db_set_mode(hDB, hKey, MODE_READ, TRUE); 01629 01630 /* get (set) default watchdog timeout */ 01631 size = sizeof(watchdog_timeout); 01632 sprintf(str, "/Programs/%s/Watchdog Timeout", orig_name); 01633 db_get_value(hDB, 0, str, &watchdog_timeout, &size, TID_INT, TRUE); 01634 01635 /* define /programs entry */ 01636 sprintf(str, "/Programs/%s", orig_name); 01637 db_create_record(hDB, 0, str, strcomb(program_info_str)); 01638 01639 /* save handle for ODB and client */ 01640 rpc_set_server_option(RPC_ODB_HANDLE, hDB); 01641 rpc_set_server_option(RPC_CLIENT_HANDLE, hKey); 01642 01643 /* save watchdog timeout */ 01644 cm_get_watchdog_params(&call_watchdog, NULL); 01645 cm_set_watchdog_params(call_watchdog, watchdog_timeout); 01646 if (call_watchdog) 01647 ss_alarm(WATCHDOG_INTERVAL, cm_watchdog); 01648 01649 /* end of atomic operations */ 01650 db_unlock_database(hDB); 01651 01652 /* touch notify key to inform others */ 01653 data = 0; 01654 db_set_value(hDB, 0, "/System/Client Notify", &data, sizeof(data), 1, TID_INT); 01655 01656 *hKeyClient = hKey; 01657 } 01658 #endif /* LOCAL_ROUTINES */ 01659 01660 return CM_SUCCESS; 01661 }
INT cm_set_experiment_database | ( | HNDLE | hDB, | |
HNDLE | hKeyClient | |||
) |
Set the handle to the ODB for the currently connected experiment
hDB | Database handle | |
hKeyClient | Key handle of client structure |
Definition at line 2382 of file midas.c.
Referenced by cm_connect_experiment1(), and cm_disconnect_experiment().
02383 { 02384 _hDB = hDB; 02385 _hKeyClient = hKeyClient; 02386 02387 return CM_SUCCESS; 02388 }
INT cm_set_path | ( | 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.
path | Pathname |
Definition at line 1216 of file midas.c.
Referenced by cm_connect_experiment1().
01217 { 01218 strcpy(_path_name, path); 01219 01220 /* check for trailing directory seperator */ 01221 if (strlen(_path_name) > 0 && _path_name[strlen(_path_name) - 1] != DIR_SEPARATOR) 01222 strcat(_path_name, DIR_SEPARATOR_STR); 01223 01224 return CM_SUCCESS; 01225 }
Change the transition sequence for the calling program.
transition | TR_START, TR_PAUSE, TR_RESUME or TR_STOP. | |
sequence_number | New sequence number, should be between 1 and 1000 |
Definition at line 2998 of file midas.c.
02999 { 03000 INT status, i; 03001 HNDLE hDB, hKey; 03002 char str[256]; 03003 03004 /* check for valid transition */ 03005 if (transition != TR_START && transition != TR_STOP && transition != TR_PAUSE && transition != TR_RESUME) { 03006 cm_msg(MERROR, "cm_set_transition_sequence", "Invalid transition request \"%d\"", transition); 03007 return CM_INVALID_TRANSITION; 03008 } 03009 03010 cm_get_experiment_database(&hDB, &hKey); 03011 03012 /* Find the transition type from the list */ 03013 for (i = 0;; i++) 03014 if (trans_name[i].name[0] == 0 || trans_name[i].transition == transition) 03015 break; 03016 sprintf(str, "Transition %s", trans_name[i].name); 03017 03018 /* Change local sequence number for this transition type */ 03019 for (i = 0; i < MAX_TRANSITIONS; i++) 03020 if (_trans_table[i].transition == transition) { 03021 _trans_table[i].sequence_number = sequence_number; 03022 break; 03023 } 03024 03025 /* unlock database */ 03026 db_set_mode(hDB, hKey, MODE_READ | MODE_WRITE, TRUE); 03027 03028 /* set value */ 03029 status = db_set_value(hDB, hKey, str, &sequence_number, sizeof(INT), 1, TID_INT); 03030 if (status != DB_SUCCESS) 03031 return status; 03032 03033 /* re-lock database */ 03034 db_set_mode(hDB, hKey, MODE_READ, TRUE); 03035 03036 return CM_SUCCESS; 03037 03038 }
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.
call_watchdog | Call the cm_watchdog routine periodically | |
timeout | Timeout for this application in ms |
Definition at line 2583 of file midas.c.
Referenced by cm_connect_experiment1(), cm_set_client_info(), lazy_copy(), lazy_main(), log_callback(), log_write(), main(), and rpc_server_dispatch().
02584 { 02585 INT i; 02586 02587 /* set also local timeout to requested value (needed by cm_enable_watchdog()) */ 02588 _watchdog_timeout = timeout; 02589 02590 if (rpc_is_remote()) 02591 return rpc_call(RPC_CM_SET_WATCHDOG_PARAMS, call_watchdog, timeout); 02592 02593 #ifdef LOCAL_ROUTINES 02594 02595 if (rpc_get_server_option(RPC_OSERVER_TYPE) != ST_REMOTE) { 02596 HNDLE hDB, hKey; 02597 02598 rpc_set_server_option(RPC_WATCHDOG_TIMEOUT, timeout); 02599 02600 /* write timeout value to client enty in ODB */ 02601 cm_get_experiment_database(&hDB, &hKey); 02602 02603 if (hDB) { 02604 db_set_mode(hDB, hKey, MODE_READ | MODE_WRITE, TRUE); 02605 db_set_value(hDB, hKey, "Link timeout", &timeout, sizeof(timeout), 1, TID_INT); 02606 db_set_mode(hDB, hKey, MODE_READ, TRUE); 02607 } 02608 } else { 02609 _call_watchdog = call_watchdog; 02610 _watchdog_timeout = timeout; 02611 02612 /* set watchdog flag of all open buffers */ 02613 for (i = _buffer_entries; i > 0; i--) { 02614 BUFFER_CLIENT *pclient; 02615 BUFFER_HEADER *pheader; 02616 INT idx; 02617 02618 idx = bm_validate_client_index(&_buffer[i - 1]); 02619 pheader = _buffer[i - 1].buffer_header; 02620 pclient = &pheader->client[idx]; 02621 02622 if (rpc_get_server_option(RPC_OSERVER_TYPE) == ST_SINGLE 02623 && _buffer[i - 1].index != rpc_get_server_acception()) 02624 continue; 02625 02626 if (rpc_get_server_option(RPC_OSERVER_TYPE) != ST_SINGLE && _buffer[i - 1].index != ss_gettid()) 02627 continue; 02628 02629 if (!_buffer[i - 1].attached) 02630 continue; 02631 02632 /* clear entry from client structure in buffer header */ 02633 pclient->watchdog_timeout = timeout; 02634 02635 /* show activity */ 02636 pclient->last_activity = ss_millitime(); 02637 } 02638 02639 /* set watchdog flag of alll open databases */ 02640 for (i = _database_entries; i > 0; i--) { 02641 DATABASE_HEADER *pheader; 02642 DATABASE_CLIENT *pclient; 02643 INT idx; 02644 02645 db_lock_database(i); 02646 idx = _database[i - 1].client_index; 02647 pheader = _database[i - 1].database_header; 02648 pclient = &pheader->client[idx]; 02649 02650 if (rpc_get_server_option(RPC_OSERVER_TYPE) == ST_SINGLE && 02651 _database[i - 1].index != rpc_get_server_acception()) { 02652 db_unlock_database(i); 02653 continue; 02654 } 02655 02656 if (rpc_get_server_option(RPC_OSERVER_TYPE) != ST_SINGLE && _database[i - 1].index != ss_gettid()) { 02657 db_unlock_database(i); 02658 continue; 02659 } 02660 02661 if (!_database[i - 1].attached) { 02662 db_unlock_database(i); 02663 continue; 02664 } 02665 02666 /* clear entry from client structure in buffer header */ 02667 pclient->watchdog_timeout = timeout; 02668 02669 /* show activity */ 02670 pclient->last_activity = ss_millitime(); 02671 02672 db_unlock_database(i); 02673 } 02674 02675 if (call_watchdog) 02676 /* restart watchdog */ 02677 ss_alarm(WATCHDOG_INTERVAL, cm_watchdog); 02678 else 02679 /* kill current timer */ 02680 ss_alarm(0, cm_watchdog); 02681 } 02682 02683 #endif /* LOCAL_ROUTINES */ 02684 02685 return CM_SUCCESS; 02686 }
Shutdown (exit) other MIDAS client
name | Client name or "all" for all clients | |
bUnique | If true, look for the exact client name. If false, look for namexxx where xxx is a any number. |
Definition at line 4846 of file midas.c.
Referenced by cm_transition1(), command_loop(), main(), and show_programs_page().
04847 { 04848 INT status, return_status, i, size; 04849 HNDLE hDB, hKeyClient, hKey, hSubkey, hKeyTmp, hConn; 04850 KEY key; 04851 char client_name[NAME_LENGTH], remote_host[HOST_NAME_LENGTH]; 04852 INT port; 04853 DWORD start_time; 04854 04855 cm_get_experiment_database(&hDB, &hKeyClient); 04856 04857 status = db_find_key(hDB, 0, "System/Clients", &hKey); 04858 if (status != DB_SUCCESS) 04859 return DB_NO_KEY; 04860 04861 return_status = CM_NO_CLIENT; 04862 04863 /* loop over all clients */ 04864 for (i = 0;; i++) { 04865 status = db_enum_key(hDB, hKey, i, &hSubkey); 04866 if (status == DB_NO_MORE_SUBKEYS) 04867 break; 04868 04869 /* don't shutdown ourselves */ 04870 if (hSubkey == hKeyClient) 04871 continue; 04872 04873 if (status == DB_SUCCESS) { 04874 db_get_key(hDB, hSubkey, &key); 04875 04876 /* contact client */ 04877 size = sizeof(client_name); 04878 db_get_value(hDB, hSubkey, "Name", client_name, &size, TID_STRING, TRUE); 04879 04880 if (!bUnique) 04881 client_name[strlen(name)] = 0; /* strip number */ 04882 04883 /* check if individual client */ 04884 if (!equal_ustring("all", name) && !equal_ustring(client_name, name)) 04885 continue; 04886 04887 size = sizeof(port); 04888 db_get_value(hDB, hSubkey, "Server Port", &port, &size, TID_INT, TRUE); 04889 04890 size = sizeof(remote_host); 04891 db_get_value(hDB, hSubkey, "Host", remote_host, &size, TID_STRING, TRUE); 04892 04893 /* client found -> connect to its server port */ 04894 status = rpc_client_connect(remote_host, port, client_name, &hConn); 04895 if (status != RPC_SUCCESS) { 04896 int client_pid = atoi(key.name); 04897 return_status = CM_NO_CLIENT; 04898 cm_msg(MERROR, "cm_shutdown", "Cannot connect to client \'%s\' on host \'%s\', port %d", 04899 client_name, remote_host, port); 04900 #ifdef SIGKILL 04901 cm_msg(MERROR, "cm_shutdown", "Killing and Deleting client \'%s\' pid %d", client_name, 04902 client_pid); 04903 kill(client_pid, SIGKILL); 04904 status = cm_delete_client_info(hDB, client_pid); 04905 if (status != CM_SUCCESS) 04906 cm_msg(MERROR, "cm_shutdown", "Cannot delete client info for client \'%s\', pid %d, status %d", 04907 name, client_pid, status); 04908 #endif 04909 } else { 04910 /* call disconnect with shutdown=TRUE */ 04911 rpc_client_disconnect(hConn, TRUE); 04912 04913 /* wait until client has shut down */ 04914 start_time = ss_millitime(); 04915 do { 04916 ss_sleep(100); 04917 status = db_find_key(hDB, hKey, key.name, &hKeyTmp); 04918 } while (status == DB_SUCCESS && (ss_millitime() - start_time < 5000)); 04919 04920 if (status == DB_SUCCESS) { 04921 int client_pid = atoi(key.name); 04922 return_status = CM_NO_CLIENT; 04923 cm_msg(MERROR, "cm_shutdown", "Client \'%s\' not responding to shutdown command", client_name); 04924 #ifdef SIGKILL 04925 cm_msg(MERROR, "cm_shutdown", "Killing and Deleting client \'%s\' pid %d", client_name, 04926 client_pid); 04927 kill(client_pid, SIGKILL); 04928 status = cm_delete_client_info(hDB, client_pid); 04929 if (status != CM_SUCCESS) 04930 cm_msg(MERROR, "cm_shutdown", 04931 "Cannot delete client info for client \'%s\', pid %d, status %d", name, client_pid, 04932 status); 04933 #endif 04934 return_status = CM_NO_CLIENT; 04935 } else { 04936 return_status = CM_SUCCESS; 04937 i--; 04938 } 04939 } 04940 } 04941 } 04942 04943 return return_status; 04944 }
Get time from MIDAS server and set local time.
seconds | Time in seconds |
Definition at line 1107 of file midas.c.
Referenced by main(), and rpc_server_dispatch().
01108 { 01109 INT sec, status; 01110 01111 /* if connected to server, get time from there */ 01112 if (rpc_is_remote()) { 01113 status = rpc_call(RPC_CM_SYNCHRONIZE, &sec); 01114 01115 /* set local time */ 01116 if (status == CM_SUCCESS) 01117 ss_settime(sec); 01118 } 01119 01120 /* return time to caller */ 01121 if (seconds != NULL) { 01122 *seconds = ss_time(); 01123 } 01124 01125 return CM_SUCCESS; 01126 }
Get time from ss_time on server.
t | string |
Definition at line 1153 of file midas.c.
Referenced by cm_transition1(), and rpc_server_dispatch().
01154 { 01155 /* if connected to server, get time from there */ 01156 if (rpc_is_remote()) 01157 return rpc_call(RPC_CM_TIME, t); 01158 01159 /* return local time */ 01160 *t = ss_time(); 01161 01162 return CM_SUCCESS; 01163 }
INT cm_transition | ( | INT | transition, | |
INT | run_number, | |||
char * | errstr, | |||
INT | errstr_size, | |||
INT | async_flag, | |||
INT | debug_flag | |||
) |
Definition at line 3867 of file midas.c.
Referenced by cm_check_deferred_transition(), command_loop(), interprete(), log_write(), main(), scan_fragment(), start_the_run(), and stop_the_run().
03869 { 03870 int status; 03871 03872 status = cm_transition1(transition, run_number, errstr, errstr_size, async_flag, debug_flag); 03873 03874 if (transition == TR_START && status != CM_SUCCESS) { 03875 cm_msg(MERROR, "cm_transition", "Could not start a run: cm_transition() status %d, message \'%s\'", 03876 status, errstr); 03877 cm_transition1(TR_STARTABORT, run_number, NULL, 0, async_flag, debug_flag); 03878 } 03879 03880 return status; 03881 }
INT cm_transition1 | ( | INT | transition, | |
INT | run_number, | |||
char * | errstr, | |||
INT | errstr_size, | |||
INT | async_flag, | |||
INT | debug_flag | |||
) |
Performs a run transition (Start/Stop/Pause/Resume).
Synchronous/Asynchronous flag. If set to 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_INT); status = cm_transition(TR_START, new_run_number, str, sizeof(str), SYNC, debug_flag); if (status != CM_SUCCESS) { // in case of error printf("Error: %s\n", str); } ...
transition | TR_START, TR_PAUSE, TR_RESUME or TR_STOP. | |
run_number | New run number. If zero, use current run number plus one. | |
errstr | returned error string. | |
errstr_size | Size of error string. | |
async_flag | SYNC: synchronization flag (SYNC:wait completion, ASYNC: retun immediately) | |
debug_flag | If 1 output debugging information, if 2 output via cm_msg(). |
Definition at line 3212 of file midas.c.
Referenced by cm_transition().
03214 { 03215 INT i, j, status, idx, size, sequence_number, port, state, old_timeout, n_tr_clients; 03216 HNDLE hDB, hRootKey, hSubkey, hKey, hKeylocal, hConn, hKeyTrans; 03217 DWORD seconds; 03218 char host_name[HOST_NAME_LENGTH], client_name[NAME_LENGTH], str[256], error[256], tr_key_name[256]; 03219 char *trname = "unknown"; 03220 KEY key; 03221 BOOL deferred; 03222 PROGRAM_INFO program_info; 03223 TR_CLIENT *tr_client; 03224 int connect_timeout = 10000; 03225 int timeout = 120000; 03226 int t0, t1; 03227 03228 deferred = (transition & TR_DEFERRED) > 0; 03229 transition &= ~TR_DEFERRED; 03230 03231 /* check for valid transition */ 03232 if (transition != TR_START && transition != TR_STOP && transition != TR_PAUSE && transition != TR_RESUME 03233 && transition != TR_STARTABORT) { 03234 cm_msg(MERROR, "cm_transition", "Invalid transition request \"%d\"", transition); 03235 if (errstr != NULL) 03236 strlcpy(errstr, "Invalid transition request", errstr_size); 03237 return CM_INVALID_TRANSITION; 03238 } 03239 03240 /* get key of local client */ 03241 cm_get_experiment_database(&hDB, &hKeylocal); 03242 03243 if (errstr != NULL) 03244 strlcpy(errstr, "Unknown error", errstr_size); 03245 03246 if (debug_flag == 0) { 03247 size = sizeof(i); 03248 db_get_value(hDB, 0, "/Experiment/Transition debug flag", &debug_flag, &size, TID_INT, TRUE); 03249 } 03250 03251 /* do detached transition via mtransition tool */ 03252 if (async_flag == DETACH) { 03253 char *args[100]; 03254 int iarg = 0; 03255 char debug_arg[256]; 03256 char start_arg[256]; 03257 char expt_name[256]; 03258 extern RPC_SERVER_CONNECTION _server_connection; 03259 03260 args[iarg++] = "mtransition"; 03261 03262 if (_server_connection.send_sock) { 03263 /* if connected to mserver, pass connection info to mtransition */ 03264 args[iarg++] = "-h"; 03265 args[iarg++] = _server_connection.host_name; 03266 args[iarg++] = "-e"; 03267 args[iarg++] = _server_connection.exp_name; 03268 } else { 03269 /* get experiment name from ODB */ 03270 size = sizeof(expt_name); 03271 db_get_value(hDB, 0, "/Experiment/Name", expt_name, &size, TID_STRING, FALSE); 03272 03273 args[iarg++] = "-e"; 03274 args[iarg++] = expt_name; 03275 } 03276 03277 if (debug_flag) { 03278 args[iarg++] = "-d"; 03279 03280 sprintf(debug_arg, "%d", debug_flag); 03281 args[iarg++] = debug_arg; 03282 } 03283 03284 if (transition == TR_STOP) 03285 args[iarg++] = "STOP"; 03286 else if (transition == TR_PAUSE) 03287 args[iarg++] = "PAUSE"; 03288 else if (transition == TR_RESUME) 03289 args[iarg++] = "RESUME"; 03290 else if (transition == TR_START) { 03291 args[iarg++] = "START"; 03292 03293 sprintf(start_arg, "%d", run_number); 03294 args[iarg++] = start_arg; 03295 } 03296 03297 args[iarg++] = NULL; 03298 03299 if (0) 03300 for (iarg = 0; args[iarg] != NULL; iarg++) 03301 printf("arg[%d] [%s]\n", iarg, args[iarg]); 03302 03303 status = ss_spawnv(P_DETACH, args[0], args); 03304 03305 if (status != SUCCESS) { 03306 if (errstr != NULL) 03307 sprintf(errstr, "Cannot execute mtransition, ss_spawnvp() returned %d", status); 03308 return CM_SET_ERROR; 03309 } 03310 03311 return CM_SUCCESS; 03312 } 03313 03314 /* if no run number is given, get it from DB */ 03315 if (run_number == 0) { 03316 size = sizeof(run_number); 03317 status = db_get_value(hDB, 0, "Runinfo/Run number", &run_number, &size, TID_INT, TRUE); 03318 assert(status == SUCCESS); 03319 } 03320 03321 if (run_number <= 0) { 03322 cm_msg(MERROR, "cm_transition", "aborting on attempt to use invalid run number %d", run_number); 03323 abort(); 03324 } 03325 03326 /* check if transition in progress */ 03327 if (!deferred) { 03328 i = 0; 03329 size = sizeof(i); 03330 db_get_value(hDB, 0, "/Runinfo/Transition in progress", &i, &size, TID_INT, TRUE); 03331 if (i == 1) { 03332 sprintf(errstr, "Start/Stop transition %d already in progress, please try again later\n", i); 03333 strlcat(errstr, "or set \"/Runinfo/Transition in progress\" manually to zero.\n", errstr_size); 03334 return CM_TRANSITION_IN_PROGRESS; 03335 } 03336 } 03337 03338 /* get transition timeout for rpc connect */ 03339 size = sizeof(timeout); 03340 db_get_value(hDB, 0, "/Experiment/Transition connect timeout", &connect_timeout, &size, TID_INT, TRUE); 03341 03342 if (connect_timeout < 1000) 03343 connect_timeout = 1000; 03344 03345 /* get transition timeout */ 03346 size = sizeof(timeout); 03347 db_get_value(hDB, 0, "/Experiment/Transition timeout", &timeout, &size, TID_INT, TRUE); 03348 03349 if (timeout < 1000) 03350 timeout = 1000; 03351 03352 /* indicate transition in progress */ 03353 i = transition; 03354 db_set_value(hDB, 0, "/Runinfo/Transition in progress", &i, sizeof(INT), 1, TID_INT); 03355 03356 /* clear run abort flag */ 03357 i = 0; 03358 db_set_value(hDB, 0, "/Runinfo/Start abort", &i, sizeof(INT), 1, TID_INT); 03359 03360 /* Set new run number in ODB */ 03361 if (transition == TR_START) { 03362 if (debug_flag == 1) 03363 printf("Setting run number %d in ODB\n", run_number); 03364 if (debug_flag == 2) 03365 cm_msg(MINFO, "cm_transition", "cm_transition: Setting run number %d in ODB", run_number); 03366 03367 status = db_set_value(hDB, 0, "Runinfo/Run number", &run_number, sizeof(run_number), 1, TID_INT); 03368 assert(status == SUCCESS); 03369 if (status != DB_SUCCESS) 03370 cm_msg(MERROR, "cm_transition", "cannot set Runinfo/Run number in database"); 03371 } 03372 03373 if (deferred) { 03374 /* remove transition request */ 03375 i = 0; 03376 db_set_value(hDB, 0, "/Runinfo/Requested transition", &i, sizeof(int), 1, TID_INT); 03377 } else { 03378 status = db_find_key(hDB, 0, "System/Clients", &hRootKey); 03379 if (status != DB_SUCCESS) { 03380 cm_msg(MERROR, "cm_transition", "cannot find System/Clients entry in database"); 03381 if (errstr != NULL) 03382 strlcpy(errstr, "Cannot find /System/Clients in ODB", errstr_size); 03383 return status; 03384 } 03385 03386 /* check if deferred transition already in progress */ 03387 size = sizeof(i); 03388 db_get_value(hDB, 0, "/Runinfo/Requested transition", &i, &size, TID_INT, TRUE); 03389 if (i) { 03390 if (errstr != NULL) 03391 strlcpy(errstr, "Deferred transition already in progress", errstr_size); 03392 return CM_TRANSITION_IN_PROGRESS; 03393 } 03394 03395 for (i = 0; trans_name[i].name[0] != 0; i++) 03396 if (trans_name[i].transition == transition) { 03397 trname = trans_name[i].name; 03398 break; 03399 } 03400 03401 sprintf(tr_key_name, "Transition %s DEFERRED", trname); 03402 03403 /* search database for clients with deferred transition request */ 03404 for (i = 0, status = 0;; i++) { 03405 status = db_enum_key(hDB, hRootKey, i, &hSubkey); 03406 if (status == DB_NO_MORE_SUBKEYS) 03407 break; 03408 03409 if (status == DB_SUCCESS) { 03410 size = sizeof(sequence_number); 03411 status = db_get_value(hDB, hSubkey, tr_key_name, &sequence_number, &size, TID_INT, FALSE); 03412 03413 /* if registered for deferred transition, set flag in ODB and return */ 03414 if (status == DB_SUCCESS) { 03415 size = NAME_LENGTH; 03416 db_get_value(hDB, hSubkey, "Name", str, &size, TID_STRING, TRUE); 03417 db_set_value(hDB, 0, "/Runinfo/Requested transition", &transition, sizeof(int), 1, TID_INT); 03418 03419 if (debug_flag == 1) 03420 printf("---- Transition %s deferred by client \"%s\" ----\n", trname, str); 03421 if (debug_flag == 2) 03422 cm_msg(MINFO, "cm_transition", 03423 "cm_transition: ---- Transition %s deferred by client \"%s\" ----", trname, str); 03424 03425 if (errstr) 03426 sprintf(errstr, "Transition %s deferred by client \"%s\"", trname, str); 03427 03428 return CM_DEFERRED_TRANSITION; 03429 } 03430 } 03431 } 03432 } 03433 03434 /* execute programs on start */ 03435 if (transition == TR_START) { 03436 str[0] = 0; 03437 size = sizeof(str); 03438 db_get_value(hDB, 0, "/Programs/Execute on start run", str, &size, TID_STRING, TRUE); 03439 if (str[0]) 03440 ss_system(str); 03441 03442 db_find_key(hDB, 0, "/Programs", &hRootKey); 03443 if (hRootKey) { 03444 for (i = 0;; i++) { 03445 status = db_enum_key(hDB, hRootKey, i, &hKey); 03446 if (status == DB_NO_MORE_SUBKEYS) 03447 break; 03448 03449 db_get_key(hDB, hKey, &key); 03450 03451 /* don't check "execute on xxx" */ 03452 if (key.type != TID_KEY) 03453 continue; 03454 03455 size = sizeof(program_info); 03456 status = db_get_record(hDB, hKey, &program_info, &size, 0); 03457 if (status != DB_SUCCESS) { 03458 cm_msg(MERROR, "cm_transition", "Cannot get program info record"); 03459 continue; 03460 } 03461 03462 if (program_info.auto_start && program_info.start_command[0]) 03463 ss_system(program_info.start_command); 03464 } 03465 } 03466 } 03467 03468 /* set new start time in database */ 03469 if (transition == TR_START) { 03470 /* ASCII format */ 03471 cm_asctime(str, sizeof(str)); 03472 db_set_value(hDB, 0, "Runinfo/Start Time", str, 32, 1, TID_STRING); 03473 03474 /* reset stop time */ 03475 seconds = 0; 03476 db_set_value(hDB, 0, "Runinfo/Stop Time binary", &seconds, sizeof(seconds), 1, TID_DWORD); 03477 03478 /* Seconds since 1.1.1970 */ 03479 cm_time(&seconds); 03480 db_set_value(hDB, 0, "Runinfo/Start Time binary", &seconds, sizeof(seconds), 1, TID_DWORD); 03481 } 03482 03483 /* set stop time in database */ 03484 if (transition == TR_STOP) { 03485 size = sizeof(state); 03486 status = db_get_value(hDB, 0, "Runinfo/State", &state, &size, TID_INT, TRUE); 03487 if (status != DB_SUCCESS) 03488 cm_msg(MERROR, "cm_transition", "cannot get Runinfo/State in database"); 03489 03490 if (state != STATE_STOPPED) { 03491 /* stop time binary */ 03492 cm_time(&seconds); 03493 status = db_set_value(hDB, 0, "Runinfo/Stop Time binary", &seconds, sizeof(seconds), 1, TID_DWORD); 03494 if (status != DB_SUCCESS) 03495 cm_msg(MERROR, "cm_transition", "cannot set \"Runinfo/Stop Time binary\" in database"); 03496 03497 /* stop time ascii */ 03498 cm_asctime(str, sizeof(str)); 03499 status = db_set_value(hDB, 0, "Runinfo/Stop Time", str, 32, 1, TID_STRING); 03500 if (status != DB_SUCCESS) 03501 cm_msg(MERROR, "cm_transition", "cannot set \"Runinfo/Stop Time\" in database"); 03502 } 03503 } 03504 03505 status = db_find_key(hDB, 0, "System/Clients", &hRootKey); 03506 if (status != DB_SUCCESS) { 03507 cm_msg(MERROR, "cm_transition", "cannot find System/Clients entry in database"); 03508 if (errstr) 03509 strlcpy(errstr, "Cannot find /System/Clients in ODB", errstr_size); 03510 return status; 03511 } 03512 03513 for (i = 0; trans_name[i].name[0] != 0; i++) 03514 if (trans_name[i].transition == transition) { 03515 trname = trans_name[i].name; 03516 break; 03517 } 03518 03519 /* check that all transition clients are alive */ 03520 for (i = 0;;) { 03521 status = db_enum_key(hDB, hRootKey, i, &hSubkey); 03522 if (status != DB_SUCCESS) 03523 break; 03524 03525 status = cm_check_client(hDB, hSubkey); 03526 03527 if (status == DB_SUCCESS) { 03528 /* this client is alive. Check next one! */ 03529 i++; 03530 continue; 03531 } 03532 03533 assert(status == CM_NO_CLIENT); 03534 03535 /* start from scratch: removing odb entries as we iterate over them 03536 * does strange things to db_enum_key() */ 03537 i = 0; 03538 } 03539 03540 if (debug_flag == 1) 03541 printf("---- Transition %s started ----\n", trname); 03542 if (debug_flag == 2) 03543 cm_msg(MINFO, "cm_transition", "cm_transition: ---- Transition %s started ----", trname); 03544 03545 sprintf(tr_key_name, "Transition %s", trname); 03546 03547 /* search database for clients which registered for transition */ 03548 n_tr_clients = 0; 03549 tr_client = NULL; 03550 03551 for (i = 0, status = 0;; i++) { 03552 status = db_enum_key(hDB, hRootKey, i, &hSubkey); 03553 if (status == DB_NO_MORE_SUBKEYS) 03554 break; 03555 03556 if (status == DB_SUCCESS) { 03557 status = db_find_key(hDB, hSubkey, tr_key_name, &hKeyTrans); 03558 03559 if (status == DB_SUCCESS) { 03560 03561 db_get_key(hDB, hKeyTrans, &key); 03562 03563 for (j = 0; j < key.num_values; j++) { 03564 size = sizeof(sequence_number); 03565 status = db_get_data_index(hDB, hKeyTrans, &sequence_number, &size, j, TID_INT); 03566 assert(status == DB_SUCCESS); 03567 03568 if (tr_client == NULL) 03569 tr_client = (TR_CLIENT *) malloc(sizeof(TR_CLIENT)); 03570 else 03571 tr_client = (TR_CLIENT *) realloc(tr_client, sizeof(TR_CLIENT) * (n_tr_clients + 1)); 03572 assert(tr_client); 03573 03574 tr_client[n_tr_clients].sequence_number = sequence_number; 03575 03576 if (hSubkey == hKeylocal) { 03577 /* remember own client */ 03578 tr_client[n_tr_clients].port = 0; 03579 } else { 03580 /* get client info */ 03581 size = sizeof(client_name); 03582 db_get_value(hDB, hSubkey, "Name", client_name, &size, TID_STRING, TRUE); 03583 strcpy(tr_client[n_tr_clients].client_name, client_name); 03584 03585 size = sizeof(port); 03586 db_get_value(hDB, hSubkey, "Server Port", &port, &size, TID_INT, TRUE); 03587 tr_client[n_tr_clients].port = port; 03588 03589 size = sizeof(host_name); 03590 db_get_value(hDB, hSubkey, "Host", host_name, &size, TID_STRING, TRUE); 03591 strcpy(tr_client[n_tr_clients].host_name, host_name); 03592 } 03593 03594 n_tr_clients++; 03595 } 03596 } 03597 } 03598 } 03599 03600 /* sort clients according to sequence number */ 03601 if (n_tr_clients > 1) 03602 qsort(tr_client, n_tr_clients, sizeof(TR_CLIENT), tr_compare); 03603 03604 /* contact ordered clients for transition */ 03605 for (idx = 0; idx < n_tr_clients; idx++) { 03606 /* erase error string */ 03607 error[0] = 0; 03608 03609 if (debug_flag == 1) 03610 printf("\n==== Found client \"%s\" with sequence number %d\n", 03611 tr_client[idx].client_name, tr_client[idx].sequence_number); 03612 if (debug_flag == 2) 03613 cm_msg(MINFO, "cm_transition", 03614 "cm_transition: ==== Found client \"%s\" with sequence number %d", 03615 tr_client[idx].client_name, tr_client[idx].sequence_number); 03616 03617 /* if own client call transition callback directly */ 03618 if (tr_client[idx].port == 0) { 03619 for (i = 0; _trans_table[i].transition; i++) 03620 if (_trans_table[i].transition == transition) 03621 break; 03622 03623 /* call registered function */ 03624 if (_trans_table[i].transition == transition && _trans_table[i].func) { 03625 if (debug_flag == 1) 03626 printf("Calling local transition callback\n"); 03627 if (debug_flag == 2) 03628 cm_msg(MINFO, "cm_transition", "cm_transition: Calling local transition callback"); 03629 03630 status = _trans_table[i].func(run_number, error); 03631 03632 if (debug_flag == 1) 03633 printf("Local transition callback finished\n"); 03634 if (debug_flag == 2) 03635 cm_msg(MINFO, "cm_transition", "cm_transition: Local transition callback finished"); 03636 } else 03637 status = CM_SUCCESS; 03638 03639 if (errstr != NULL) 03640 memcpy(errstr, error, 03641 (INT) strlen(error) + 1 < errstr_size ? (INT) strlen(error) + 1 : errstr_size); 03642 03643 if (status != CM_SUCCESS) { 03644 /* indicate abort */ 03645 i = 1; 03646 db_set_value(hDB, 0, "/Runinfo/Start abort", &i, sizeof(INT), 1, TID_INT); 03647 i = 0; 03648 db_set_value(hDB, 0, "/Runinfo/Transition in progress", &i, sizeof(INT), 1, TID_INT); 03649 03650 free(tr_client); 03651 return status; 03652 } 03653 03654 } else { 03655 03656 /* contact client if transition mask set */ 03657 if (debug_flag == 1) 03658 printf("Connecting to client \"%s\" on host %s...\n", tr_client[idx].client_name, 03659 tr_client[idx].host_name); 03660 if (debug_flag == 2) 03661 cm_msg(MINFO, "cm_transition", 03662 "cm_transition: Connecting to client \"%s\" on host %s...", 03663 tr_client[idx].client_name, tr_client[idx].host_name); 03664 03665 /* set our timeout for rpc_client_connect() */ 03666 old_timeout = rpc_get_option(-2, RPC_OTIMEOUT); 03667 rpc_set_option(-2, RPC_OTIMEOUT, connect_timeout); 03668 03669 /* client found -> connect to its server port */ 03670 status = 03671 rpc_client_connect(tr_client[idx].host_name, tr_client[idx].port, tr_client[idx].client_name, 03672 &hConn); 03673 03674 rpc_set_option(-2, RPC_OTIMEOUT, old_timeout); 03675 03676 if (status != RPC_SUCCESS) { 03677 cm_msg(MERROR, "cm_transition", 03678 "cannot connect to client \"%s\" on host %s, port %d, status %d", 03679 tr_client[idx].client_name, tr_client[idx].host_name, tr_client[idx].port, status); 03680 if (errstr != NULL) { 03681 strlcpy(errstr, "Cannot connect to client \'", errstr_size); 03682 strlcat(errstr, tr_client[idx].client_name, errstr_size); 03683 strlcat(errstr, "\'", errstr_size); 03684 } 03685 03686 /* clients that do not respond to transitions are dead or defective, get rid of them. K.O. */ 03687 cm_shutdown(tr_client[idx].client_name, TRUE); 03688 cm_cleanup(tr_client[idx].client_name, TRUE); 03689 03690 /* indicate abort */ 03691 i = 1; 03692 db_set_value(hDB, 0, "/Runinfo/Start abort", &i, sizeof(INT), 1, TID_INT); 03693 i = 0; 03694 db_set_value(hDB, 0, "/Runinfo/Transition in progress", &i, sizeof(INT), 1, TID_INT); 03695 03696 return status; 03697 } 03698 03699 if (debug_flag == 1) 03700 printf("Connection established to client \"%s\" on host %s\n", 03701 tr_client[idx].client_name, tr_client[idx].host_name); 03702 if (debug_flag == 2) 03703 cm_msg(MINFO, "cm_transition", 03704 "cm_transition: Connection established to client \"%s\" on host %s", 03705 tr_client[idx].client_name, tr_client[idx].host_name); 03706 03707 /* call RC_TRANSITION on remote client with increased timeout */ 03708 old_timeout = rpc_get_option(hConn, RPC_OTIMEOUT); 03709 rpc_set_option(hConn, RPC_OTIMEOUT, timeout); 03710 03711 /* set FTPC protocol if in async mode */ 03712 if (async_flag == ASYNC) 03713 rpc_set_option(hConn, RPC_OTRANSPORT, RPC_FTCP); 03714 03715 if (debug_flag == 1) 03716 printf("Executing RPC transition client \"%s\" on host %s...\n", 03717 tr_client[idx].client_name, tr_client[idx].host_name); 03718 if (debug_flag == 2) 03719 cm_msg(MINFO, "cm_transition", 03720 "cm_transition: Executing RPC transition client \"%s\" on host %s...", 03721 tr_client[idx].client_name, tr_client[idx].host_name); 03722 03723 t0 = ss_millitime(); 03724 03725 status = rpc_client_call(hConn, RPC_RC_TRANSITION, transition, 03726 run_number, error, errstr_size, tr_client[idx].sequence_number); 03727 03728 t1 = ss_millitime(); 03729 03730 /* reset timeout */ 03731 rpc_set_option(hConn, RPC_OTIMEOUT, old_timeout); 03732 03733 /* reset protocol */ 03734 if (async_flag == ASYNC) 03735 rpc_set_option(hConn, RPC_OTRANSPORT, RPC_TCP); 03736 03737 if (debug_flag == 1) 03738 printf("RPC transition finished client \"%s\" on host %s in %d ms with status %d\n", 03739 tr_client[idx].client_name, tr_client[idx].host_name, t1 - t0, status); 03740 if (debug_flag == 2) 03741 cm_msg(MINFO, "cm_transition", 03742 "cm_transition: RPC transition finished client \"%s\" on host %s in %d ms with status %d", 03743 tr_client[idx].client_name, tr_client[idx].host_name, t1 - t0, status); 03744 03745 if (errstr != NULL) { 03746 if (strlen(error) < 2) 03747 sprintf(errstr, "Unknown error %d from client \'%s\' on host %s", status, 03748 tr_client[idx].client_name, tr_client[idx].host_name); 03749 else 03750 memcpy(errstr, error, 03751 (INT) strlen(error) + 1 < (INT) errstr_size ? (INT) strlen(error) + 1 : errstr_size); 03752 } 03753 03754 if (status != CM_SUCCESS) { 03755 /* indicate abort */ 03756 i = 1; 03757 db_set_value(hDB, 0, "/Runinfo/Start abort", &i, sizeof(INT), 1, TID_INT); 03758 i = 0; 03759 db_set_value(hDB, 0, "/Runinfo/Transition in progress", &i, sizeof(INT), 1, TID_INT); 03760 03761 free(tr_client); 03762 return status; 03763 } 03764 } 03765 } 03766 03767 if (tr_client) 03768 free(tr_client); 03769 03770 if (debug_flag == 1) 03771 printf("\n---- Transition %s finished ----\n", trname); 03772 if (debug_flag == 2) 03773 cm_msg(MINFO, "cm_transition", "cm_transition: ---- Transition %s finished ----", trname); 03774 03775 /* set new run state in database */ 03776 if (transition == TR_START || transition == TR_RESUME) 03777 state = STATE_RUNNING; 03778 03779 if (transition == TR_PAUSE) 03780 state = STATE_PAUSED; 03781 03782 if (transition == TR_STOP) 03783 state = STATE_STOPPED; 03784 03785 if (transition == TR_STARTABORT) 03786 state = STATE_STOPPED; 03787 03788 size = sizeof(state); 03789 status = db_set_value(hDB, 0, "Runinfo/State", &state, size, 1, TID_INT); 03790 if (status != DB_SUCCESS) 03791 cm_msg(MERROR, "cm_transition", "cannot set Runinfo/State in database"); 03792 03793 /* send notification message */ 03794 str[0] = 0; 03795 if (transition == TR_START) 03796 sprintf(str, "Run #%d started", run_number); 03797 if (transition == TR_STOP) 03798 sprintf(str, "Run #%d stopped", run_number); 03799 if (transition == TR_PAUSE) 03800 sprintf(str, "Run #%d paused", run_number); 03801 if (transition == TR_RESUME) 03802 sprintf(str, "Run #%d resumed", run_number); 03803 if (transition == TR_STARTABORT) 03804 sprintf(str, "Run #%d start aborted", run_number); 03805 03806 if (str[0]) 03807 cm_msg(MINFO, "cm_transition", str); 03808 03809 /* lock/unlock ODB values if present */ 03810 db_find_key(hDB, 0, "/Experiment/Lock when running", &hKey); 03811 if (hKey) { 03812 if (state == STATE_STOPPED) 03813 db_set_mode(hDB, hKey, MODE_READ | MODE_WRITE | MODE_DELETE, TRUE); 03814 else 03815 db_set_mode(hDB, hKey, MODE_READ, TRUE); 03816 } 03817 03818 /* flush online database */ 03819 if (transition == TR_STOP) 03820 db_flush_database(hDB); 03821 03822 /* execute/stop programs on stop */ 03823 if (transition == TR_STOP) { 03824 str[0] = 0; 03825 size = sizeof(str); 03826 db_get_value(hDB, 0, "/Programs/Execute on stop run", str, &size, TID_STRING, TRUE); 03827 if (str[0]) 03828 ss_system(str); 03829 03830 db_find_key(hDB, 0, "/Programs", &hRootKey); 03831 if (hRootKey) { 03832 for (i = 0;; i++) { 03833 status = db_enum_key(hDB, hRootKey, i, &hKey); 03834 if (status == DB_NO_MORE_SUBKEYS) 03835 break; 03836 03837 db_get_key(hDB, hKey, &key); 03838 03839 /* don't check "execute on xxx" */ 03840 if (key.type != TID_KEY) 03841 continue; 03842 03843 size = sizeof(program_info); 03844 status = db_get_record(hDB, hKey, &program_info, &size, 0); 03845 if (status != DB_SUCCESS) { 03846 cm_msg(MERROR, "cm_transition", "Cannot get program info record"); 03847 continue; 03848 } 03849 03850 if (program_info.auto_stop) 03851 cm_shutdown(key.name, FALSE); 03852 } 03853 } 03854 } 03855 03856 03857 /* indicate success */ 03858 i = 0; 03859 db_set_value(hDB, 0, "/Runinfo/Transition in progress", &i, sizeof(INT), 1, TID_INT); 03860 03861 if (errstr != NULL) 03862 strlcpy(errstr, "Success", errstr_size); 03863 03864 return CM_SUCCESS; 03865 }
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.
millisec | Timeout 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. |
Definition at line 3979 of file midas.c.
Referenced by analyze_run(), check_abort(), close_channels(), cmd_idle(), command_loop(), lazy_copy(), loop_online(), main(), scan_fragment(), server_loop(), and tr_stop().
03980 { 03981 INT status; 03982 BOOL bMore; 03983 static DWORD last_checked = 0; 03984 03985 /* check for ctrl-c */ 03986 if (_ctrlc_pressed) 03987 return RPC_SHUTDOWN; 03988 03989 /* check for available events */ 03990 if (rpc_is_remote()) { 03991 bMore = bm_poll_event(TRUE); 03992 if (bMore) 03993 status = ss_suspend(0, 0); 03994 else 03995 status = ss_suspend(millisec, 0); 03996 03997 return status; 03998 } 03999 04000 /* check alarms once every 10 seconds */ 04001 if (!rpc_is_remote() && ss_time() - last_checked > 10) { 04002 al_check(); 04003 last_checked = ss_time(); 04004 } 04005 04006 bMore = bm_check_buffers(); 04007 04008 if (bMore) { 04009 /* if events available, quickly check other IPC channels */ 04010 status = ss_suspend(0, 0); 04011 } else { 04012 /* mark event buffers for ready-to-receive */ 04013 bm_mark_read_waiting(TRUE); 04014 04015 status = ss_suspend(millisec, 0); 04016 04017 /* unmark event buffers for ready-to-receive */ 04018 bm_mark_read_waiting(FALSE); 04019 } 04020 04021 return status; 04022 }
int tr_compare | ( | const void * | arg1, | |
const void * | arg2 | |||
) |
Definition at line 3167 of file midas.c.
Referenced by cm_transition1().
03168 { 03169 return ((TR_CLIENT *) arg1)->sequence_number - ((TR_CLIENT *) arg2)->sequence_number; 03170 }