blob: d7e6295271134e50ca0c2b496f109094b70be783 [file] [log] [blame]
//------------------------------------------------------------------
//
// @@@ START COPYRIGHT @@@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
// @@@ END COPYRIGHT @@@
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/shm.h>
#include <sys/time.h>
#include "SCMVersHelp.h"
#include "seabed/fserr.h"
#include "seabed/ms.h"
#include "seabed/pctl.h"
#include "seabed/pevents.h"
#include "seabed/timer.h"
#include "seabed/thread.h"
#include "idtmsrv.h"
short gv_tleid;
short gv_time_refresh_delay; // time in tics (10ms)
char ga_name[BUFSIZ];
char *gp_shm;
unsigned long *gp_shml;
bool gv_shook = false;
bool gv_verbose = false;
DEFINE_EXTERN_COMP_DOVERS(idtmsrv)
// forwards
void do_reply(BMS_SRE *pp_sre, char *pp_reply, int pv_len, short pv_ec);
//
// Reset the global time counter
//
void reset_time_counter() {
struct timespec lv_new_ts;
clock_gettime(CLOCK_REALTIME, &lv_new_ts);
unsigned long lv_new_tsl = ((unsigned long) lv_new_ts.tv_sec << 20) |
((unsigned long) lv_new_ts.tv_nsec / 1000);
if (gv_verbose)
printf("srv: reset_time_counter, original ts =0x%lx,0x%lx converted time 0x%lx\n", lv_new_ts.tv_sec, lv_new_ts.tv_nsec, lv_new_tsl);
unsigned long lv_existing_tsl = __sync_add_and_fetch_8(gp_shm, 0);
__sync_add_and_fetch_8(gp_shm, lv_new_tsl - lv_existing_tsl);
if (gv_verbose)
printf("srv: reset_time_counter, adjustment=0x%lx, shm=0x%lx\n", lv_new_tsl - lv_existing_tsl, *gp_shml);
}
//
// Convert a time id generated by us back to a timespec
//
struct timespec long_to_timespec(unsigned long pv_time_id) {
if (gv_verbose)
printf("srv: long_to_timespec, current pv_time_id Ox%lx\n", pv_time_id);
struct timespec lv_orig_ts;
// To restore the original timespec we get the usecs by taking the bottom 20 bits
// lv_curr_ts.tv_nsec 00000000000000000000000000000000000000000000zzzzzzzzzzzzzzzzzzzz
lv_orig_ts.tv_nsec = (unsigned long) (pv_time_id & 0x00000000000FFFFFL); // bottom 20 bits only
// Then for the seconds we right shift 20 bits to get the original number
// consisting of the top 44 bits
// pv_time_is xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxyyyyyyyyyyyyyyyyyyyy
// lv_orig_ts.tv_sec xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
lv_orig_ts.tv_sec = (unsigned long)(pv_time_id >> 20);
if (gv_verbose)
printf("srv: long_to_timespec, tv_sec=0x%lx, tv_nsec=0x%lx\n", lv_orig_ts.tv_sec, lv_orig_ts.tv_nsec);
return lv_orig_ts;
}
int timespec_to_str(char *buf, size_t max_len, struct timespec *ppv_timespec) {
if (gv_verbose)
printf("srv: enter timespec_to_str\n");
unsigned int len;
char * ptr;
char tmp_buffer[MAX_DATE_TIME_BUFF_LEN * 2];
char mon_buff[5];
char day_buff[3];
char year_buff[5];
char time_buff[10];
// ctime adds a new line character at the end of the string, which we don't want
strcpy(tmp_buffer, ctime(&ppv_timespec->tv_sec));
len = (unsigned int)(strlen(tmp_buffer) - 1);
tmp_buffer[len] = '\0';
// The current date/time string only has second resolution, and is of
// this format: 'Fri May 6 03:01:52 2016'. We need to append the
// usecs to the time portion (4th token) and create a new string
// of the format'2016-05-06 03:01:52.123456'
ptr = strtok(tmp_buffer, " ");
// Skip the day of the week and get the month
ptr = strtok(NULL, " ");
strcpy(mon_buff, ptr);
ptr = strtok(NULL, " ");
if(strlen(ptr) == 1){
// Pad it with a leading '0'
day_buff[0] = '0';
strcpy(&day_buff[1], ptr);
}
else {
strcpy(day_buff, ptr);
}
ptr = strtok(NULL, " ");
strcpy(time_buff, ptr);
ptr = strtok(NULL, " ");
strcpy(year_buff, ptr);
// Convert the name of the month to numerical equivalent
if(strncmp(mon_buff, "Jan", 3) == 0 ) {
strcpy(mon_buff, "01");
}
else if(strncmp(mon_buff, "Feb", 3) == 0 ) {
strcpy(mon_buff, "02");
}
else if(strncmp(mon_buff, "Mar", 3) == 0 ) {
strcpy(mon_buff, "03");
}
else if(strncmp(mon_buff, "Apr", 3) == 0 ) {
strcpy(mon_buff, "04");
}
else if(strncmp(mon_buff, "May", 3) == 0 ) {
strcpy(mon_buff, "05");
}
else if(strncmp(mon_buff, "Jun", 3) == 0 ) {
strcpy(mon_buff, "06");
}
else if(strncmp(mon_buff, "Jul", 3) == 0 ) {
strcpy(mon_buff, "07");
}
else if(strncmp(mon_buff, "Aug", 3) == 0 ) {
strcpy(mon_buff, "08");
}
else if(strncmp(mon_buff, "Sep", 3) == 0 ) {
strcpy(mon_buff, "09");
}
else if(strncmp(mon_buff, "Oct", 3) == 0 ) {
strcpy(mon_buff, "10");
}
else if(strncmp(mon_buff, "Nov", 3) == 0 ) {
strcpy(mon_buff, "11");
}
else if(strncmp(mon_buff, "Dec", 3) == 0 ) {
strcpy(mon_buff, "12");
}
else {
printf("srv: timespec_to_string unrecognized month string %s\n", mon_buff);
return XZFIL_ERR_FSERR;
}
// Now put it all together
sprintf(tmp_buffer, "%s-%s-%s %s.%ld", year_buff, mon_buff, day_buff, time_buff, ppv_timespec->tv_nsec);
len = (unsigned int) strlen(tmp_buffer);
if(len > max_len) {
return XZFIL_ERR_BADCOUNT;
}
strcpy(buf, tmp_buffer);
return XZFIL_ERR_OK;
}
int str_to_tm_id(char *buf, unsigned long *ppv_tm_id) {
if (gv_verbose)
printf("srv: enter str_to_tm_id for: %s\n", buf);
char * ptr;
char tmp_buffer[MAX_DATE_TIME_BUFF_LEN * 2];
char date_buff[12];
char mon_buff[3];
char day_buff[3];
char year_buff[5];
char time_buff[20];
char hour_buff[3];
char min_buff[3];
char sec_usec_buff[12];
char sec_buff[3];
char usec_buff[10];
struct tm lv_tm;
struct timespec lv_ts;
// Initialize the output parameter in case an error occurs to avoid confusion
*ppv_tm_id = 0L;
// The format of the passed in date string is '2016-05-06 03:01:52.123456'
// Using a 'space' we separate the input string into date and time components
strcpy(tmp_buffer, buf);
ptr = strtok(tmp_buffer, " ");
if (ptr == NULL){
if (gv_verbose)
printf("srv: str_to_tm_id time string requires a space between date and time: %s\n", tmp_buffer );
return XZFIL_ERR_BADPARMVALUE;
}
strcpy(date_buff, ptr);
ptr = strtok(NULL, " ");
if (ptr == NULL){
if (gv_verbose)
printf("srv: str_to_tm_id time string requires a space between date and time: %s\n", tmp_buffer );
return XZFIL_ERR_BADPARMVALUE;
}
strcpy(time_buff, ptr);
// Tokenize the date using the '-' character
ptr = strtok(date_buff, "-");
if (ptr == NULL){
if (gv_verbose)
printf("srv: str_to_tm_id time string requires a hyphen in the date: %s\n", date_buff );
return XZFIL_ERR_BADPARMVALUE;
}
strcpy(year_buff, ptr);
ptr = strtok(NULL, "-");
if (ptr == NULL){
if (gv_verbose)
printf("srv: str_to_tm_id time string requires a hyphen in the date: %s\n", date_buff );
return XZFIL_ERR_BADPARMVALUE;
}
strcpy(mon_buff, ptr);
ptr = strtok(NULL, "-");
if (ptr == NULL){
if (gv_verbose)
printf("srv: str_to_tm_id time string requires a hyphen in the date: %s\n", date_buff );
return XZFIL_ERR_BADPARMVALUE;
}
strcpy(day_buff, ptr);
// Tokenize the time using the ':' character
ptr = strtok(time_buff, ":");
if (ptr == NULL){
if (gv_verbose)
printf("srv: str_to_tm_id time string requires a colon in the time: %s\n", time_buff );
return XZFIL_ERR_BADPARMVALUE;
}
strcpy(hour_buff, ptr);
ptr = strtok(NULL, ":");
if (ptr == NULL){
if (gv_verbose)
printf("srv: str_to_tm_id time string requires a colon in the time: %s\n", time_buff );
return XZFIL_ERR_BADPARMVALUE;
}
strcpy(min_buff, ptr);
ptr = strtok(NULL, ":");
if (ptr == NULL){
if (gv_verbose)
printf("srv: str_to_tm_id time string requires a colon in the time: %s\n", time_buff );
return XZFIL_ERR_BADPARMVALUE;
}
strcpy(sec_usec_buff, ptr);
// Tokenize the sec_usec_buff using the '.' character
ptr = strtok(sec_usec_buff, ".");
if (ptr == NULL){
if (gv_verbose)
printf("srv: str_to_tm_id time string requires a period separating seconds and usecs: %s\n", sec_usec_buff );
return XZFIL_ERR_BADPARMVALUE;
}
strcpy(sec_buff, ptr);
ptr = strtok(NULL, ".");
if (ptr == NULL){
if (gv_verbose)
printf("srv: str_to_tm_id time string requires a period separating secons and usecs: %s\n", sec_usec_buff );
return XZFIL_ERR_BADPARMVALUE;
}
strcpy(usec_buff, ptr);
memset(&lv_tm, 0, sizeof(struct tm));
lv_tm.tm_year = atoi(year_buff) - 1900;
lv_tm.tm_mon = atoi(mon_buff) - 1; // Months are 0 based from January
lv_tm.tm_mday = atoi(day_buff);
lv_tm.tm_hour = atoi(hour_buff);
lv_tm.tm_min = atoi(min_buff);
lv_tm.tm_sec = atoi(sec_buff);
// Take the tm struct we have created and translate it into the time_t (seconds)
// portion of a timespec. We set the nsec portion directly.
lv_ts.tv_sec = mktime(&lv_tm);
if (lv_ts.tv_sec == -1){
// Unsuccessful conversion
return XZFIL_ERR_FSERR;
}
lv_ts.tv_nsec = (atol(usec_buff) * 1000L);
*ppv_tm_id = ((unsigned long) lv_ts.tv_sec << 20) |
((unsigned long) lv_ts.tv_nsec / 1000);
if (gv_verbose)
printf("srv: str_to_tm_id lv_ts =0x%lx,0x%lx converted time 0x%lx\n", lv_ts.tv_sec, lv_ts.tv_nsec, *ppv_tm_id);
return XZFIL_ERR_OK;
}
//
// Timer callback
//
void timer_callback(int tleid, int toval, short parm1, long parm2) {
int ferr;
if (gv_verbose)
printf("timer_callback \n");
reset_time_counter();
ferr = timer_start_cb(gv_time_refresh_delay, 0, 0, &gv_tleid, &timer_callback);
assert(ferr == XZFIL_ERR_OK);
}
//
// initialize
//
void do_init(int pv_argc, char **ppp_argv) {
char *lp_arg;
int lv_arg;
bool lv_attach;
int lv_ferr;
char *lv_delay_s;
lv_attach = false;
for (lv_arg = 1; lv_arg < pv_argc; lv_arg++) {
lp_arg = ppp_argv[lv_arg];
if (strcmp(lp_arg, "-attach") == 0)
lv_attach = true;
else if (strcmp(lp_arg, "-shook") == 0)
gv_shook = true;
else if (strcmp(lp_arg, "-v") == 0)
gv_verbose = true;
}
if (lv_attach)
lv_ferr = msg_init_attach(&pv_argc, &ppp_argv, false, (char *) "$TSID0");
else
lv_ferr = msg_init(&pv_argc, &ppp_argv);
assert(lv_ferr == XZFIL_ERR_OK);
gv_time_refresh_delay = 200; // 2 seconds
lv_delay_s = getenv("TM_IDTMSRV_REFRESH_DELAY_SECONDS");
if (lv_delay_s != NULL) {
gv_time_refresh_delay = 100 * (atoi(lv_delay_s));
}
if (gv_verbose){
printf("TM_IDTMSRV_REFRESH_DELAY_SECONDS is %s. Setting gv_time_refresh_delay to %d \n", lv_delay_s, gv_time_refresh_delay);
}
if (gv_shook)
msg_debug_hook("s", "s");
}
//
// process monitor message.
//
// if shutdown, set done
//
void do_mon_msg(BMS_SRE *pp_sre, bool *pp_done) {
int lv_ferr;
MS_Mon_Msg lv_mon_msg;
lv_ferr = BMSG_READDATA_(pp_sre->sre_msgId, // msgid
(char *) &lv_mon_msg, // reqdata
(int) sizeof(lv_mon_msg)); // bytecount
assert(lv_ferr == XZFIL_ERR_OK);
if (lv_mon_msg.type == MS_MsgType_Shutdown)
*pp_done = true;
if (gv_verbose)
printf("srv: received mon message\n");
do_reply(pp_sre, NULL, 0, 0);
}
//
// process non-mon message
//
void do_req(BMS_SRE *pp_sre) {
const char *lp_req_type;
short lv_ec;
int lv_ferr;
int lv_len;
GID_Rep lv_rep;
GID_Req lv_req;
long lv_req_id;
struct timeval lv_tv;
struct timespec lv_orig_ts;
unsigned long lv_converted_tm_id;
lv_ec = XZFIL_ERR_OK;
lv_len = 0;
if (gv_verbose)
printf("srv: received NON-mon message\n");
if (pp_sre->sre_reqDataSize < (int) sizeof(lv_req)) {
if (gv_verbose)
printf("srv: received short data - sre_reqDataSize=%d, expecting len=%d, setting BADCOUNT\n",
pp_sre->sre_reqDataSize, (int) sizeof(lv_req));
lv_ec = XZFIL_ERR_BADCOUNT;
} else {
lv_ferr = BMSG_READDATA_(pp_sre->sre_msgId, // msgid
(char *) &lv_req, // reqdata
(int) sizeof(lv_req)); // bytecount
if (lv_ferr != XZFIL_ERR_OK){
printf("srv: received lv_ferr %d in do_req \n", lv_ferr);
if((lv_ferr = XMSG_ISCANCELED_(pp_sre->sre_msgId))){
printf("srv: XMSG_ISCANCELED_ returned %d in do_req. Most likely the client timeout was exceeded \n", lv_ferr);
return;
}
else{
printf("srv: XMSG_ISCANCELED_ returned %d in do_req after FEEOF on BMSG_READDATA_. ABORTING \n", lv_ferr);
abort();
}
}
if (gv_verbose) {
switch (lv_req.iv_req_type) {
case GID_REQ_PING:
lp_req_type = "ping";
break;
case GID_REQ_ID:
lp_req_type = "id";
break;
case GID_REQ_ID_TO_STRING:
lp_req_type = "id_to_string";
break;
case GID_REQ_STRING_TO_ID:
lp_req_type = "string_to_id";
break;
default:
lp_req_type = "unknown";
break;
}
if (gv_verbose)
printf("srv: received msg. req-type=%d(%s), tag=%ld, len=%d\n",
lv_req.iv_req_type, lp_req_type, lv_req.iv_req_tag, lv_req.iv_req_len);
}
switch (lv_req.iv_req_type) {
case GID_REQ_PING:
if (lv_req.iv_req_len == (int) sizeof(lv_req.u.iv_ping)) {
if (gv_verbose)
printf("srv: received ping request\n");
lv_rep.iv_rep_type = GID_REP_PING;
lv_rep.iv_rep_tag = lv_req.iv_req_tag;
lv_rep.iv_rep_len = (int) sizeof(lv_rep.u.iv_ping);
lv_rep.u.iv_ping.iv_com.iv_error = GID_ERR_OK;
gettimeofday(&lv_tv, NULL);
lv_rep.u.iv_ping.iv_ts_sec = lv_tv.tv_sec;
lv_rep.u.iv_ping.iv_ts_us = lv_tv.tv_usec;
} else {
if (gv_verbose)
printf("srv: received ping, req-len=%d, expecting len=%d, setting BADCOUNT\n",
lv_req.iv_req_len, (int) sizeof(lv_req.u.iv_ping));
lv_ec = XZFIL_ERR_BADCOUNT;
}
break;
case GID_REQ_ID:
if (lv_req.iv_req_len == (int) sizeof(lv_req.u.iv_id)) {
if (gv_verbose)
printf("srv: received id request\n");
lv_rep.iv_rep_type = GID_REP_ID;
lv_rep.iv_rep_tag = lv_req.iv_req_tag;
lv_rep.iv_rep_len = (int) sizeof(lv_rep.u.iv_id);
lv_rep.u.iv_id.iv_com.iv_error = GID_ERR_OK;
lv_rep.u.iv_id.iv_id = __sync_add_and_fetch_8(gp_shm, 1);
} else {
if (gv_verbose)
printf("srv: received id, req-len=%d, expecting len=%d, setting BADCOUNT\n",
lv_req.iv_req_len, (int) sizeof(lv_req.u.iv_id));
lv_ec = XZFIL_ERR_BADCOUNT;
}
break;
case GID_REQ_ID_TO_STRING:
if (lv_req.iv_req_len == (int) sizeof(lv_req.u.iv_id_to_string)) {
lv_rep.iv_rep_type = GID_REP_ID_TO_STRING;
lv_rep.iv_rep_tag = lv_req.iv_req_tag;
lv_req_id = lv_req.u.iv_id_to_string.iv_req_id_to_string;
if (gv_verbose)
printf("srv: received id_to_string request for id:Ox%lx\n", lv_req_id);
lv_orig_ts = long_to_timespec(lv_req_id);
lv_ferr = timespec_to_str(lv_rep.u.iv_id_to_string.iv_id_to_string, sizeof(lv_rep.u.iv_id_to_string.iv_id_to_string)
, &lv_orig_ts);
lv_rep.iv_rep_len = sizeof(lv_rep.u.iv_id_to_string);
lv_rep.u.iv_id_to_string.iv_com.iv_error = (GID_Err_Type) lv_ferr;
if (gv_verbose){
printf("srv: replying to id_to_string request with err=%d, reply-size %d, string %s, and len%d\n",
lv_rep.u.iv_id_to_string.iv_com.iv_error,
lv_rep.iv_rep_len, lv_rep.u.iv_id_to_string.iv_id_to_string,
(int) strlen(lv_rep.u.iv_id_to_string.iv_id_to_string));
}
} else {
if (gv_verbose)
printf("srv: received id_to_string, req-len=%d, expecting len=%d, setting BADCOUNT\n",
lv_req.iv_req_len, (int) sizeof(lv_req.u.iv_id_to_string));
lv_ec = XZFIL_ERR_BADCOUNT;
}
break;
case GID_REQ_STRING_TO_ID:
if (lv_req.iv_req_len == (int) sizeof(lv_req.u.iv_string_to_id)) {
if (gv_verbose)
printf("srv: received string_to_id request, string: %s\n", lv_req.u.iv_string_to_id.iv_string_to_id);
lv_rep.iv_rep_type = GID_REP_STRING_TO_ID;
lv_rep.iv_rep_tag = lv_req.iv_req_tag;
lv_ferr = str_to_tm_id(lv_req.u.iv_string_to_id.iv_string_to_id, &lv_converted_tm_id);
lv_rep.u.iv_string_to_id.iv_string_to_id = lv_converted_tm_id;
lv_rep.iv_rep_len = sizeof(lv_rep.u.iv_string_to_id);
lv_rep.u.iv_string_to_id.iv_com.iv_error = (GID_Err_Type) lv_ferr;
if (lv_ferr != XZFIL_ERR_OK)
lv_ec = lv_ferr;
if (gv_verbose)
printf("srv: replying to string_to_id request with err=%d, size %d, and id %ld\n",
lv_ferr, lv_rep.iv_rep_len, lv_converted_tm_id);
} else {
if (gv_verbose)
printf("srv: received string_to_id, req-len=%d, expecting len=%d, setting BADCOUNT\n",
lv_req.iv_req_len, (int) sizeof(lv_req.u.iv_string_to_id));
lv_ec = XZFIL_ERR_BADCOUNT;
}
break;
default:
if (gv_verbose)
printf("srv: received unknown req-type=%d, setting INVALOP\n",
lv_req.iv_req_type);
lv_ec = XZFIL_ERR_INVALOP;
break;
}
}
if (gv_verbose){
if(lv_rep.iv_rep_type == GID_REP_ID_TO_STRING){
printf("srv: reply, rep-type=%d, tag=%ld, id_to_string=%s, len=%d\n",
lv_rep.iv_rep_type, lv_rep.iv_rep_tag, lv_rep.u.iv_id_to_string.iv_id_to_string, lv_rep.iv_rep_len);
}
else {
printf("srv: reply, rep-type=%d, tag=%ld, id=%ld, len=%d\n",
lv_rep.iv_rep_type, lv_rep.iv_rep_tag, lv_rep.u.iv_id.iv_id, lv_rep.iv_rep_len);
}
}
lv_len = (int) sizeof(lv_rep);
do_reply(pp_sre, (char *) &lv_rep, lv_len, lv_ec);
}
//
// do reply
//
void do_reply(BMS_SRE *pp_sre, char *pp_reply, int pv_len, short pv_ec) {
GID_Rep * lv_rep = (GID_Rep *) pp_reply;
int lv_error = 0;
if (lv_rep != NULL)
lv_error = lv_rep->u.iv_id.iv_com.iv_error;
if (gv_verbose){
printf("srv: reply, len=%d, ec=%d, error=%d\n", pv_len, pv_ec, lv_error);
}
if (pv_ec == XZFIL_ERR_OK){
pv_ec = lv_error;
}
BMSG_REPLY_(pp_sre->sre_msgId, // msgid
NULL, // replyctrl
0, // replyctrlsize
pp_reply, // replydata
pv_len, // replydatasize
pv_ec, // errorclass
NULL); // newphandle
}
//
// setup shared memory.
//
// if shared memory created, then initialize to current time.
//
void do_shm() {
bool lv_created;
int lv_ferr;
int lv_key;
int lv_msid;
struct timespec lv_ts;
unsigned long lv_tsl;
lv_ferr = msg_mon_get_my_segid(&lv_key);
assert(lv_ferr == XZFIL_ERR_OK);
if (gv_verbose)
printf("srv: shm key=%d\n", lv_key);
lv_msid = shmget(lv_key, sizeof(long), 0640);
if (lv_msid == -1) {
lv_created = true;
if (gv_verbose)
printf("srv: shmget failed, errno=%d\n", errno);
lv_msid = shmget(lv_key, sizeof(long), IPC_CREAT | 0640);
if (lv_msid == -1) {
if (gv_verbose)
printf("srv: shmget(IPC_CREAT) failed, errno=%d\n", errno);
assert(lv_msid != -1);
} else {
if (gv_verbose)
printf("srv: shmget(IPC_CREAT) ok\n");
}
} else {
lv_created = false;
if (gv_verbose)
printf("srv: shmget ok\n");
}
gp_shm = (char *) shmat(lv_msid, NULL, 0);
if (gp_shm == NULL) {
if (gv_verbose)
printf("srv: shmat failed, errno=%d\n", errno);
assert(gp_shm != NULL);
} else {
gp_shml = (unsigned long *) gp_shm;
if (gv_verbose)
printf("srv: shmat ok, shm=%p\n", gp_shm);
if (lv_created) {
clock_gettime(CLOCK_REALTIME, &lv_ts);
// nsec / 1000 => usec
// 1,000,000 usec requires 20 bits. i.e. 2^20=1,048,576
// unsigned long is 64 bits, so squeeze secs into leftover 44 bits
// 100(yrs) * 365(days) * 24(hrs) * 60(min) * 60(sec)=3,153,600,000
// requires 32 bits
lv_tsl = ((unsigned long) lv_ts.tv_sec << 20) | ((unsigned long) lv_ts.tv_nsec / 1000);
*gp_shml = lv_tsl;
if (gv_verbose)
printf("srv: initializing shm=0x%lx\n", lv_tsl);
}
}
}
//
// server main
//
int main(int pv_argc, char *pa_argv[]) {
bool lv_done;
int lv_ferr;
int lv_lerr;
BMS_SRE lv_sre;
CALL_COMP_DOVERS(idtmsrv, pv_argc, pa_argv);
do_init(pv_argc, pa_argv);
lv_ferr = msg_mon_process_startup(true); // system messages
assert(lv_ferr == XZFIL_ERR_OK);
msg_mon_enable_mon_messages(true);
lv_ferr = msg_mon_get_my_process_name(ga_name, sizeof(ga_name));
assert(lv_ferr == XZFIL_ERR_OK);
do_shm();
lv_ferr = timer_start_cb(gv_time_refresh_delay, 0, 0, &gv_tleid, &timer_callback);
assert(lv_ferr == XZFIL_ERR_OK);
lv_done = false;
while (!lv_done) {
do {
lv_lerr = XWAIT(LREQ, -1);
lv_lerr = BMSG_LISTEN_((short *) &lv_sre, // sre
0, // listenopts
0); // listenertag
} while (lv_lerr == XSRETYPE_NOWORK);
if (lv_sre.sre_flags & XSRE_MON) {
do_mon_msg(&lv_sre, &lv_done);
} else {
do_req(&lv_sre);
}
}
if (gv_verbose)
printf("server %s shutting down\n", ga_name);
lv_ferr = msg_mon_process_shutdown();
assert(lv_ferr == XZFIL_ERR_OK);
return 0;
}