mevb.c

Go to the documentation of this file.
00001 /********************************************************************\
00002 Name:         mevb.c
00003 Created by:   Pierre-Andre Amaudruz
00004 
00005 Contents:     Main Event builder task.
00006 $Log: mevb.c,v $
00007 Revision 1.12  2004/01/08 08:40:08  midas
00008 Implemented standard indentation
00009 
00010 Revision 1.11  2004/01/08 06:48:26  pierre
00011 Doxygen the file
00012 
00013 Revision 1.10  2003/08/19 23:26:36  pierre
00014 fix cm_get_environment arg
00015 
00016 Revision 1.9  2002/10/07 17:04:01  pierre
00017 fix tr_stop request
00018 
00019 Revision 1.8  2002/09/28 00:48:33  pierre
00020 Add EB_USER_ERROR handling, handFlush()
00021 
00022 Revision 1.7  2002/09/25 18:37:37  pierre
00023 correct: header passing, user field, abort run
00024 
00025 Revision 1.6  2002/08/29 22:07:47  pierre
00026 fix event header, double task, EOR
00027 
00028 Revision 1.5  2002/07/13 05:45:49  pierre
00029 added swap before user function
00030 
00031 Revision 1.4  2002/06/14 04:59:08  pierre
00032 revised for ybos 
00033 
00034 Revision 1.3  2002/05/08 20:51:41  midas
00035 Added extra parameter to function db_get_value()
00036 
00037 Revision 1.2  2002/01/17 23:34:14  pierre
00038 doc++ format
00039 
00040 Revision 1.1.1.1  2002/01/17 19:49:54  pierre
00041 Initial Version
00042 
00043 \********************************************************************/
00044 
00045 /**dox***************************************************************/
00046 /* @file mevb.c
00047 The Event builder main file 
00048 */
00049 
00050 #include <stdio.h>
00051 #include "midas.h"
00052 #include "mevb.h"
00053 #include "msystem.h"
00054 #include "ybos.h"
00055 
00056 EBUILDER_SETTINGS ebset;
00057 EBUILDER_STATISTICS ebstat;
00058 EBUILDER_CHANNEL ebch[MAX_CHANNELS];
00059 
00060 DWORD max_event_size = MAX_EVENT_SIZE;
00061 
00062 HNDLE hDB, hKey, hStatKey;
00063 BOOL debug = FALSE, debug1 = FALSE;
00064 
00065 BOOL abort_requested = FALSE, stop_requested = TRUE;
00066 BOOL stopped = TRUE;
00067 BOOL wheel = FALSE;
00068 INT run_state = 0;
00069 DWORD start_time = 0, stop_time = 0, request_stop_time = 0;
00070 DWORD gbl_bytes_sent = 0, gbl_events_sent = 0;
00071 DWORD cdemask = 0;
00072 INT gbl_run = 0;
00073 
00074 INT(*meb_fragment_add) (char *, char *, INT *);
00075 INT handFlush(INT);
00076 INT source_booking(INT nfrag);
00077 INT eb_mfragment_add(char *pdest, char *psrce, INT * size);
00078 INT eb_yfragment_add(char *pdest, char *psrce, INT * size);
00079 
00080 INT eb_begin_of_run(INT, char *, char *);
00081 INT eb_end_of_run(INT, char *);
00082 INT eb_user(INT, EBUILDER_CHANNEL *, EVENT_HEADER *, void *, INT *);
00083 
00084 extern INT ybos_event_swap(DWORD * pevt);
00085 
00086 /********************************************************************/
00087 INT eb_mfragment_add(char *pdest, char *psrce, INT * size)
00088 {
00089    BANK_HEADER *psbh, *pdbh;
00090    char *psdata, *pddata;
00091    INT bksize;
00092 
00093    /* Condition for new EVENT the data_size should be ZERO */
00094    *size = ((EVENT_HEADER *) pdest)->data_size;
00095 
00096    /* destination pointer */
00097    pddata = pdest + *size + sizeof(EVENT_HEADER);
00098 
00099    if (*size) {
00100       /* NOT the first fragment */
00101 
00102       /* Swap event source if necessary */
00103       psbh = (BANK_HEADER *) (((EVENT_HEADER *) psrce) + 1);
00104       bk_swap(psbh, FALSE);
00105 
00106       /* source pointer */
00107       psbh = (BANK_HEADER *) (((EVENT_HEADER *) psrce) + 1);
00108       psdata = (char *) (psbh + 1);
00109 
00110       /* copy all banks without the bank header */
00111       bksize = psbh->data_size;
00112 
00113       /* copy */
00114       memcpy(pddata, psdata, bksize);
00115 
00116       /* update event size */
00117       ((EVENT_HEADER *) pdest)->data_size += bksize;
00118 
00119       /* update bank size */
00120       pdbh = (BANK_HEADER *) (((EVENT_HEADER *) pdest) + 1);
00121       pdbh->data_size += bksize;
00122 
00123       *size = ((EVENT_HEADER *) pdest)->data_size;
00124    } else {
00125       /* First event without the event header but with the 
00126          bank header as the size is zero */
00127       *size = ((EVENT_HEADER *) psrce)->data_size;
00128 
00129       /* Swap event if necessary */
00130       psbh = (BANK_HEADER *) (((EVENT_HEADER *) psrce) + 1);
00131       bk_swap(psbh, FALSE);
00132 
00133       /* copy first fragment */
00134       memcpy(pddata, psbh, *size);
00135 
00136       /* update destination event size */
00137       ((EVENT_HEADER *) pdest)->data_size = *size;
00138    }
00139    return CM_SUCCESS;
00140 }
00141 
00142 /*--------------------------------------------------------------------*/
00143 INT eb_yfragment_add(char *pdest, char *psrce, INT * size)
00144 {
00145    /* pdest : EVENT_HEADER pointer
00146       psrce : EVENT_HEADER pointer
00147       Keep pbkh for later incrementation
00148     */
00149    char *psdata, *pddata;
00150    DWORD *pslrl, *pdlrl;
00151    INT i4frgsize, i1frgsize, status;
00152 
00153    /* Condition for new EVENT the data_size should be ZERO */
00154    *size = ((EVENT_HEADER *) pdest)->data_size;
00155 
00156    /* destination pointer skip the header as it has been already
00157       composed and the usere may have modified it on purpose (Midas Control) */
00158    pddata = pdest + *size + sizeof(EVENT_HEADER);
00159 
00160    /* the Midas header is present for logger */
00161    if (*size) {                 /* already filled with a fragment */
00162 
00163       /* source pointer: number of DWORD (lrl included) */
00164       pslrl = (DWORD *) (((EVENT_HEADER *) psrce) + 1);
00165 
00166       /* Swap event if necessary */
00167       status = ybos_event_swap(pslrl);
00168 
00169       /* copy done in bytes, do not include LRL */
00170       psdata = (char *) (pslrl + 1);
00171 
00172       /* copy size in I*4 (lrl included, remove it) */
00173       i4frgsize = (*pslrl);
00174       i1frgsize = 4 * i4frgsize;
00175 
00176       /* append fragment */
00177       memcpy(pddata, psdata, i1frgsize);
00178 
00179       /* update Midas header event size */
00180       ((EVENT_HEADER *) pdest)->data_size += i1frgsize;
00181 
00182       /* update LRL size (I*4) */
00183       pdlrl = (DWORD *) (((EVENT_HEADER *) pdest) + 1);
00184       *pdlrl += i4frgsize;
00185 
00186       /* Return event size in bytes */
00187       *size = ((EVENT_HEADER *) pdest)->data_size;
00188    } else {                     /* new destination event */
00189       /* The composed event has already the MIDAS header.
00190          which may have been modified by the user in ebuser.c
00191          Will be stripped by the logger (YBOS).
00192          Copy the first full event ( no EVID suppression )
00193          First event (without the event header) */
00194 
00195       /* source pointer */
00196       pslrl = (DWORD *) (((EVENT_HEADER *) psrce) + 1);
00197 
00198       /* Swap event if necessary */
00199       status = ybos_event_swap(pslrl);
00200 
00201       /* size in byte from the source midas header */
00202       *size = ((EVENT_HEADER *) psrce)->data_size;
00203 
00204       /* copy first fragment */
00205       memcpy(pddata, (char *) pslrl, *size);
00206 
00207       /* update destination Midas header event size */
00208       ((EVENT_HEADER *) pdest)->data_size += *size;
00209 
00210    }
00211    return CM_SUCCESS;
00212 }
00213 
00214 /*--------------------------------------------------------------------*/
00215 INT tr_prestart(INT rn, char *error)
00216 {
00217    INT fragn, status, size;
00218 
00219    abort_requested = FALSE;
00220    gbl_run = rn;
00221    printf("EBuilder-Starting New Run: %d\n", rn);
00222 
00223    /* Reset Destination statistics */
00224    memset((char *) &ebstat, 0, sizeof(EBUILDER_STATISTICS));
00225    db_set_record(hDB, hStatKey, &ebstat, sizeof(EBUILDER_STATISTICS), 0);
00226    gbl_bytes_sent = 0;
00227    gbl_events_sent = 0;
00228 
00229    /* Reset local Source statistics */
00230    for (fragn = 0;; fragn++) {
00231       if (ebch[fragn].name[0] == 0)
00232          break;
00233       memset(&(ebch[fragn].stat), 0, sizeof(EBUILDER_STATISTICS));
00234    }
00235 
00236    /* Update the user_field */
00237    size = sizeof(ebset.user_field);
00238    db_get_value(hDB, 0, "/Ebuilder/Settings/User Field", ebset.user_field, &size,
00239                 TID_STRING, FALSE);
00240 
00241    /* Call BOR user function */
00242    status = eb_begin_of_run(gbl_run, ebset.user_field, error);
00243    if (status != EB_SUCCESS) {
00244       cm_msg(MERROR, "eb_prestart", "run start aborted due to eb_begin_of_run (%d)",
00245              status);
00246       return status;
00247    }
00248 
00249    /* Book all fragment */
00250    status = source_booking(fragn);
00251    if (status != SUCCESS)
00252       return status;
00253 
00254    /* Mark run start time for local purpose */
00255    start_time = ss_millitime();
00256 
00257    /* local run state */
00258    run_state = STATE_RUNNING;
00259    stopped = FALSE;
00260    stop_requested = FALSE;
00261 
00262    /* Reset global trigger mask */
00263    cdemask = 0;
00264    return CM_SUCCESS;
00265 }
00266 
00267 /*--------------------------------------------------------------------*/
00268 INT tr_stop(INT rn, char *error)
00269 {
00270    printf("\nEBuilder-Stopping Run: %d detected\n", rn);
00271 
00272    /* local stop */
00273    stop_requested = TRUE;
00274 
00275    /* local stop time */
00276    request_stop_time = ss_millitime();
00277    return CM_SUCCESS;
00278 }
00279 
00280 /*--------------------------------------------------------------------*/
00281 void free_event_buffer(INT nfrag)
00282 {
00283    INT i;
00284    for (i = 0; i < nfrag; i++) {
00285       if (ebch[i].pfragment) {
00286          free(ebch[i].pfragment);
00287          ebch[i].pfragment = NULL;
00288       }
00289    }
00290 }
00291 
00292 
00293 /*--------------------------------------------------------------------*/
00294 INT handFlush(INT nfragment)
00295 {
00296    int i, size, status;
00297    char strout[256];
00298 
00299    /* Do Hand flush until better way to  garantee the input buffer to be empty */
00300    if (debug)
00301       printf("Hand flushing system buffer... \n");
00302    for (i = 0; i < nfragment; i++) {
00303       do {
00304          size = max_event_size;
00305          status = bm_receive_event(ebch[i].hBuf, ebch[i].pfragment, &size, ASYNC);
00306          if (debug1) {
00307             sprintf(strout,
00308                     "booking:Hand flush bm_receive_event[%d] hndle:%d stat:%d  Last Ser:%d",
00309                     i, ebch[i].hBuf, status,
00310                     ((EVENT_HEADER *) ebch[i].pfragment)->serial_number);
00311             printf("%s\n", strout);
00312          }
00313       } while (status == BM_SUCCESS);
00314    }
00315 
00316    /* Empty source buffer */
00317    status = bm_empty_buffers();
00318    if (status != BM_SUCCESS)
00319       cm_msg(MERROR, "source_booking", "bm_empty_buffers failure [%d]", status);
00320    stopped = TRUE;
00321    run_state = STATE_STOPPED;
00322    return status;
00323 }
00324 
00325 
00326 /*--------------------------------------------------------------------*/
00327 INT source_booking(INT nfrag)
00328 {
00329    INT j, i, status, status1, status2;
00330 
00331    if (debug)
00332       printf("Entering booking\n");
00333 
00334    /* Book all the source channels */
00335    for (i = 0; i < nfrag; i++) {
00336       /* Book only the requested event mask */
00337       if (ebch[i].set.emask) {
00338          /* Connect channel to source buffer */
00339          status1 = bm_open_buffer(ebch[i].set.buffer, EVENT_BUFFER_SIZE, &(ebch[i].hBuf));
00340 
00341          if (debug)
00342             printf("bm_open_buffer frag:%d handle:%d stat:%d\n",
00343                    i, ebch[i].hBuf, status1);
00344          /* Register for specified channel event ID and Trigger mask */
00345          status2 =
00346              bm_request_event(ebch[i].hBuf, ebch[i].set.event_id,
00347                               ebch[i].set.trigger_mask, GET_ALL, &ebch[i].req_id, NULL);
00348          if (debug)
00349             printf("bm_request_event frag:%d req_id:%d stat:%d\n",
00350                    i, ebch[i].req_id, status1);
00351          if (((status1 != BM_SUCCESS) && (status1 != BM_CREATED)) ||
00352              ((status2 != BM_SUCCESS) && (status2 != BM_CREATED))) {
00353             cm_msg(MERROR, "source_booking",
00354                    "Open buffer/event request failure [%d %d %d]", i, status1, status2);
00355             return BM_CONFLICT;
00356          }
00357 
00358          /* allocate local source event buffer */
00359          if (ebch[i].pfragment)
00360             free(ebch[i].pfragment);
00361          ebch[i].pfragment = (char *) malloc(max_event_size + sizeof(EVENT_HEADER));
00362          if (debug)
00363             printf("malloc pevent frag:%d pevent:%p\n", i, ebch[i].pfragment);
00364          if (ebch[i].pfragment == NULL) {
00365             free_event_buffer(nfrag);
00366             cm_msg(MERROR, "source_booking", "Can't allocate space for buffer");
00367             return BM_NO_MEMORY;
00368          }
00369       }
00370    }
00371 
00372    /* Empty source buffer */
00373    status = bm_empty_buffers();
00374    if (status != BM_SUCCESS) {
00375       cm_msg(MERROR, "source_booking", "bm_empty_buffers failure [%d]", status);
00376       return status;
00377    }
00378 
00379    if (debug) {
00380       printf("bm_empty_buffers stat:%d\n", status);
00381       printf("Dest: mask:%x\n", ebset.emask);
00382       for (j = 0;; j++) {
00383          if (ebch[j].name[0] == 0)
00384             break;
00385 
00386          printf("%d)%s", j, ebch[j].name);
00387          printf(" buff:%s", ebch[j].set.buffer);
00388          printf(" msk#:%4.4x", ebch[j].set.emask);
00389          printf(" ser#:%d", ebch[j].serial);
00390          printf(" hbuf:%2d", ebch[j].hBuf);
00391          printf(" rqid:%2d", ebch[j].req_id);
00392          printf(" opst:%d", status1);
00393          printf(" rqst:%d", status2);
00394          printf(" evid:%2d", ebch[j].set.event_id);
00395          printf(" tmsk:0x%4.4x\n", ebch[j].set.trigger_mask);
00396       }
00397    }
00398 
00399    return SUCCESS;
00400 }
00401 
00402 /*--------------------------------------------------------------------*/
00403 INT source_unbooking(nfrag)
00404 {
00405    INT i, status;
00406 
00407    /* Skip unbooking if already done */
00408    if (ebch[0].pfragment == NULL)
00409       return EB_SUCCESS;
00410 
00411    /* unbook all source channels */
00412    for (i = nfrag - 1; i >= 0; i--) {
00413       bm_empty_buffers();
00414 
00415       /* Remove event ID registration */
00416       status = bm_delete_request(ebch[i].req_id);
00417       if (debug)
00418          printf("unbook: bm_delete_req[%d] req_id:%d stat:%d\n", i, ebch[i].req_id,
00419                 status);
00420 
00421       /* Close source buffer */
00422       status = bm_close_buffer(ebch[i].hBuf);
00423       if (debug)
00424          printf("unbook: bm_close_buffer[%d] hndle:%d stat:%d\n", i, ebch[i].hBuf,
00425                 status);
00426       if (status != BM_SUCCESS) {
00427          cm_msg(MERROR, "source_unbooking", "Close buffer[%d] stat:", i, status);
00428          return status;
00429       }
00430    }
00431 
00432    /* release local event buffer memory */
00433    free_event_buffer(nfrag);
00434 
00435    return EB_SUCCESS;
00436 }
00437 
00438 /********************************************************************/
00439 /**
00440 Scan all the fragment source once per call.
00441 
00442 -# This will retrieve the full midas event not swapped (except the
00443 MIDAS_HEADER) for each fragment if possible. The fragment will
00444 be stored in the channel event pointer.
00445 -# if after a full nfrag path some frag are still not cellected, it
00446 returns with the frag# missing for timeout check.
00447 -# If ALL fragments are present it will check the midas serial#
00448 for a full match across all the fragments.
00449 -# If the serial check fails it returns with "event mismatch"
00450 and will abort the event builder but not stop the run for now.
00451 -# If the serial check is passed, it will call the user_build function
00452 where the destination event is going to be composed.
00453 
00454 @param fmt Fragment format type 
00455 @param nfragment number of fragment to collect
00456 @param dest_hBuf  Destination buffer handle
00457 @param dest_event destination point for built event 
00458 @return   EB_NO_MORE_EVENT, EB_COMPOSE_TIMEOUT
00459 if different then SUCCESS (bm_compose, rpc_sent error)
00460 */
00461 INT source_scan(INT fmt, INT nfragment, HNDLE dest_hBuf, char *dest_event)
00462 {
00463    static char bars[] = "|/-\\";
00464    static int i_bar;
00465    static DWORD serial;
00466    DWORD *plrl;
00467    INT i, j, status, size;
00468    INT act_size;
00469    BOOL found, event_mismatch;
00470    BANK_HEADER *psbh;
00471 
00472    /* Scan all channels at least once */
00473    for (i = 0; i < nfragment; i++) {
00474       /* Check if current channel needs to be received */
00475       if ((ebset.emask & ebch[i].set.emask) & ~cdemask) {
00476          /* Get fragment and store it in ebch[i].pfragment */
00477          size = max_event_size;
00478          status = bm_receive_event(ebch[i].hBuf, ebch[i].pfragment, &size, ASYNC);
00479          switch (status) {
00480          case BM_SUCCESS:      /* event received */
00481             /* Mask event */
00482             cdemask |= ebch[i].set.emask;
00483 
00484             /* Keep local serial */
00485             ebch[i].serial = ((EVENT_HEADER *) ebch[i].pfragment)->serial_number;
00486 
00487             /* Swap event depending on data format */
00488             switch (fmt) {
00489             case FORMAT_YBOS:
00490                plrl = (DWORD *) (((EVENT_HEADER *) ebch[i].pfragment) + 1);
00491                ybos_event_swap(plrl);
00492                break;
00493             case FORMAT_MIDAS:
00494                psbh = (BANK_HEADER *) (((EVENT_HEADER *) ebch[i].pfragment) + 1);
00495                bk_swap(psbh, FALSE);
00496                break;
00497             }
00498 
00499             /* update local source statistics */
00500             ebch[i].stat.events_sent++;
00501 
00502             if (debug1) {
00503                printf("SUCC: ch:%d ser:%d Dest_emask:%d cdemask:%x emask:%x sz:%d\n", i,
00504                       ebch[i].serial, ebset.emask, cdemask, ebch[i].set.emask, size);
00505             }
00506             break;
00507          case BM_ASYNC_RETURN: /* timeout */
00508             ebch[i].timeout++;
00509             if (debug1) {
00510                printf("ASYNC: ch:%d ser:%d Dest_emask:%d cdemask:%x emask:%x sz:%d\n", i,
00511                       ebch[i].serial, ebset.emask, cdemask, ebch[i].set.emask, size);
00512             }
00513             break;
00514          default:              /* Error */
00515             cm_msg(MERROR, "event_scan", "bm_receive_event error %d", status);
00516             return status;
00517             break;
00518          }
00519       }                         /* ~cdemask => next channel */
00520    }
00521 
00522    /* Check if all fragments have been received */
00523    if (cdemask == ebset.emask) {        /* All fragment in */
00524       /* Check if serial matches */
00525       found = event_mismatch = FALSE;
00526       /* Mark first serial */
00527       for (j = 0; j < nfragment; j++) {
00528          if (ebch[j].set.emask && !found) {
00529             serial = ebch[j].serial;
00530             found = TRUE;
00531          } else {
00532             if (ebch[j].set.emask && (serial != ebch[j].serial)) {
00533                /* Event mismatch */
00534                event_mismatch = TRUE;
00535             }
00536          }
00537       }
00538 
00539       if (abort_requested) {
00540          cdemask = 0;
00541          return EB_SKIP;
00542       }
00543 
00544       /* Global event mismatch */
00545       if (event_mismatch) {
00546          char str[256];
00547          char strsub[128];
00548          cdemask = 0;
00549          strcpy(str, "event mismatch: ");
00550          for (j = 0; j < nfragment; j++) {
00551             sprintf(strsub, "Ser[%d]:%d ", j, ebch[j].serial);
00552             strcat(str, strsub);
00553          }
00554       } else {                  /* serial number match */
00555 
00556          /* wheel display */
00557          if (wheel && (serial % 1024) == 0) {
00558             printf("...%c ..Going on %1.0lf\r", bars[i_bar++ % 4], ebstat.events_sent);
00559             fflush(stdout);
00560          }
00561 
00562          /* Inform this is a NEW destination event building procedure */
00563          memset(dest_event, 0, sizeof(EVENT_HEADER));
00564          act_size = 0;
00565 
00566          /* Fill reserved header space of destination event with
00567             final header information */
00568          bm_compose_event((EVENT_HEADER *) dest_event, ebset.event_id, ebset.trigger_mask,
00569                           act_size, ebch[0].serial);
00570 
00571          /* Pass fragments to user for final check before assembly */
00572          status =
00573              eb_user(nfragment, ebch, (EVENT_HEADER *) dest_event,
00574                      (void *) ((EVENT_HEADER *) dest_event + 1), &act_size);
00575          if (status != SS_SUCCESS)
00576             return status;
00577 
00578          /* Allow bypass of fragment assembly if user wants to do it on its own */
00579          if (!ebset.user_build) {
00580             for (j = 0; j < nfragment; j++) {
00581                status = meb_fragment_add(dest_event, ebch[j].pfragment, &act_size);
00582                if (status != EB_SUCCESS) {
00583                   cm_msg(MERROR, "source_scan",
00584                          "compose fragment:%d current size:%d (%d)", j, act_size, status);
00585                   return EB_ERROR;
00586                }
00587             }
00588          }
00589 
00590          /* skip user_build */
00591          /* Overall event to be sent */
00592          act_size = ((EVENT_HEADER *) dest_event)->data_size + sizeof(EVENT_HEADER);
00593 
00594          /* Send event and wait for completion */
00595          status = rpc_send_event(dest_hBuf, dest_event, act_size, SYNC);
00596          if (status != BM_SUCCESS) {
00597             if (debug)
00598                printf("rpc_send_event returned error %d, event_size %d\n",
00599                       status, act_size);
00600             cm_msg(MERROR, "EBuilder", "rpc_send_event returned error %d", status);
00601             return EB_ERROR;
00602          }
00603 
00604          /* Keep track of the total byte count */
00605          gbl_bytes_sent += act_size;
00606 
00607          /* update destination event count */
00608          ebstat.events_sent++;
00609          gbl_events_sent++;
00610 
00611          /* Reset mask and timeouts */
00612          for (i = 0; i < nfragment; i++)
00613             ebch[i].timeout = 0;
00614          cdemask = 0;
00615       }                         /* serial match */
00616       return EB_SUCCESS;
00617    }
00618    /* cdemask == ebset.emask */
00619    return status;
00620 }
00621 
00622 /*--------------------------------------------------------------------*/
00623 int main(unsigned int argc, char **argv)
00624 {
00625    static char bars[] = "|\\-/";
00626    static int i_bar;
00627    char host_name[HOST_NAME_LENGTH], expt_name[HOST_NAME_LENGTH];
00628    INT size, status;
00629    DWORD nfragment, fragn;
00630    char *dest_event;
00631    DWORD last_time = 0, actual_millitime = 0, previous_event_sent = 0;
00632    DWORD i, j;
00633    BOOL daemon = FALSE, flag = TRUE;
00634    INT state, fmt;
00635    HNDLE hBuf, hSubkey, hEKey, hSetKey, hChKey;
00636    EBUILDER(ebuilder_str);
00637    EBUILDER_CHANNEL(ebuilder_channel_str);
00638    char strout[128];
00639    KEY key;
00640    /* init structure */
00641    memset(&ebch[0], 0, sizeof(ebch));
00642 
00643    /* set default */
00644    cm_get_environment(host_name, sizeof(host_name), expt_name, sizeof(expt_name));
00645 
00646    /* get parameters */
00647    for (i = 1; i < argc; i++) {
00648       if (argv[i][0] == '-' && argv[i][1] == 'd')
00649          debug = TRUE;
00650       else if (argv[i][0] == '-' && argv[i][1] == 'D')
00651          daemon = TRUE;
00652       else if (argv[i][0] == '-' && argv[i][1] == 'w')
00653          wheel = TRUE;
00654       else if (argv[i][0] == '-') {
00655          if (i + 1 >= argc || argv[i + 1][0] == '-')
00656             goto usage;
00657          if (strncmp(argv[i], "-e", 2) == 0)
00658             strcpy(expt_name, argv[++i]);
00659          else if (strncmp(argv[i], "-h", 2) == 0)
00660             strcpy(host_name, argv[++i]);
00661       } else {
00662        usage:
00663          printf("usage: mevb [-h <Hostname>] [-e <Experiment>] [-d debug]\n");
00664          printf("             -w show wheel -D to start as a daemon\n\n");
00665          return 0;
00666       }
00667    }
00668 
00669    printf("Program mevb/EBuilder version 3 started\n\n");
00670    if (daemon) {
00671       printf("Becoming a daemon...\n");
00672       ss_daemon_init(FALSE);
00673    }
00674 
00675    /* Connect to experiment */
00676    status = cm_connect_experiment(host_name, expt_name, "EBuilder", NULL);
00677    if (status != CM_SUCCESS)
00678       return 1;
00679 
00680    /* check if Ebuilder is already running */
00681    status = cm_exist("Ebuilder", FALSE);
00682    if (status == CM_SUCCESS) {
00683       cm_msg(MERROR, "Ebuilder", "Ebuilder running already!.\n");
00684       cm_disconnect_experiment();
00685       return 1;
00686    }
00687 
00688    /* Connect to ODB */
00689    cm_get_experiment_database(&hDB, &hKey);
00690 
00691    /* Setup tree */
00692    if (db_find_key(hDB, 0, "EBuilder", &hEKey) != DB_SUCCESS)
00693       db_create_record(hDB, 0, "EBuilder", strcomb(ebuilder_str));
00694    db_find_key(hDB, 0, "EBuilder", &hEKey);
00695 
00696    /* EB setting handle */
00697    db_find_key(hDB, hEKey, "Settings", &hSetKey);
00698    size = sizeof(EBUILDER_SETTINGS);
00699    status = db_get_record(hDB, hSetKey, &ebset, &size, 0);
00700 
00701    /* Get hostname for status page */
00702    gethostname(ebset.hostname, sizeof(ebset.hostname));
00703    size = sizeof(ebset.hostname);
00704    db_set_value(hDB, hSetKey, "hostname", ebset.hostname, size, 1, TID_STRING);
00705 
00706    /* Get EB statistics */
00707    db_find_key(hDB, hEKey, "Statistics", &hStatKey);
00708 
00709    /* extract format */
00710    if (equal_ustring(ebset.format, "YBOS"))
00711       fmt = FORMAT_YBOS;
00712    else if (equal_ustring(ebset.format, "MIDAS"))
00713       fmt = FORMAT_MIDAS;
00714    else {                       /* default format is MIDAS */
00715 
00716       cm_msg(MERROR, "EBuilder", "Format not permitted");
00717       goto error;
00718    }
00719 
00720    /* Check for run condition */
00721    size = sizeof(state);
00722    db_get_value(hDB, 0, "/Runinfo/state", &state, &size, TID_INT, TRUE);
00723    if (state != STATE_STOPPED) {
00724       cm_msg(MTALK, "EBuilder", "Run must be stopped before starting EBuilder");
00725       goto error;
00726    }
00727 
00728    /* Scan EB Channels */
00729    if (db_find_key(hDB, hEKey, "Channels", &hChKey) != DB_SUCCESS) {
00730       db_create_record(hDB, hEKey, "Channels", strcomb(ebuilder_channel_str));
00731       db_find_key(hDB, hEKey, "Channels", &hChKey);
00732    }
00733 
00734    for (i = 0, j = 0, nfragment = 0; i < MAX_CHANNELS; i++) {
00735       db_enum_key(hDB, hChKey, i, &hSubkey);
00736       if (!hSubkey)
00737          break;
00738       db_get_key(hDB, hSubkey, &key);
00739       if (key.type == TID_KEY) {
00740          /* read channel record */
00741          sprintf(ebch[j].name, "%s", key.name);
00742          status = db_find_key(hDB, hSubkey, "Statistics", &(ebch[j].hStat));
00743          status = db_find_key(hDB, hSubkey, "Settings", &hKey);
00744          size = sizeof(EBUILDER_SETTINGS_CH);
00745          status = db_get_record(hDB, hKey, &(ebch[j].set), &size, 0);
00746          j++;
00747          nfragment++;
00748       }
00749    }
00750 
00751    /* Register transition for reset counters */
00752    if (cm_register_transition(TR_PRESTART, tr_prestart) != CM_SUCCESS)
00753       goto error;
00754    if (cm_register_transition(TR_STOP, tr_stop) != CM_SUCCESS)
00755       goto error;
00756 
00757    if (debug)
00758       cm_set_watchdog_params(TRUE, 0);
00759 
00760    /* Destination buffer */
00761    status = bm_open_buffer(ebset.buffer, EVENT_BUFFER_SIZE, &hBuf);
00762    if (debug)
00763       printf("bm_open_buffer dest returns %d\n", status);
00764    if (status != BM_SUCCESS && status != BM_CREATED) {
00765       printf("Error return from bm_open_buffer\n");
00766       goto error;
00767    }
00768 
00769    /* set the buffer write cache size */
00770    status = bm_set_cache_size(hBuf, 0, 200000);
00771    if (debug)
00772       printf("bm_set_cache_size dest returns %d\n", status);
00773 
00774    /* allocate destination event buffer */
00775    dest_event = (char *) malloc(nfragment * (max_event_size + sizeof(EVENT_HEADER)));
00776    memset(dest_event, 0, nfragment * (max_event_size + sizeof(EVENT_HEADER)));
00777    if (dest_event == NULL) {
00778       cm_msg(MERROR, "EBuilder", "Not enough memory for event buffer\n");
00779       goto error;
00780    }
00781 
00782    /* Set fragment_add function based on the format */
00783    if (fmt == FORMAT_MIDAS)
00784       meb_fragment_add = eb_mfragment_add;
00785    else if (fmt == FORMAT_YBOS)
00786       meb_fragment_add = eb_yfragment_add;
00787    else {
00788       cm_msg(MERROR, "mevb", "Unknown data format :%d", fmt);
00789       goto error;
00790    }
00791 
00792    /* Main event loop */
00793    do {
00794       if (run_state != STATE_RUNNING) {
00795          /* skip the source scan and yield */
00796          status = cm_yield(500);
00797          if (wheel) {
00798             printf("...%c Snoring on %1.0lf\r", bars[i_bar++ % 4], ebstat.events_sent);
00799             fflush(stdout);
00800          }
00801          continue;
00802       }
00803 
00804       /* scan source buffer and send event to destination
00805          The source_scan() serves one event at the time.
00806          The status returns:
00807          EB_SUCCESS, BM_ASYNC_RETURN, EB_ERROR
00808          In the case of no fragment found(timeout), a watchdog would
00809          kick in for a fix amount of time. If timeout occur,
00810          the run state is checked and memory channels are freed
00811        */
00812       status = source_scan(fmt, nfragment, hBuf, dest_event);
00813       switch (status) {
00814       case BM_ASYNC_RETURN:
00815          // No event found for now:
00816          // Check for timeout 
00817          for (fragn = 0; fragn < nfragment; fragn++) {
00818             if (ebch[fragn].timeout > TIMEOUT) {        /* Timeout */
00819                if (stop_requested) {    /* Stop */
00820                   if (debug)
00821                      printf("Stop requested on timeout %d\n", status);
00822 
00823                   /* Flush local destination cache */
00824                   bm_flush_cache(hBuf, SYNC);
00825 
00826                   /* Call user function */
00827                   eb_end_of_run(gbl_run, strout);
00828 
00829                   /* Cleanup buffers */
00830                   handFlush(nfragment);
00831 
00832                   /* Detach all source from midas */
00833                   source_unbooking(nfragment);
00834 
00835                   /* Compose message */
00836                   stop_time = ss_millitime() - request_stop_time;
00837                   sprintf(strout, "Run %d Stop on frag#%d; events_sent %1.0lf DT:%d[ms]",
00838                           gbl_run, fragn, ebstat.events_sent, stop_time);
00839 
00840                   /* Send message */
00841                   cm_msg(MINFO, "EBuilder", "%s", strout);
00842 
00843                   run_state = STATE_STOPPED;
00844                   abort_requested = FALSE;
00845                   break;
00846                } else {         /* No stop requested */
00847                   ebch[fragn].timeout = 0;
00848                   status = cm_yield(100);
00849                   if (wheel) {
00850                      printf("...%c Timoing on %1.0lf\r", bars[i_bar++ % 4],
00851                             ebstat.events_sent);
00852                      fflush(stdout);
00853                   }
00854                }
00855             }
00856             //else { /* No timeout */
00857             //  status = cm_yield(50);
00858             //}
00859          }                      /* do loop */
00860          break;
00861       case EB_ERROR:
00862       case EB_USER_ERROR:
00863          abort_requested = TRUE;
00864          if (status == EB_USER_ERROR)
00865             cm_msg(MTALK, "EBuilder", "Error signaled by user code - stopping run...");
00866          else
00867             cm_msg(MTALK, "EBuilder", "Event mismatch - Stopping run...");
00868          cdemask = 0;
00869          if (cm_transition(TR_STOP, 0, NULL, 0, ASYNC, 0) != CM_SUCCESS) {
00870             cm_msg(MERROR, "EBuilder", "Stop Transition request failed");
00871             goto error;
00872          }
00873          break;
00874       case EB_SUCCESS:
00875       case EB_SKIP:
00876          //   Normal path if event has been assembled
00877          //   No yield in this case.
00878          break;
00879       default:
00880          cm_msg(MERROR, "Source_scan", "unexpected return %d", status);
00881          status = SS_ABORT;
00882       }
00883 
00884       /* EB job done, update statistics if its time */
00885 
00886       /* Check if it's time to do statistics job */
00887       if ((actual_millitime = ss_millitime()) - last_time > 1000) {
00888          /* Force event to appear at the destination if Ebuilder is remote */
00889          rpc_flush_event();
00890          /* Force event ot appear at the destination if Ebuilder is local */
00891          bm_flush_cache(hBuf, ASYNC);
00892 
00893          /* update all source statistics */
00894          for (j = 0; j < nfragment; j++) {
00895 
00896             /* Compute statistics */
00897             if ((actual_millitime > start_time) && ebch[j].stat.events_sent) {
00898                ebch[j].stat.events_per_sec_ = ebch[j].stat.events_sent
00899                    / ((actual_millitime - last_time) / 1000.0);
00900 
00901                /* Update ODB channel statistics */
00902                db_set_record(hDB, ebch[j].hStat, &(ebch[j].stat)
00903                              , sizeof(EBUILDER_STATISTICS), 0);
00904             }
00905          }
00906 
00907          /* Compute destination statistics */
00908          if ((actual_millitime > start_time) && ebstat.events_sent) {
00909             ebstat.events_per_sec_ = gbl_events_sent
00910                 / ((actual_millitime - last_time) / 1000.0);
00911 
00912             ebstat.kbytes_per_sec_ = gbl_bytes_sent
00913                 / 1024.0 / ((actual_millitime - last_time) / 1000.0);
00914 
00915             /* update destination statistics */
00916             db_set_record(hDB, hStatKey, &ebstat, sizeof(EBUILDER_STATISTICS), 0);
00917          }
00918 
00919          /* Keep track of last ODB update */
00920          last_time = ss_millitime();
00921 
00922          /* Reset local rate counters */
00923          gbl_events_sent = 0;
00924          gbl_bytes_sent = 0;
00925 
00926          /* Yield for system messages */
00927          status = cm_yield(50);
00928          if (wheel && (run_state != STATE_RUNNING)) {
00929             printf("...%c Idleing on %1.0lf\r", bars[i_bar++ % 4], ebstat.events_sent);
00930             fflush(stdout);
00931          }
00932       }
00933    } while (status != RPC_SHUTDOWN && status != SS_ABORT);
00934    if (status == SS_ABORT)
00935       goto error;
00936    else
00937       goto exit;
00938 
00939  error:
00940    cm_msg(MTALK, "EBuilder", "Event builder error. Check messages");
00941 
00942  exit:
00943    /* Detach all source from midas */
00944    printf("EBuilder-Unbooking\n");
00945    source_unbooking(nfragment);
00946 
00947    /* Free local memory */
00948    free_event_buffer(nfragment);
00949 
00950    /* Clean disconnect from midas */
00951    cm_disconnect_experiment();
00952    return 0;
00953 }

Midas DOC Version 1.9.3 ---- PSI Stefan Ritt ----
Contributions: Pierre-Andre Amaudruz - Suzannah Daviel - Doxygen - Peter Green - Greg Hackman - Gertjan Hofman - Paul Knowles - Rudi Meier - Glenn Moloney - Dave Morris - Konstantin Olchanski - Renee Poutissou - Andreas Suter - Piotr Adam Zolnierczuk