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

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