dm_eb.c

Go to the documentation of this file.
00001 /********************************************************************\
00002 
00003   Name:         dm_eb.c
00004   Created by:   Stefan Ritt
00005 
00006   Contents:     dm_xxx() and eb_xxx() functions separated from midas.c
00007 
00008   $Id: dm_eb.c 4801 2010-08-06 18:29:14Z olchanski $
00009 
00010 \********************************************************************/
00011 
00012 #include "midas.h"
00013 #include "msystem.h"
00014 #include "strlcpy.h"
00015 #include <assert.h>
00016 #include <signal.h>
00017 
00018 static INT _send_sock;
00019 
00020 /**dox***************************************************************/
00021 /** @file dm_eb.c
00022 The main core C-code for Midas.
00023 */
00024 
00025 /** @defgroup dmfunctionc Midas Dual Buffer Memory Functions (dm_xxx)
00026  */
00027 
00028 /**dox***************************************************************/
00029 /** @addtogroup dmfunctionc
00030  *
00031  *  @{  */
00032 
00033 /**dox***************************************************************/
00034 #ifndef DOXYGEN_SHOULD_SKIP_THIS
00035 
00036 /********************************************************************\
00037 *                                                                    *
00038 *                 Dual memory buffer functions                       *
00039 *                                                                    *
00040 * Provide a dual memory buffer scheme for handling front-end         *
00041 * event. This code as been requested for allowing contemporary       *
00042 * task handling a)acquisition, b)network transfer if possible.       *
00043 * The pre-compiler switch will determine the mode of operation.      *
00044 * if DM_DUAL_THREAD is defined in mfe.c, it is expected to have      *
00045 * a seperate task taking care of the dm_area_send                    *
00046 *                                                                    *
00047 * "*" : visible functions                                            *
00048 * dm_buffer_create():     *Setup the dual memory buffer              *
00049 *                          Setup semaphore                           *
00050 *                          Spawn second thread                       *
00051 * dm_buffer_release():    *Release memory allocation for dm          *
00052 *                          Force a kill of 2nd thread                *
00053 *                          Remove semaphore                          *
00054 * dm_area_full():         *Check for both area being full            *
00055 *                          None blocking, may be used for interrupt  *
00056 *                          disable.                                  *
00057 * dm_pointer_get()     :  *Check memory space and return pointer     *
00058 *                          Blocking function with timeout if no more *
00059 *                          space for next event. If error will abort.*
00060 * dm_pointer_increment(): *Move pointer to next free location        *
00061 *                          None blocking. performs bm_send_event if  *
00062 *                          local connection.                         *
00063 * dm_area_send():         *Transfer FULL buffer(s)                   *
00064 *                          None blocking function.                   *
00065 *                          if DUAL_THREAD: Give sem_send semaphore   *
00066 *                          else transfer FULL buffer                 *
00067 * dm_area_flush():        *Transfer all remaining events from dm     *
00068 *                          Blocking function with timeout            *
00069 *                          if DUAL_THREAD: Give sem_flush semaphore. *
00070 * dm_task():               Secondary thread handling DUAL_THREAD     *
00071 *                          mechanism. Serves 2 requests:             *
00072 *                          dm_send:  Transfer FULL buffer only.      *
00073 *                          dm_flush: Transfer ALL buffers.           *
00074 * dm_area_switch():        internal, used by dm_pointer_get()        *
00075 * dm_active_full():        internal: check space in current buffer   *
00076 * dm_buffer_send():        internal: send data for given area        *
00077 * dm_buffer_time_get():    interal: return the time stamp of the     *
00078 *                          last switch                               *
00079 \********************************************************************/
00080 
00081 #define DM_FLUSH       10       /* flush request for DUAL_THREAD */
00082 #define DM_SEND        11       /* FULL send request for DUAL_THREAD */
00083 #define DM_KILL        12       /* Kill request for 2nd thread */
00084 #define DM_TIMEOUT     13       /* "timeout" return state in flush request for DUAL_THREAD */
00085 #define DM_ACTIVE_NULL 14       /* "both buffer were/are FULL with no valid area" return state */
00086 
00087 typedef struct {
00088    char *pt;                    /* top pointer    memory buffer          */
00089    char *pw;                    /* write pointer  memory buffer          */
00090    char *pe;                    /* end   pointer  memory buffer          */
00091    char *pb;                    /* bottom pointer memory buffer          */
00092    BOOL full;                   /* TRUE if memory buffer is full         */
00093    DWORD serial;                /* full buffer serial# for evt order     */
00094 } DMEM_AREA;
00095 
00096 typedef struct {
00097    DMEM_AREA *pa;               /* active memory buffer */
00098    DMEM_AREA area1;             /* mem buffer area 1 */
00099    DMEM_AREA area2;             /* mem buffer area 2 */
00100    DWORD serial;                /* overall buffer serial# for evt order     */
00101    INT action;                  /* for multi thread configuration */
00102    DWORD last_active;           /* switch time stamp */
00103    HNDLE sem_send;              /* semaphore for dm_task */
00104    HNDLE sem_flush;             /* semaphore for dm_task */
00105 } DMEM_BUFFER;
00106 
00107 DMEM_BUFFER dm;
00108 INT dm_user_max_event_size;
00109 
00110 /**dox***************************************************************/
00111 #endif                          /* DOXYGEN_SHOULD_SKIP_THIS */
00112 
00113 /********************************************************************/
00114 /**
00115 Setup a dual memory buffer. Has to be called initially before
00116            any other dm_xxx function
00117 @param size             Size in bytes
00118 @param user_max_event_size max event size
00119 @return CM_SUCCESS, BM_NO_MEMORY, BM_MEMSIZE_MISMATCH
00120 */
00121 INT dm_buffer_create(INT size, INT user_max_event_size)
00122 {
00123 
00124    dm.area1.pt = (char *) M_MALLOC(size);
00125    if (dm.area1.pt == NULL)
00126       return (BM_NO_MEMORY);
00127    dm.area2.pt = (char *) M_MALLOC(size);
00128    if (dm.area2.pt == NULL)
00129       return (BM_NO_MEMORY);
00130 
00131    /* check user event size against the system MAX_EVENT_SIZE */
00132    if (user_max_event_size > MAX_EVENT_SIZE) {
00133       cm_msg(MERROR, "dm_buffer_create", "user max event size too large");
00134       return BM_MEMSIZE_MISMATCH;
00135    }
00136    dm_user_max_event_size = user_max_event_size;
00137 
00138    memset(dm.area1.pt, 0, size);
00139    memset(dm.area2.pt, 0, size);
00140 
00141    /* initialize pointers */
00142    dm.area1.pb = dm.area1.pt + size - 1024;
00143    dm.area1.pw = dm.area1.pe = dm.area1.pt;
00144    dm.area2.pb = dm.area2.pt + size - 1024;
00145    dm.area2.pw = dm.area2.pe = dm.area2.pt;
00146 
00147   /*-PAA-*/
00148 #ifdef DM_DEBUG
00149    printf(" in dm_buffer_create ---------------------------------\n");
00150    printf(" %i %p %p %p %p\n", size, dm.area1.pt, dm.area1.pw, dm.area1.pe, dm.area1.pb);
00151    printf(" %i %p %p %p %p\n", size, dm.area2.pt, dm.area2.pw, dm.area2.pe, dm.area2.pb);
00152 #endif
00153 
00154    /* activate first area */
00155    dm.pa = &dm.area1;
00156 
00157    /* Default not full */
00158    dm.area1.full = dm.area2.full = FALSE;
00159 
00160    /* Reset serial buffer number with proper starting sequence */
00161    dm.area1.serial = dm.area2.serial = 0;
00162    /* ensure proper serial on next increment */
00163    dm.serial = 1;
00164 
00165    /* set active buffer time stamp */
00166    dm.last_active = ss_millitime();
00167 
00168    /* get socket for event sending */
00169    _send_sock = rpc_get_event_sock();
00170 
00171 #ifdef DM_DUAL_THREAD
00172    {
00173       INT status;
00174       VX_TASK_SPAWN starg;
00175 
00176       /* create semaphore */
00177       status = ss_semaphore_create("send", &dm.sem_send);
00178       if (status != SS_CREATED && status != SS_SUCCESS) {
00179          cm_msg(MERROR, "dm_buffer_create", "error in ss_semaphore_create send");
00180          return status;
00181       }
00182       status = ss_semaphore_create("flush", &dm.sem_flush);
00183       if (status != SS_CREATED && status != SS_SUCCESS) {
00184          cm_msg(MERROR, "dm_buffer_create", "error in ss_semaphore_create flush");
00185          return status;
00186       }
00187       /* spawn dm_task */
00188       memset(&starg, 0, sizeof(VX_TASK_SPAWN));
00189 
00190 #ifdef OS_VXWORKS
00191       /* Fill up the necessary arguments */
00192       strcpy(starg.name, "areaSend");
00193       starg.priority = 120;
00194       starg.stackSize = 20000;
00195 #endif
00196 
00197       if ((status = ss_thread_create(dm_task, (void *) &starg))
00198           != SS_SUCCESS) {
00199          cm_msg(MERROR, "dm_buffer_create", "error in ss_thread_create");
00200          return status;
00201       }
00202 #ifdef OS_WINNT
00203       /* necessary for true MUTEX (NT) */
00204       ss_semaphore_wait_for(dm.sem_send, 0);
00205 #endif
00206    }
00207 #endif                          /* DM_DUAL_THREAD */
00208 
00209    return CM_SUCCESS;
00210 }
00211 
00212 /**dox***************************************************************/
00213 #ifndef DOXYGEN_SHOULD_SKIP_THIS
00214 
00215 /********************************************************************/
00216 INT dm_buffer_release(void)
00217 /********************************************************************\
00218   Routine: dm_buffer_release
00219 
00220   Purpose: Release dual memory buffers
00221   Input:
00222     none
00223   Output:
00224     none
00225   Function value:
00226     CM_SUCCESS              Successful completion
00227 \********************************************************************/
00228 {
00229    if (dm.area1.pt) {
00230       free(dm.area1.pt);
00231       dm.area1.pt = NULL;
00232    }
00233    if (dm.area2.pt) {
00234       free(dm.area2.pt);
00235       dm.area2.pt = NULL;
00236    }
00237    dm.serial = 0;
00238    dm.area1.full = dm.area2.full = TRUE;
00239    dm.area1.serial = dm.area2.serial = 0;
00240 
00241 #ifdef DM_DUAL_THREAD
00242    /* kill spawned dm_task */
00243    dm.action = DM_KILL;
00244    ss_semaphore_release(dm.sem_send);
00245    ss_semaphore_release(dm.sem_flush);
00246 
00247    /* release semaphore */
00248    ss_semaphore_delete(dm.sem_send, 0);
00249    ss_semaphore_delete(dm.sem_flush, 0);
00250 #endif
00251 
00252    return CM_SUCCESS;
00253 }
00254 
00255 /********************************************************************/
00256 INLINE DMEM_AREA *dm_area_switch(void)
00257 /********************************************************************\
00258   Routine: dm_area_switch
00259 
00260   Purpose: set active area to the other empty area or NULL if both
00261            area are full. May have to check the serial consistancy...
00262   Input:
00263     none
00264   Output:
00265     none
00266   Function value:
00267     DMEM_AREA *            Pointer to active area or both full
00268 \********************************************************************/
00269 {
00270    volatile BOOL full1, full2;
00271 
00272    full1 = dm.area1.full;
00273    full2 = dm.area2.full;
00274 
00275    if (!full1 && !full2) {
00276       if (dm.area1.serial <= dm.area2.serial)
00277          return (&(dm.area1));
00278       else
00279          return (&(dm.area2));
00280    }
00281 
00282    if (!full1) {
00283       return (&(dm.area1));
00284    } else if (!full2) {
00285       return (&(dm.area2));
00286    }
00287    return (NULL);
00288 }
00289 
00290 /********************************************************************/
00291 INLINE BOOL dm_area_full(void)
00292 /********************************************************************\
00293   Routine: dm_area_full
00294 
00295   Purpose: Test if both area are full in order to block interrupt
00296   Input:
00297     none
00298   Output:
00299     none
00300   Function value:
00301     BOOL         TRUE if not enough space for another event
00302 \********************************************************************/
00303 {
00304    if (dm.pa == NULL || (dm.area1.full && dm.area2.full))
00305       return TRUE;
00306    return FALSE;
00307 }
00308 
00309 /********************************************************************/
00310 INLINE BOOL dm_active_full(void)
00311 /********************************************************************\
00312   Routine: dm_active_full
00313 
00314   Purpose: Test if there is sufficient space in either event buffer
00315            for another event.
00316   Input:
00317     none
00318   Output:
00319     none
00320   Function value:
00321     BOOL         TRUE if not enough space for another event
00322 \********************************************************************/
00323 {
00324    /* catch both full areas, waiting for transfer */
00325    if (dm.pa == NULL)
00326       return TRUE;
00327    /* Check the space in the active buffer only
00328       as I don't switch buffer here */
00329    if (dm.pa->full)
00330       return TRUE;
00331    return (((POINTER_T) dm.pa->pb - (POINTER_T) dm.pa->pw) < (INT)
00332            (dm_user_max_event_size + sizeof(EVENT_HEADER) + sizeof(INT)));
00333 }
00334 
00335 /********************************************************************/
00336 DWORD dm_buffer_time_get(void)
00337 /********************************************************************\
00338   Routine: dm_buffer_time_get
00339 
00340   Purpose: return the time from the last buffer switch.
00341 
00342   Input:
00343     none
00344   Output:
00345     none
00346   Function value:
00347     DWORD        time stamp
00348 
00349 \********************************************************************/
00350 {
00351    return (dm.last_active);
00352 }
00353 
00354 
00355 /********************************************************************/
00356 EVENT_HEADER *dm_pointer_get(void)
00357 /********************************************************************\
00358   Routine: dm_pointer_get
00359 
00360   Purpose: Get pointer to next free location in event buffer.
00361            after 10sec tries, it times out return NULL indicating a
00362            serious problem, i.e. abort.
00363   REMARK : Cannot be called twice in a raw due to +sizeof(INT)
00364   Input:
00365     none
00366   Output:
00367     DM_BUFFER * dm    local valid dm to work on
00368   Function value:
00369     EVENT_HEADER *    Pointer to free location
00370     NULL              cannot after several attempt get free space => abort
00371 \********************************************************************/
00372 {
00373    int timeout, status;
00374 
00375    /* Is there still space in the active area ? */
00376    if (!dm_active_full())
00377       return (EVENT_HEADER *) (dm.pa->pw + sizeof(INT));
00378 
00379    /* no more space => switch area */
00380 
00381    /* Tag current area with global dm.serial for order consistency */
00382    dm.pa->serial = dm.serial++;
00383 
00384    /* set active buffer time stamp */
00385    dm.last_active = ss_millitime();
00386 
00387    /* mark current area full */
00388    dm.pa->full = TRUE;
00389 
00390    /* Trigger/do data transfer (Now/don't wait) */
00391    if ((status = dm_area_send()) == RPC_NET_ERROR) {
00392       cm_msg(MERROR, "dm_pointer_get()", "Net error or timeout %i", status);
00393       return NULL;
00394    }
00395 
00396    /* wait switch completion (max 10 sec) */
00397    timeout = ss_millitime();    /* with timeout */
00398    while ((ss_millitime() - timeout) < 10000) {
00399       dm.pa = dm_area_switch();
00400       if (dm.pa != NULL)
00401          return (EVENT_HEADER *) (dm.pa->pw + sizeof(INT));
00402       ss_sleep(200);
00403 #ifdef DM_DEBUG
00404       printf(" waiting for space ... %i  dm_buffer  %i %i %i %i %i \n",
00405              ss_millitime() - timeout, dm.area1.full, dm.area2.full, dm.area1.serial, dm.area2.serial,
00406              dm.serial);
00407 #endif
00408    }
00409 
00410    /* Time running out abort */
00411    cm_msg(MERROR, "dm_pointer_get", "Timeout due to buffer full");
00412    return NULL;
00413 }
00414 
00415 
00416 /********************************************************************/
00417 int dm_pointer_increment(INT buffer_handle, INT event_size)
00418 /********************************************************************\
00419   Routine: dm_pointer_increment
00420 
00421   Purpose: Increment write pointer of event buffer after an event
00422            has been copied into the buffer (at an address previously
00423            obtained via dm_pointer_get)
00424   Input:
00425     INT buffer_handle         Buffer handle event should be sent to
00426     INT event_size            Event size in bytes including header
00427   Output:
00428     none
00429   Function value:
00430     CM_SUCCESS                Successful completion
00431     status                    from bm_send_event for local connection
00432 \********************************************************************/
00433 {
00434    INT aligned_event_size;
00435 
00436    /* if not connected remotely, use bm_send_event */
00437    if (_send_sock == 0) {
00438       *((INT *) dm.pa->pw) = buffer_handle;
00439       return bm_send_event(buffer_handle, dm.pa->pw + sizeof(INT), event_size, SYNC);
00440    }
00441    aligned_event_size = ALIGN8(event_size);
00442 
00443    *((INT *) dm.pa->pw) = buffer_handle;
00444 
00445    /* adjust write pointer */
00446    dm.pa->pw += sizeof(INT) + aligned_event_size;
00447 
00448    /* adjust end pointer */
00449    dm.pa->pe = dm.pa->pw;
00450 
00451    return CM_SUCCESS;
00452 }
00453 
00454 /********************************************************************/
00455 INLINE INT dm_buffer_send(DMEM_AREA * larea)
00456 /********************************************************************\
00457   Routine: dm_buffer_send
00458 
00459   Purpose: Ship data to the cache in fact!
00460            Basically the same do loop is done in the send_tcp.
00461            but _opt_tcp_size preveal if <= NET_TCP_SIZE.
00462            Introduced for bringing tcp option to user code.
00463   Input:
00464     DMEM_AREA * larea   The area to work with.
00465   Output:
00466     none
00467   Function value:
00468     CM_SUCCESS       Successful completion
00469     DM_ACTIVE_NULL   Both area were/are full
00470     RPC_NET_ERROR    send error
00471 \********************************************************************/
00472 {
00473    INT tot_size, nwrite;
00474    char *lpt;
00475 
00476    /* if not connected remotely, use bm_send_event */
00477    if (_send_sock == 0)
00478       return bm_flush_cache(*((INT *) dm.pa->pw), ASYNC);
00479 
00480    /* alias */
00481    lpt = larea->pt;
00482 
00483    /* Get overall buffer size */
00484    tot_size = (POINTER_T) larea->pe - (POINTER_T) lpt;
00485 
00486    /* shortcut for speed */
00487    if (tot_size == 0)
00488       return CM_SUCCESS;
00489 
00490 #ifdef DM_DEBUG
00491    printf("lpt:%p size:%i ", lpt, tot_size);
00492 #endif
00493    nwrite = send_tcp(_send_sock, lpt, tot_size, 0);
00494 #ifdef DM_DEBUG
00495    printf("nwrite:%i  errno:%i\n", nwrite, errno);
00496 #endif
00497    if (nwrite < 0)
00498       return RPC_NET_ERROR;
00499 
00500    /* reset area */
00501    larea->pw = larea->pe = larea->pt;
00502    larea->full = FALSE;
00503    return CM_SUCCESS;
00504 }
00505 
00506 /********************************************************************/
00507 INT dm_area_send(void)
00508 /********************************************************************\
00509   Routine: dm_area_send
00510 
00511   Purpose: Empty the FULL area only in proper event order
00512            Meant to be use either in mfe.c scheduler on every event
00513 
00514   Dual memory scheme:
00515    DM_DUAL_THREAD : Trigger sem_send
00516    !DM_DUAL_THREAD: empty full buffer in order, return active to area1
00517                     if dm.pa is NULL (were both full) and now both are empty
00518 
00519   Input:
00520     none
00521   Output:
00522     none
00523   Function value:
00524     CM_SUCCESS                Successful completion
00525     RPC_NET_ERROR             send error
00526 \********************************************************************/
00527 {
00528 #ifdef DM_DUAL_THREAD
00529    INT status;
00530 
00531    /* force a DM_SEND if possible. Don't wait for completion */
00532    dm.action = DM_SEND;
00533    ss_semaphore_release(dm.sem_send);
00534 #ifdef OS_WINNT
00535    /* necessary for true MUTEX (NT) */
00536    status = ss_semaphore_wait_for(dm.sem_send, 1);
00537    if (status == SS_NO_SEMAPHORE) {
00538       printf(" timeout while waiting for sem_send\n");
00539       return RPC_NET_ERROR;
00540    }
00541 #endif
00542 
00543    return CM_SUCCESS;
00544 #else
00545    /* ---------- NOT IN DUAL THREAD ----------- */
00546    INT status = 0;
00547 
00548    /* if no DUAL thread everything is local then */
00549    /* select the full area */
00550    if (dm.area1.full && dm.area2.full)
00551       if (dm.area1.serial <= dm.area2.serial)
00552          status = dm_buffer_send(&dm.area1);
00553       else
00554          status = dm_buffer_send(&dm.area2);
00555    else if (dm.area1.full)
00556       status = dm_buffer_send(&dm.area1);
00557    else if (dm.area2.full)
00558       status = dm_buffer_send(&dm.area2);
00559    if (status != CM_SUCCESS)
00560       return status;            /* catch transfer error too */
00561 
00562    if (dm.pa == NULL) {
00563       printf(" sync send dm.pa:%p full 1%d 2%d\n", dm.pa, dm.area1.full, dm.area2.full);
00564       dm.pa = &dm.area1;
00565    }
00566    return CM_SUCCESS;
00567 #endif
00568 }
00569 
00570 /********************************************************************/
00571 INT dm_task(void *pointer)
00572 /********************************************************************\
00573   Routine: dm_task
00574 
00575   Purpose: async send events doing a double purpose:
00576   a) send full buffer if found (DM_SEND) set by dm_active_full
00577   b) flush full areas (DM_FLUSH) set by dm_area_flush
00578   Input:
00579   none
00580   Output:
00581   none
00582   Function value:
00583   none
00584   \********************************************************************/
00585 {
00586 #ifdef DM_DUAL_THREAD
00587    INT status, timeout;
00588 
00589    printf("Semaphores initialization ... in areaSend ");
00590    /* Check or Wait for semaphore to be setup */
00591    timeout = ss_millitime();
00592    while ((ss_millitime() - timeout < 3000) && (dm.sem_send == 0))
00593       ss_sleep(200);
00594    if (dm.sem_send == 0)
00595       goto kill;
00596 
00597 #ifdef OS_WINNT
00598    /* necessary for true MUTEX (NT) get semaphore */
00599    ss_semaphore_wait_for(dm.sem_flush, 0);
00600 #endif
00601 
00602    /* Main FOREVER LOOP */
00603    printf("task areaSend ready...\n");
00604    while (1) {
00605       if (!dm_area_full()) {
00606          /* wait semaphore here ........ 0 == forever */
00607          ss_semaphore_wait_for(dm.sem_send, 0);
00608 #ifdef OS_WINNT
00609          /* necessary for true MUTEX (NT) give semaphore */
00610          ss_semaphore_release(dm.sem_send);
00611 #endif
00612       }
00613       if (dm.action == DM_SEND) {
00614 #ifdef DM_DEBUG
00615          printf("Send %i %i ", dm.area1.full, dm.area2.full);
00616 #endif
00617          /* DM_SEND : Empty the oldest buffer only. */
00618          if (dm.area1.full && dm.area2.full) {
00619             if (dm.area1.serial <= dm.area2.serial)
00620                status = dm_buffer_send(&dm.area1);
00621             else
00622                status = dm_buffer_send(&dm.area2);
00623          } else if (dm.area1.full)
00624             status = dm_buffer_send(&dm.area1);
00625          else if (dm.area2.full)
00626             status = dm_buffer_send(&dm.area2);
00627 
00628          if (status != CM_SUCCESS) {
00629             cm_msg(MERROR, "dm_task", "network error %i", status);
00630             goto kill;
00631          }
00632       } /* if DM_SEND */
00633       else if (dm.action == DM_FLUSH) {
00634          /* DM_FLUSH: User is waiting for completion (i.e. No more incomming
00635             events) Empty both area in order independently of being full or not */
00636          if (dm.area1.serial <= dm.area2.serial) {
00637             status = dm_buffer_send(&dm.area1);
00638             if (status != CM_SUCCESS)
00639                goto error;
00640             status = dm_buffer_send(&dm.area2);
00641             if (status != CM_SUCCESS)
00642                goto error;
00643          } else {
00644             status = dm_buffer_send(&dm.area2);
00645             if (status != CM_SUCCESS)
00646                goto error;
00647             status = dm_buffer_send(&dm.area1);
00648             if (status != CM_SUCCESS)
00649                goto error;
00650          }
00651          /* reset counter */
00652          dm.area1.serial = 0;
00653          dm.area2.serial = dm.serial = 1;
00654 #ifdef DM_DEBUG
00655          printf("dm.action: Flushing ...\n");
00656 #endif
00657          /* reset area to #1 */
00658          dm.pa = &dm.area1;
00659 
00660          /* release user */
00661          ss_semaphore_release(dm.sem_flush);
00662 #ifdef OS_WINNT
00663          /* necessary for true MUTEX (NT) get semaphore back */
00664          ss_semaphore_wait_for(dm.sem_flush, 0);
00665 #endif
00666       }
00667       /* if FLUSH */
00668       if (dm.action == DM_KILL)
00669          goto kill;
00670 
00671    }                            /* FOREVER (go back wainting for semaphore) */
00672 
00673    /* kill spawn now */
00674  error:
00675    cm_msg(MERROR, "dm_area_flush", "aSync Net error");
00676  kill:
00677    ss_semaphore_release(dm.sem_flush);
00678 #ifdef OS_WINNT
00679    ss_semaphore_wait_for(dm.sem_flush, 1);
00680 #endif
00681    cm_msg(MERROR, "areaSend", "task areaSend exiting now");
00682    exit;
00683    return 1;
00684 #else
00685    printf("DM_DUAL_THREAD not defined %p\n", pointer);
00686    return 0;
00687 #endif
00688 }
00689 
00690 /********************************************************************/
00691 INT dm_area_flush(void)
00692 /********************************************************************\
00693   Routine: dm_area_flush
00694 
00695   Purpose: Flush all the events in the areas.
00696            Used in mfe for BOR events, periodic events and
00697            if rate to low in main loop once a second. The standard
00698            data transfer should be done/triggered by dm_area_send (sync/async)
00699            in dm_pointer_get().
00700   Input:
00701     none
00702   Output:
00703     none
00704   Function value:
00705     CM_SUCCESS       Successful completion
00706     RPC_NET_ERROR    send error
00707 \********************************************************************/
00708 {
00709    INT status;
00710 #ifdef DM_DUAL_THREAD
00711    /* request FULL flush */
00712    dm.action = DM_FLUSH;
00713    ss_semaphore_release(dm.sem_send);
00714 #ifdef OS_WINNT
00715    /* necessary for true MUTEX (NT) get semaphore back */
00716    ss_semaphore_wait_for(dm.sem_send, 0);
00717 #endif
00718 
00719    /* important to wait for completion before continue with timeout
00720       timeout specified milliseconds */
00721    status = ss_semaphore_wait_for(dm.sem_flush, 10000);
00722 #ifdef DM_DEBUG
00723    printf("dm_area_flush after waiting %i\n", status);
00724 #endif
00725 #ifdef OS_WINNT
00726    ss_semaphore_release(dm.sem_flush);      /* give it back now */
00727 #endif
00728 
00729    return status;
00730 #else
00731    /* full flush done here */
00732    /* select in order both area independently of being full or not */
00733    if (dm.area1.serial <= dm.area2.serial) {
00734       status = dm_buffer_send(&dm.area1);
00735       if (status != CM_SUCCESS)
00736          return status;
00737       status = dm_buffer_send(&dm.area2);
00738       if (status != CM_SUCCESS)
00739          return status;
00740    } else {
00741       status = dm_buffer_send(&dm.area2);
00742       if (status != CM_SUCCESS)
00743          return status;
00744       status = dm_buffer_send(&dm.area1);
00745       if (status != CM_SUCCESS)
00746          return status;
00747    }
00748    /* reset serial counter */
00749    dm.area1.serial = dm.area2.serial = 0;
00750    dm.last_active = ss_millitime();
00751    return CM_SUCCESS;
00752 #endif
00753 }
00754 
00755 /**dox***************************************************************/
00756 #endif                          /* DOXYGEN_SHOULD_SKIP_THIS */
00757 
00758 /**dox***************************************************************/
00759                   /** @} *//* end of dmfunctionc */
00760 
00761 /***** sKIP eb_xxx **************************************************/
00762 /**dox***************************************************************/
00763 #ifndef DOXYGEN_SHOULD_SKIP_THIS
00764 /***** sKIP eb_xxx **************************************************/
00765 
00766 #if !defined(OS_VXWORKS)
00767 /********************************************************************\
00768 *                                                                    *
00769 *                 Event buffer functions                             *
00770 *                                                                    *
00771 \********************************************************************/
00772 
00773 /* PAA several modification in the eb_xxx()
00774    also new function eb_buffer_full()
00775 */
00776 static char *_event_ring_buffer = NULL;
00777 static INT _eb_size;
00778 static char *_eb_read_pointer, *_eb_write_pointer, *_eb_end_pointer;
00779 
00780 /********************************************************************/
00781 INT eb_create_buffer(INT size)
00782 /********************************************************************\
00783 
00784   Routine: eb_create_buffer
00785 
00786   Purpose: Create an event buffer. Has to be called initially before
00787            any other eb_xxx function
00788 
00789   Input:
00790     INT    size             Size in bytes
00791 
00792   Output:
00793     none
00794 
00795   Function value:
00796     CM_SUCCESS              Successful completion
00797     BM_NO_MEMEORY           Out of memory
00798 
00799 \********************************************************************/
00800 {
00801    _event_ring_buffer = (char *) M_MALLOC(size);
00802    if (_event_ring_buffer == NULL)
00803       return BM_NO_MEMORY;
00804 
00805    memset(_event_ring_buffer, 0, size);
00806    _eb_size = size;
00807 
00808    _eb_write_pointer = _eb_read_pointer = _eb_end_pointer = _event_ring_buffer;
00809 
00810    _send_sock = rpc_get_event_sock();
00811 
00812    return CM_SUCCESS;
00813 }
00814 
00815 /********************************************************************/
00816 INT eb_free_buffer()
00817 /********************************************************************\
00818 
00819   Routine: eb_free_buffer
00820 
00821   Purpose: Free memory allocated voa eb_create_buffer
00822 
00823   Input:
00824     none
00825 
00826   Output:
00827     none
00828 
00829   Function value:
00830     CM_SUCCESS              Successful completion
00831 
00832 \********************************************************************/
00833 {
00834    if (_event_ring_buffer)
00835       M_FREE(_event_ring_buffer);
00836 
00837    _eb_size = 0;
00838    return CM_SUCCESS;
00839 }
00840 
00841 
00842 /********************************************************************/
00843 INT eb_free_space(void)
00844 /********************************************************************\
00845 
00846   Routine: eb_free_space
00847 
00848   Purpose: Compute and return usable free space in the event buffer
00849 
00850   Input:
00851     none
00852 
00853   Output:
00854     none
00855 
00856   Function value:
00857     INT    Number of usable free bytes in the event buffer
00858 
00859 \********************************************************************/
00860 {
00861    INT free_space;
00862 
00863    if (_event_ring_buffer == NULL) {
00864       cm_msg(MERROR, "eb_get_pointer", "please call eb_create_buffer first");
00865       return -1;
00866    }
00867 
00868    if (_eb_write_pointer >= _eb_read_pointer) {
00869       free_space = _eb_size - ((POINTER_T) _eb_write_pointer - (POINTER_T) _event_ring_buffer);
00870    } else if (_eb_write_pointer >= _event_ring_buffer) {
00871       free_space = (POINTER_T) _eb_read_pointer - (POINTER_T) _eb_write_pointer;
00872    } else if (_eb_end_pointer == _event_ring_buffer) {
00873       _eb_write_pointer = _event_ring_buffer;
00874       free_space = _eb_size;
00875    } else if (_eb_read_pointer == _event_ring_buffer) {
00876       free_space = 0;
00877    } else {
00878       _eb_write_pointer = _event_ring_buffer;
00879       free_space = (POINTER_T) _eb_read_pointer - (POINTER_T) _eb_write_pointer;
00880    }
00881 
00882    return free_space;
00883 }
00884 
00885 
00886 /********************************************************************/
00887 DWORD eb_get_level()
00888 /********************************************************************\
00889 
00890   Routine: eb_get_level
00891 
00892   Purpose: Return filling level of event buffer in percent
00893 
00894   Input:
00895     none
00896 
00897   Output:
00898     none
00899 
00900   Function value:
00901     DWORD level              0..99
00902 
00903 \********************************************************************/
00904 {
00905    INT size;
00906 
00907    size = _eb_size - eb_free_space();
00908 
00909    return (100 * size) / _eb_size;
00910 }
00911 
00912 
00913 /********************************************************************/
00914 BOOL eb_buffer_full(void)
00915 /********************************************************************\
00916 
00917   Routine: eb_buffer_full
00918 
00919   Purpose: Test if there is sufficient space in the event buffer
00920     for another event
00921 
00922   Input:
00923     none
00924 
00925   Output:
00926     none
00927 
00928   Function value:
00929     BOOL  Is there enough space for another event in the event buffer
00930 
00931 \********************************************************************/
00932 {
00933    DWORD free_space;
00934 
00935    free_space = eb_free_space();
00936 
00937    /* if max. event won't fit, return zero */
00938    return (free_space < MAX_EVENT_SIZE + sizeof(EVENT_HEADER) + sizeof(INT));
00939 }
00940 
00941 
00942 /********************************************************************/
00943 EVENT_HEADER *eb_get_pointer()
00944 /********************************************************************\
00945 
00946   Routine: eb_get_pointer
00947 
00948   Purpose: Get pointer to next free location in event buffer
00949 
00950   Input:
00951     none
00952 
00953   Output:
00954     none
00955 
00956   Function value:
00957     EVENT_HEADER *            Pointer to free location
00958 
00959 \********************************************************************/
00960 {
00961    /* if max. event won't fit, return zero */
00962    if (eb_buffer_full()) {
00963 #ifdef OS_VXWORKS
00964       logMsg("eb_get_pointer(): Event won't fit: read=%d, write=%d, end=%d\n",
00965              _eb_read_pointer - _event_ring_buffer,
00966              _eb_write_pointer - _event_ring_buffer, _eb_end_pointer - _event_ring_buffer, 0, 0, 0);
00967 #endif
00968       return NULL;
00969    }
00970 
00971    /* leave space for buffer handle */
00972    return (EVENT_HEADER *) (_eb_write_pointer + sizeof(INT));
00973 }
00974 
00975 
00976 /********************************************************************/
00977 INT eb_increment_pointer(INT buffer_handle, INT event_size)
00978 /********************************************************************\
00979 
00980   Routine: eb_increment_pointer
00981 
00982   Purpose: Increment write pointer of event buffer after an event
00983            has been copied into the buffer (at an address previously
00984            obtained via eb_get_pointer)
00985 
00986   Input:
00987     INT buffer_handle         Buffer handle event should be sent to
00988     INT event_size            Event size in bytes including header
00989 
00990   Output:
00991     none
00992 
00993   Function value:
00994     CM_SUCCESS                Successful completion
00995 
00996 \********************************************************************/
00997 {
00998    INT aligned_event_size;
00999 
01000    /* if not connected remotely, use bm_send_event */
01001    if (_send_sock == 0)
01002       return bm_send_event(buffer_handle, _eb_write_pointer + sizeof(INT), event_size, SYNC);
01003 
01004    aligned_event_size = ALIGN8(event_size);
01005 
01006    /* copy buffer handle */
01007    *((INT *) _eb_write_pointer) = buffer_handle;
01008    _eb_write_pointer += sizeof(INT) + aligned_event_size;
01009 
01010    if (_eb_write_pointer > _eb_end_pointer)
01011       _eb_end_pointer = _eb_write_pointer;
01012 
01013    if (_eb_write_pointer > _event_ring_buffer + _eb_size)
01014       cm_msg(MERROR, "eb_increment_pointer",
01015              "event size (%d) exceeds maximum event size (%d)", event_size, MAX_EVENT_SIZE);
01016 
01017    if (_eb_size - ((POINTER_T) _eb_write_pointer - (POINTER_T) _event_ring_buffer) <
01018        (int) (MAX_EVENT_SIZE + sizeof(EVENT_HEADER) + sizeof(INT))) {
01019       _eb_write_pointer = _event_ring_buffer;
01020 
01021       /* avoid rp==wp */
01022       if (_eb_read_pointer == _event_ring_buffer)
01023          _eb_write_pointer--;
01024    }
01025 
01026    return CM_SUCCESS;
01027 }
01028 
01029 
01030 /********************************************************************/
01031 INT eb_send_events(BOOL send_all)
01032 /********************************************************************\
01033 
01034   Routine: eb_send_events
01035 
01036   Purpose: Send events from the event buffer to the server
01037 
01038   Input:
01039     BOOL send_all             If FALSE, only send events if buffer
01040                               contains more than _opt_tcp_size bytes
01041 
01042   Output:
01043     none
01044 
01045   Function value:
01046     CM_SUCCESS                Successful completion
01047 
01048 \********************************************************************/
01049 {
01050    char *eb_wp, *eb_ep;
01051    INT size, i;
01052    INT opt_tcp_size = rpc_get_opt_tcp_size();
01053 
01054    /* write pointers are volatile, so make copy */
01055    eb_ep = _eb_end_pointer;
01056    eb_wp = _eb_write_pointer;
01057 
01058    if (eb_wp == _eb_read_pointer)
01059       return CM_SUCCESS;
01060    if (eb_wp > _eb_read_pointer) {
01061       size = (POINTER_T) eb_wp - (POINTER_T) _eb_read_pointer;
01062 
01063       /* don't send if less than optimal TCP buffer size available */
01064       if (size < opt_tcp_size && !send_all)
01065          return CM_SUCCESS;
01066    } else {
01067       /* send last piece of event buffer */
01068       size = (POINTER_T) eb_ep - (POINTER_T) _eb_read_pointer;
01069    }
01070 
01071    while (size > opt_tcp_size) {
01072       /* send buffer */
01073       i = send_tcp(_send_sock, _eb_read_pointer, opt_tcp_size, 0);
01074       if (i < 0) {
01075          printf("send_tcp() returned %d\n", i);
01076          cm_msg(MERROR, "eb_send_events", "send_tcp() failed");
01077          return RPC_NET_ERROR;
01078       }
01079 
01080       _eb_read_pointer += opt_tcp_size;
01081       if (_eb_read_pointer == eb_ep && eb_wp < eb_ep)
01082          _eb_read_pointer = _eb_end_pointer = _event_ring_buffer;
01083 
01084       size -= opt_tcp_size;
01085    }
01086 
01087    if (send_all || eb_wp < _eb_read_pointer) {
01088       /* send buffer */
01089       i = send_tcp(_send_sock, _eb_read_pointer, size, 0);
01090       if (i < 0) {
01091          printf("send_tcp() returned %d\n", i);
01092          cm_msg(MERROR, "eb_send_events", "send_tcp() failed");
01093          return RPC_NET_ERROR;
01094       }
01095 
01096       _eb_read_pointer += size;
01097       if (_eb_read_pointer == eb_ep && eb_wp < eb_ep)
01098          _eb_read_pointer = _eb_end_pointer = _event_ring_buffer;
01099    }
01100 
01101    /* Check for case where eb_wp = eb_ring_buffer - 1 */
01102    if (eb_wp < _event_ring_buffer && _eb_end_pointer == _event_ring_buffer) {
01103       return CM_SUCCESS;
01104    }
01105 
01106    if (eb_wp != _eb_read_pointer)
01107       return BM_MORE_EVENTS;
01108 
01109    return CM_SUCCESS;
01110 }
01111 
01112 #endif                          /* OS_VXWORKS  eb section */
01113 
01114 /**dox***************************************************************/
01115 #endif                          /* DOXYGEN_SHOULD_SKIP_THIS */
01116 
01117 /**dox***************************************************************/
01118                   /** @} *//* end of midasincludecode */

Midas DOC Version 3.0.0 ---- PSI Stefan Ritt ----
Contributions: Pierre-Andre Amaudruz - Sergio Ballestrero - Suzannah Daviel - Doxygen - Peter Green - Qing Gu - Greg Hackman - Gertjan Hofman - Paul Knowles - Exaos Lee - Rudi Meier - Glenn Moloney - Dave Morris - John M O'Donnell - Konstantin Olchanski - Renee Poutissou - Tamsen Schurman - Andreas Suter - Jan M.Wouters - Piotr Adam Zolnierczuk