Midas Buffer Manager Functions (bm_xxx)
[The midas.h & midas.c]


Functions

INT bm_match_event (short int event_id, short int trigger_mask, EVENT_HEADER *pevent)
void bm_remove_client_locked (BUFFER_HEADER *pheader, int j)
static void bm_cleanup (const char *who, DWORD actual_time, BOOL wrong_interval)
INT bm_open_buffer (char *buffer_name, INT buffer_size, INT *buffer_handle)
INT bm_close_buffer (INT buffer_handle)
INT bm_close_all_buffers (void)
INT bm_set_cache_size (INT buffer_handle, INT read_size, INT write_size)
INT bm_compose_event (EVENT_HEADER *event_header, short int event_id, short int trigger_mask, DWORD size, DWORD serial)
INT bm_request_event (HNDLE buffer_handle, short int event_id, short int trigger_mask, INT sampling_type, HNDLE *request_id, void(*func)(HNDLE, HNDLE, EVENT_HEADER *, void *))
INT bm_remove_event_request (INT buffer_handle, INT request_id)
INT bm_delete_request (INT request_id)
static void bm_validate_client_pointers (BUFFER_HEADER *pheader, BUFFER_CLIENT *pclient)
static BOOL bm_update_read_pointer (const char *caller_name, BUFFER_HEADER *pheader)
static void bm_wakeup_producers (const BUFFER_HEADER *pheader, const BUFFER_CLIENT *pc)
static void bm_dispatch_event (int buffer_handle, EVENT_HEADER *pevent)
static void bm_dispatch_from_cache (BUFFER *pbuf, int buffer_handle)
static void bm_convert_event_header (EVENT_HEADER *pevent, int convert_flags)
static int bm_copy_from_cache (BUFFER *pbuf, void *destination, int max_size, int *buf_size, int convert_flags)
static int bm_read_cache_has_events (const BUFFER *pbuf)
static int bm_wait_for_free_space (int buffer_handle, BUFFER *pbuf, int async_flag, int requested_space)
INT bm_send_event (INT buffer_handle, void *source, INT buf_size, INT async_flag)
INT bm_flush_cache (INT buffer_handle, INT async_flag)
INT bm_receive_event (INT buffer_handle, void *destination, INT *buf_size, INT async_flag)
INT bm_skip_event (INT buffer_handle)
INT bm_push_event (char *buffer_name)
INT bm_check_buffers ()
INT bm_empty_buffers ()


Function Documentation

INT bm_check_buffers (  ) 

Check if any requested event is waiting in a buffer

Returns:
TRUE More events are waiting
FALSE No more events are waiting

Definition at line 7305 of file midas.c.

Referenced by cm_yield().

07306 {
07307 #ifdef LOCAL_ROUTINES
07308    {
07309       INT idx, status = 0;
07310       INT server_type, server_conn, tid;
07311       BOOL bMore;
07312       DWORD start_time;
07313 
07314       server_type = rpc_get_server_option(RPC_OSERVER_TYPE);
07315       server_conn = rpc_get_server_acception();
07316       tid = ss_gettid();
07317 
07318       /* if running as a server, buffer checking is done by client
07319          via ASYNC bm_receive_event */
07320       if (server_type == ST_SUBPROCESS || server_type == ST_MTHREAD)
07321          return FALSE;
07322 
07323       bMore = FALSE;
07324       start_time = ss_millitime();
07325 
07326       /* go through all buffers */
07327       for (idx = 0; idx < _buffer_entries; idx++) {
07328          if (server_type == ST_SINGLE && _buffer[idx].index != server_conn)
07329             continue;
07330 
07331          if (server_type != ST_SINGLE && _buffer[idx].index != tid)
07332             continue;
07333 
07334          if (!_buffer[idx].attached)
07335             continue;
07336 
07337          do {
07338 
07339             /* one bm_push_event could cause a run stop and a buffer close, which
07340                would crash the next call to bm_push_event(). So check for valid
07341                buffer on each call */
07342             if (idx < _buffer_entries && _buffer[idx].buffer_header->name != NULL)
07343                status = bm_push_event(_buffer[idx].buffer_header->name);
07344 
07345             if (status != BM_MORE_EVENTS)
07346                break;
07347 
07348             /* stop after one second */
07349             if (ss_millitime() - start_time > 1000) {
07350                bMore = TRUE;
07351                break;
07352             }
07353 
07354          } while (TRUE);
07355       }
07356 
07357       return bMore;
07358 
07359    }
07360 #else                           /* LOCAL_ROUTINES */
07361 
07362    return FALSE;
07363 
07364 #endif
07365 }

static void bm_cleanup ( const char *  who,
DWORD  actual_time,
BOOL  wrong_interval 
) [static]

Check all clients on all buffers, remove invalid clients

Definition at line 4189 of file midas.c.

Referenced by bm_open_buffer().

04190 {
04191    BUFFER_HEADER *pheader;
04192    BUFFER_CLIENT *pbclient;
04193    int i, j;
04194    char str[256];
04195 
04196    /* check buffers */
04197    for (i = 0; i < _buffer_entries; i++)
04198       if (_buffer[i].attached) {
04199          /* update the last_activity entry to show that we are alive */
04200          pheader = _buffer[i].buffer_header;
04201          pbclient = pheader->client;
04202          pbclient[bm_validate_client_index(&_buffer[i])].last_activity = actual_time;
04203 
04204          /* don't check other clients if interval is stange */
04205          if (wrong_interval)
04206             continue;
04207 
04208          /* now check other clients */
04209          for (j = 0; j < pheader->max_client_index; j++, pbclient++) {
04210 
04211 #ifdef OS_UNIX
04212 #ifdef ESRCH
04213             if (pbclient->pid) {
04214                errno = 0;
04215                kill(pbclient->pid, 0);
04216                if (errno == ESRCH) {
04217                   cm_msg(MINFO, "bm_cleanup",
04218                          "Client \'%s\' on buffer \'%s\' removed by %s because client pid %d does not exist",
04219                          pbclient->name, pheader->name, who, pbclient->pid);
04220 
04221                   bm_lock_buffer(i + 1);
04222                   bm_remove_client_locked(pheader, j);
04223                   bm_unlock_buffer(i + 1);
04224                   continue;
04225                }
04226             }
04227 #endif
04228 #endif
04229 
04230             /* If client process has no activity, clear its buffer entry. */
04231             if (pbclient->pid && pbclient->watchdog_timeout > 0 &&
04232                 actual_time > pbclient->last_activity &&
04233                 actual_time - pbclient->last_activity > pbclient->watchdog_timeout) {
04234                bm_lock_buffer(i + 1);
04235                str[0] = 0;
04236 
04237                /* now make again the check with the buffer locked */
04238                actual_time = ss_millitime();
04239                if (pbclient->pid && pbclient->watchdog_timeout > 0 &&
04240                    actual_time > pbclient->last_activity &&
04241                    actual_time - pbclient->last_activity > pbclient->watchdog_timeout) {
04242                   sprintf(str,
04243                           "Client \'%s\' on buffer \'%s\' removed by %s (idle %1.1lfs,TO %1.0lfs)",
04244                           pbclient->name, pheader->name, who,
04245                           (actual_time - pbclient->last_activity) / 1000.0,
04246                           pbclient->watchdog_timeout / 1000.0);
04247 
04248                   bm_remove_client_locked(pheader, j);
04249                }
04250 
04251                bm_unlock_buffer(i + 1);
04252 
04253                /* display info message after unlocking buffer */
04254                if (str[0])
04255                   cm_msg(MINFO, "bm_cleanup", str);
04256             }
04257          }
04258       }
04259 }

INT bm_close_all_buffers ( void   ) 

Close all open buffers

Returns:
BM_SUCCESS

Definition at line 4649 of file midas.c.

Referenced by cm_disconnect_experiment(), cm_set_client_info(), and rpc_server_dispatch().

04650 {
04651    if (rpc_is_remote())
04652       return rpc_call(RPC_BM_CLOSE_ALL_BUFFERS);
04653 
04654 #ifdef LOCAL_ROUTINES
04655    {
04656       INT i;
04657 
04658       for (i = _buffer_entries; i > 0; i--)
04659          bm_close_buffer(i);
04660    }
04661 #endif                          /* LOCAL_ROUTINES */
04662 
04663    return BM_SUCCESS;
04664 }

INT bm_close_buffer ( INT  buffer_handle  ) 

Closes an event buffer previously opened with bm_open_buffer().

Parameters:
buffer_handle buffer handle
Returns:
BM_SUCCESS, BM_INVALID_HANDLE

Definition at line 4533 of file midas.c.

Referenced by bm_close_all_buffers(), close_buffers(), command_loop(), rpc_server_dispatch(), source_unbooking(), and tr_stop().

04534 {
04535    if (rpc_is_remote())
04536       return rpc_call(RPC_BM_CLOSE_BUFFER, buffer_handle);
04537 
04538 #ifdef LOCAL_ROUTINES
04539    {
04540       BUFFER_CLIENT *pclient;
04541       BUFFER_HEADER *pheader;
04542       INT i, j, idx, destroy_flag;
04543 
04544       if (buffer_handle > _buffer_entries || buffer_handle <= 0) {
04545          cm_msg(MERROR, "bm_close_buffer", "invalid buffer handle %d", buffer_handle);
04546          return BM_INVALID_HANDLE;
04547       }
04548 
04549       /* check if buffer got already closed */
04550       if (!_buffer[buffer_handle - 1].attached) {
04551          return BM_SUCCESS;
04552       }
04553 
04554       /*
04555          Check if buffer was opened by current thread. This is necessary
04556          in the server process where one thread may not close the buffer
04557          of other threads.
04558        */
04559 
04560       idx = bm_validate_client_index(&_buffer[buffer_handle - 1]);
04561       pheader = _buffer[buffer_handle - 1].buffer_header;
04562 
04563       if (rpc_get_server_option(RPC_OSERVER_TYPE) == ST_SINGLE &&
04564           _buffer[buffer_handle - 1].index != rpc_get_server_acception())
04565          return BM_INVALID_HANDLE;
04566 
04567       if (rpc_get_server_option(RPC_OSERVER_TYPE) != ST_SINGLE
04568           && _buffer[buffer_handle - 1].index != ss_gettid())
04569          return BM_INVALID_HANDLE;
04570 
04571       if (!_buffer[buffer_handle - 1].attached) {
04572          /* don't produce error, since bm_close_all_buffers() might want to close an
04573             already closed buffer */
04574          return BM_SUCCESS;
04575       }
04576 
04577       /* delete all requests for this buffer */
04578       for (i = 0; i < _request_list_entries; i++)
04579          if (_request_list[i].buffer_handle == buffer_handle)
04580             bm_delete_request(i);
04581 
04582       /* first lock buffer */
04583       bm_lock_buffer(buffer_handle);
04584 
04585       /* mark entry in _buffer as empty */
04586       _buffer[buffer_handle - 1].attached = FALSE;
04587 
04588       /* clear entry from client structure in buffer header */
04589       memset(&(pheader->client[idx]), 0, sizeof(BUFFER_CLIENT));
04590 
04591       /* calculate new max_client_index entry */
04592       for (i = MAX_CLIENTS - 1; i >= 0; i--)
04593          if (pheader->client[i].pid != 0)
04594             break;
04595       pheader->max_client_index = i + 1;
04596 
04597       /* count new number of clients */
04598       for (i = MAX_CLIENTS - 1, j = 0; i >= 0; i--)
04599          if (pheader->client[i].pid != 0)
04600             j++;
04601       pheader->num_clients = j;
04602 
04603       destroy_flag = (pheader->num_clients == 0);
04604 
04605       /* free cache */
04606       if (_buffer[buffer_handle - 1].read_cache_size > 0)
04607          M_FREE(_buffer[buffer_handle - 1].read_cache);
04608       if (_buffer[buffer_handle - 1].write_cache_size > 0)
04609          M_FREE(_buffer[buffer_handle - 1].write_cache);
04610 
04611       /* check if anyone is waiting and wake him up */
04612       pclient = pheader->client;
04613 
04614       for (i = 0; i < pheader->max_client_index; i++, pclient++)
04615          if (pclient->pid && (pclient->write_wait || pclient->read_wait))
04616             ss_resume(pclient->port, "B  ");
04617 
04618       /* unmap shared memory, delete it if we are the last */
04619       ss_shm_close(pheader->name, _buffer[buffer_handle - 1].buffer_header,
04620                    _buffer[buffer_handle - 1].shm_handle, destroy_flag);
04621 
04622       /* unlock buffer */
04623       bm_unlock_buffer(buffer_handle);
04624 
04625       /* delete semaphore */
04626       ss_semaphore_delete(_buffer[buffer_handle - 1].semaphore, destroy_flag);
04627 
04628       /* update _buffer_entries */
04629       if (buffer_handle == _buffer_entries)
04630          _buffer_entries--;
04631 
04632       if (_buffer_entries > 0)
04633          _buffer = (BUFFER *) realloc(_buffer, sizeof(BUFFER) * (_buffer_entries));
04634       else {
04635          M_FREE(_buffer);
04636          _buffer = NULL;
04637       }
04638    }
04639 #endif                          /* LOCAL_ROUTINES */
04640 
04641    return BM_SUCCESS;
04642 }

INT bm_compose_event ( EVENT_HEADER event_header,
short int  event_id,
short int  trigger_mask,
DWORD  size,
DWORD  serial 
)

Compose a Midas event header. An event header can usually be set-up manually or through this routine. If the data size of the event is not known when the header is composed, it can be set later with event_header->data-size = <...> Following structure is created at the beginning of an event

typedef struct {
 short int     event_id;
 short int     trigger_mask;
 DWORD         serial_number;
 DWORD         time_stamp;
 DWORD         data_size;
} EVENT_HEADER;

char event[1000];
 bm_compose_event((EVENT_HEADER *)event, 1, 0, 100, 1);
 *(event+sizeof(EVENT_HEADER)) = <...>
Parameters:
event_header pointer to the event header
event_id event ID of the event
trigger_mask trigger mask of the event
size size if the data part of the event in bytes
serial serial number
Returns:
BM_SUCCESS

Definition at line 5556 of file midas.c.

Referenced by cm_msg(), cm_msg1(), and log_odb_dump().

05558 {
05559    event_header->event_id = event_id;
05560    event_header->trigger_mask = trigger_mask;
05561    event_header->data_size = size;
05562    event_header->time_stamp = ss_time();
05563    event_header->serial_number = serial;
05564 
05565    return BM_SUCCESS;
05566 }

static void bm_convert_event_header ( EVENT_HEADER pevent,
int  convert_flags 
) [static]

Definition at line 6071 of file midas.c.

Referenced by bm_copy_from_cache().

06072 {
06073    /* now convert event header */
06074    if (convert_flags) {
06075       rpc_convert_single(&pevent->event_id, TID_SHORT, RPC_OUTGOING, convert_flags);
06076       rpc_convert_single(&pevent->trigger_mask, TID_SHORT, RPC_OUTGOING, convert_flags);
06077       rpc_convert_single(&pevent->serial_number, TID_DWORD, RPC_OUTGOING, convert_flags);
06078       rpc_convert_single(&pevent->time_stamp, TID_DWORD, RPC_OUTGOING, convert_flags);
06079       rpc_convert_single(&pevent->data_size, TID_DWORD, RPC_OUTGOING, convert_flags);
06080    }
06081 }

static int bm_copy_from_cache ( BUFFER pbuf,
void *  destination,
int  max_size,
int *  buf_size,
int  convert_flags 
) [static]

Definition at line 6083 of file midas.c.

Referenced by bm_receive_event().

06085 {
06086    int status;
06087    EVENT_HEADER *pevent;
06088    int size;
06089 
06090    pevent = (EVENT_HEADER *) (pbuf->read_cache + pbuf->read_cache_rp);
06091    size = pevent->data_size + sizeof(EVENT_HEADER);
06092 
06093    if (size > max_size) {
06094       memcpy(destination, pevent, max_size);
06095       cm_msg(MERROR, "bm_receive_event", "event size %d larger than buffer size %d", size, max_size);
06096       *buf_size = max_size;
06097       status = BM_TRUNCATED;
06098    } else {
06099       memcpy(destination, pevent, size);
06100       *buf_size = size;
06101       status = BM_SUCCESS;
06102    }
06103 
06104    bm_convert_event_header((EVENT_HEADER *) destination, convert_flags);
06105 
06106    /* correct size for DWORD boundary */
06107    size = ALIGN8(size);
06108 
06109    pbuf->read_cache_rp += size;
06110 
06111    if (pbuf->read_cache_rp == pbuf->read_cache_wp)
06112       pbuf->read_cache_rp = pbuf->read_cache_wp = 0;
06113 
06114    return status;
06115 }

INT bm_delete_request ( INT  request_id  ) 

Deletes an event request previously done with bm_request_event(). When an event request gets deleted, events of that requested type are not received any more. When a buffer is closed via bm_close_buffer(), all event requests from that buffer are deleted automatically

Parameters:
request_id request identifier given by bm_request_event()
Returns:
BM_SUCCESS, BM_INVALID_HANDLE

Definition at line 5855 of file midas.c.

Referenced by bm_close_buffer(), close_buffers(), source_unbooking(), tr_stop(), and update_request().

05856 {
05857    if (request_id < 0 || request_id >= _request_list_entries)
05858       return BM_INVALID_HANDLE;
05859 
05860    /* remove request entry from buffer */
05861    bm_remove_event_request(_request_list[request_id].buffer_handle, request_id);
05862 
05863    memset(&_request_list[request_id], 0, sizeof(REQUEST_LIST));
05864 
05865    return BM_SUCCESS;
05866 }

static void bm_dispatch_event ( int  buffer_handle,
EVENT_HEADER pevent 
) [static]

Definition at line 6035 of file midas.c.

Referenced by bm_dispatch_from_cache().

06036 {
06037    int i;
06038 
06039    /* call dispatcher */
06040    for (i = 0; i < _request_list_entries; i++)
06041       if (_request_list[i].buffer_handle == buffer_handle &&
06042           bm_match_event(_request_list[i].event_id, _request_list[i].trigger_mask, pevent)) {
06043          /* if event is fragmented, call defragmenter */
06044          if ((pevent->event_id & 0xF000) == EVENTID_FRAG1 || (pevent->event_id & 0xF000) == EVENTID_FRAG)
06045             bm_defragment_event(buffer_handle, i, pevent, (void *) (pevent + 1), _request_list[i].dispatcher);
06046          else
06047             _request_list[i].dispatcher(buffer_handle, i, pevent, (void *) (pevent + 1));
06048       }
06049 }

static void bm_dispatch_from_cache ( BUFFER pbuf,
int  buffer_handle 
) [static]

Definition at line 6051 of file midas.c.

Referenced by bm_push_event().

06052 {
06053    EVENT_HEADER *pevent;
06054    int size;
06055 
06056    pevent = (EVENT_HEADER *) (pbuf->read_cache + pbuf->read_cache_rp);
06057    size = pevent->data_size + sizeof(EVENT_HEADER);
06058 
06059    /* correct size for DWORD boundary */
06060    size = ALIGN8(size);
06061 
06062    /* increment read pointer */
06063    pbuf->read_cache_rp += size;
06064 
06065    if (pbuf->read_cache_rp == pbuf->read_cache_wp)
06066       pbuf->read_cache_rp = pbuf->read_cache_wp = 0;
06067 
06068    bm_dispatch_event(buffer_handle, pevent);
06069 }

INT bm_empty_buffers (  ) 

Clears event buffer and cache. If an event buffer is large and a consumer is slow in analyzing events, events are usually received some time after they are produced. This effect is even more experienced if a read cache is used (via bm_set_cache_size()). When changes to the hardware are made in the experience, the consumer will then still analyze old events before any new event which reflects the hardware change. Users can be fooled by looking at histograms which reflect the hardware change many seconds after they have been made.

To overcome this potential problem, the analyzer can call bm_empty_buffers() just after the hardware change has been made which skips all old events contained in event buffers and read caches. Technically this is done by forwarding the read pointer of the client. No events are really deleted, they are still visible to other clients like the logger.

Note that the front-end also contains write buffers which can delay the delivery of events. The standard front-end framework mfe.c reduces this effect by flushing all buffers once every second.

Returns:
BM_SUCCESS

Definition at line 7632 of file midas.c.

Referenced by rpc_server_dispatch(), and source_unbooking().

07633 {
07634    if (rpc_is_remote())
07635       return rpc_call(RPC_BM_EMPTY_BUFFERS);
07636 
07637 #ifdef LOCAL_ROUTINES
07638    {
07639       INT idx, server_type, server_conn, tid;
07640       BUFFER *pbuf;
07641       BUFFER_CLIENT *pclient;
07642 
07643       server_type = rpc_get_server_option(RPC_OSERVER_TYPE);
07644       server_conn = rpc_get_server_acception();
07645       tid = ss_gettid();
07646 
07647       /* go through all buffers */
07648       for (idx = 0; idx < _buffer_entries; idx++) {
07649          if (server_type == ST_SINGLE && _buffer[idx].index != server_conn)
07650             continue;
07651 
07652          if (server_type != ST_SINGLE && _buffer[idx].index != tid)
07653             continue;
07654 
07655          if (!_buffer[idx].attached)
07656             continue;
07657 
07658          pbuf = &_buffer[idx];
07659 
07660          /* empty cache */
07661          pbuf->read_cache_rp = pbuf->read_cache_wp = 0;
07662 
07663          /* set read pointer to write pointer */
07664          pclient = (pbuf->buffer_header)->client + bm_validate_client_index(pbuf);
07665          bm_lock_buffer(idx + 1);
07666          pclient->read_pointer = (pbuf->buffer_header)->write_pointer;
07667          bm_unlock_buffer(idx + 1);
07668       }
07669 
07670    }
07671 #endif                          /* LOCAL_ROUTINES */
07672 
07673    return BM_SUCCESS;
07674 }

INT bm_flush_cache ( INT  buffer_handle,
INT  async_flag 
)

Empty write cache. This function should be used if events in the write cache should be visible to the consumers immediately. It should be called at the end of each run, otherwise events could be kept in the write buffer and will flow to the data of the next run.

Parameters:
buffer_handle Buffer handle obtained via bm_open_buffer()
async_flag Synchronous/asynchronous flag. If FALSE, the function blocks if the buffer has not enough free space to receive the full cache. If TRUE, the function returns immediately with a value of BM_ASYNC_RETURN without writing the cache.
Returns:
BM_SUCCESS, BM_INVALID_HANDLE
BM_ASYNC_RETURN Routine called with async_flag == TRUE and buffer has not enough space to receive cache
BM_NO_MEMORY Event is too large for network buffer or event buffer. One has to increase MAX_EVENT_SIZE in midas.h and recompile.

Definition at line 6542 of file midas.c.

Referenced by bm_send_event(), rpc_server_dispatch(), scan_fragment(), send_event(), and tr_stop().

06543 {
06544    if (rpc_is_remote())
06545       return rpc_call(RPC_BM_FLUSH_CACHE, buffer_handle, async_flag);
06546 
06547 #ifdef LOCAL_ROUTINES
06548    {
06549       BUFFER *pbuf;
06550       BUFFER_HEADER *pheader;
06551       BUFFER_CLIENT *pclient;
06552       EVENT_HEADER *pevent;
06553       INT i, size, total_size, status;
06554       INT my_client_index;
06555       INT old_write_pointer;
06556       char *pdata;
06557 
06558       pbuf = &_buffer[buffer_handle - 1];
06559 
06560       if (buffer_handle > _buffer_entries || buffer_handle <= 0) {
06561          cm_msg(MERROR, "bm_flush_cache", "invalid buffer handle %d", buffer_handle);
06562          return BM_INVALID_HANDLE;
06563       }
06564 
06565       if (!pbuf->attached) {
06566          cm_msg(MERROR, "bm_flush_cache", "invalid buffer handle %d", buffer_handle);
06567          return BM_INVALID_HANDLE;
06568       }
06569 
06570       if (pbuf->write_cache_size == 0)
06571          return BM_SUCCESS;
06572 
06573       /* check if anything needs to be flushed */
06574       if (pbuf->write_cache_rp == pbuf->write_cache_wp)
06575          return BM_SUCCESS;
06576 
06577       /* calculate some shorthands */
06578       pheader = _buffer[buffer_handle - 1].buffer_header;
06579       pdata = (char *) (pheader + 1);
06580       my_client_index = bm_validate_client_index(pbuf);
06581       pclient = pheader->client;
06582       pevent = (EVENT_HEADER *) (pbuf->write_cache + pbuf->write_cache_rp);
06583 
06584       /* lock the buffer */
06585       bm_lock_buffer(buffer_handle);
06586 
06587 #ifdef DEBUG_MSG
06588       cm_msg(MDEBUG, "bm_flush_cache initial: rp=%d, wp=%d", pheader->read_pointer, pheader->write_pointer);
06589 #endif
06590 
06591       status = bm_wait_for_free_space(buffer_handle, pbuf, async_flag, pbuf->write_cache_wp);
06592       if (status != BM_SUCCESS) {
06593          bm_unlock_buffer(buffer_handle);
06594          return status;
06595       }
06596 
06597       /* we have space, so let's copy the event */
06598       old_write_pointer = pheader->write_pointer;
06599 
06600 #ifdef DEBUG_MSG
06601       cm_msg(MDEBUG, "bm_flush_cache: found space rp=%d, wp=%d", pheader->read_pointer,
06602              pheader->write_pointer);
06603 #endif
06604 
06605       while (pbuf->write_cache_rp < pbuf->write_cache_wp) {
06606          /* loop over all events in cache */
06607 
06608          assert(pbuf->write_cache_rp >= 0);
06609          assert(pbuf->write_cache_rp < pbuf->write_cache_size);
06610 
06611          pevent = (EVENT_HEADER *) (pbuf->write_cache + pbuf->write_cache_rp);
06612          total_size = pevent->data_size + sizeof(EVENT_HEADER);
06613 
06614          assert(total_size > 0);
06615          assert(total_size <= pheader->size);
06616 
06617          /* correct size for DWORD boundary */
06618          total_size = ALIGN8(total_size);
06619 
06620          if (pheader->write_pointer + total_size <= pheader->size) {
06621             memcpy(pdata + pheader->write_pointer, pevent, total_size);
06622             pheader->write_pointer = (pheader->write_pointer + total_size) % pheader->size;
06623             if (pheader->write_pointer > pheader->size - (int) sizeof(EVENT_HEADER))
06624                pheader->write_pointer = 0;
06625          } else {
06626             /* split event */
06627             size = pheader->size - pheader->write_pointer;
06628 
06629             memcpy(pdata + pheader->write_pointer, pevent, size);
06630             memcpy(pdata, (char *) pevent + size, total_size - size);
06631 
06632             pheader->write_pointer = total_size - size;
06633          }
06634 
06635          /* see comment for the same code in bm_send_event().
06636           * We make sure the buffer is nevere 100% full */
06637          assert(pheader->write_pointer != pheader->read_pointer);
06638 
06639          /* this loop does not loop forever because write_cache_rp
06640           * is monotonously incremented here. write_cache_wp does
06641           * not change */
06642 
06643          pbuf->write_cache_rp += total_size;
06644       }
06645 
06646       pbuf->write_cache_rp = pbuf->write_cache_wp = 0;
06647 
06648       /* check which clients are waiting */
06649       for (i = 0; i < pheader->max_client_index; i++)
06650          if (pclient[i].pid && pclient[i].read_wait) {
06651             char str[80];
06652 #ifdef DEBUG_MSG
06653             cm_msg(MDEBUG, "Send wake: rp=%d, wp=%d", pheader->read_pointer, pheader->write_pointer);
06654 #endif
06655             sprintf(str, "B %s %d", pheader->name, -1);
06656             ss_resume(pclient[i].port, str);
06657          }
06658 
06659       /* shift read pointer of own client */
06660       if (pclient[my_client_index].read_pointer == old_write_pointer)
06661          pclient[my_client_index].read_pointer = pheader->write_pointer;
06662 
06663       /* calculate global read pointer as "minimum" of client read pointers */
06664 
06665       bm_update_read_pointer("bm_flush_cache", pheader);
06666 
06667       /* update statistics */
06668       pheader->num_in_events++;
06669 
06670       /* unlock the buffer */
06671       bm_unlock_buffer(buffer_handle);
06672    }
06673 #endif                          /* LOCAL_ROUTINES */
06674 
06675    return BM_SUCCESS;
06676 }

INT bm_match_event ( short int  event_id,
short int  trigger_mask,
EVENT_HEADER pevent 
)

Check if an event matches a given event request by the event id and trigger mask

Parameters:
event_id Event ID of request
trigger_mask Trigger mask of request
pevent Pointer to event to check
Returns:
TRUE if event matches request

Definition at line 4140 of file midas.c.

Referenced by bm_dispatch_event(), bm_push_event(), bm_receive_event(), bm_send_event(), and bm_wait_for_free_space().

04141 {
04142    if ((pevent->event_id & 0xF000) == EVENTID_FRAG1 || (pevent->event_id & 0xF000) == EVENTID_FRAG)
04143       /* fragmented event */
04144       return ((event_id == EVENTID_ALL ||
04145                event_id == (pevent->event_id & 0x0FFF)) &&
04146               (trigger_mask == TRIGGER_ALL || (trigger_mask & pevent->trigger_mask)));
04147 
04148    return ((event_id == EVENTID_ALL ||
04149             event_id == pevent->event_id) && (trigger_mask == TRIGGER_ALL
04150                                               || (trigger_mask & pevent->trigger_mask)));
04151 }

INT bm_open_buffer ( char *  buffer_name,
INT  buffer_size,
INT buffer_handle 
)

Open an event buffer. Two default buffers are created by the system. The "SYSTEM" buffer is used to exchange events and the "SYSMSG" buffer is used to exchange system messages. The name and size of the event buffers is defined in midas.h as EVENT_BUFFER_NAME and 2*MAX_EVENT_SIZE. Following example opens the "SYSTEM" buffer, requests events with ID 1 and enters a main loop. Events are then received in process_event()

#include <stdio.h>
#include "midas.h"
void process_event(HNDLE hbuf, HNDLE request_id,
           EVENT_HEADER *pheader, void *pevent)
{
  printf("Received event #%d\r",
  pheader->serial_number);
}
main()
{
  INT status, request_id;
  HNDLE hbuf;
  status = cm_connect_experiment("pc810", "Sample", "Simple Analyzer", NULL);
  if (status != CM_SUCCESS)
  return 1;
  bm_open_buffer(EVENT_BUFFER_NAME, 2*MAX_EVENT_SIZE, &hbuf);
  bm_request_event(hbuf, 1, TRIGGER_ALL, GET_ALL, request_id, process_event);

  do
  {
   status = cm_yield(1000);
  } while (status != RPC_SHUTDOWN && status != SS_ABORT);
  cm_disconnect_experiment();
  return 0;
}
Parameters:
buffer_name Name of buffer
buffer_size Default size of buffer in bytes. Can by overwritten with ODB value
buffer_handle Buffer handle returned by function
Returns:
BM_SUCCESS, BM_CREATED
BM_NO_SHM Shared memory cannot be created
BM_NO_SEMAPHORE Semaphore cannot be created
BM_NO_MEMORY Not enough memory to create buffer descriptor
BM_MEMSIZE_MISMATCH Buffer size conflicts with an existing buffer of different size
BM_INVALID_PARAM Invalid parameter

Definition at line 4309 of file midas.c.

Referenced by cm_msg(), cm_msg1(), cm_msg_register(), command_loop(), register_equipment(), register_requests(), rpc_server_dispatch(), source_booking(), and tr_start().

04310 {
04311    INT status;
04312 
04313    if (rpc_is_remote()) {
04314       status = rpc_call(RPC_BM_OPEN_BUFFER, buffer_name, buffer_size, buffer_handle);
04315       bm_mark_read_waiting(TRUE);
04316       return status;
04317    }
04318 #ifdef LOCAL_ROUTINES
04319    {
04320       INT i, handle, size;
04321       BUFFER_CLIENT *pclient;
04322       BOOL shm_created;
04323       HNDLE shm_handle;
04324       BUFFER_HEADER *pheader;
04325       HNDLE hDB, odb_key;
04326       char odb_path[256];
04327       void *p;
04328 
04329       bm_cleanup("bm_open_buffer", ss_millitime(), FALSE);
04330 
04331       /* get buffer size from ODB, user parameter as default if not present in ODB */
04332       strlcpy(odb_path, "/Experiment/Buffer sizes/", sizeof(odb_path));
04333       strlcat(odb_path, buffer_name, sizeof(odb_path));
04334 
04335       status = cm_get_experiment_database(&hDB, &odb_key);
04336       assert(status == SUCCESS);
04337       size = sizeof(INT);
04338       status = db_get_value(hDB, 0, odb_path, &buffer_size, &size, TID_DWORD, TRUE);
04339 
04340       if (buffer_size <= 0 || buffer_size > 1 * 1024 * 1024 * 1024) {
04341          cm_msg(MERROR, "bm_open_buffer", "invalid buffer size %d", buffer_size);
04342          return BM_INVALID_PARAM;
04343       }
04344 
04345       if (!buffer_name[0]) {
04346          cm_msg(MERROR, "bm_open_buffer", "cannot open buffer with zero name");
04347          return BM_INVALID_PARAM;
04348       }
04349 
04350       /* allocate new space for the new buffer descriptor */
04351       if (_buffer_entries == 0) {
04352          _buffer = (BUFFER *) M_MALLOC(sizeof(BUFFER));
04353          memset(_buffer, 0, sizeof(BUFFER));
04354          if (_buffer == NULL) {
04355             *buffer_handle = 0;
04356             return BM_NO_MEMORY;
04357          }
04358 
04359          _buffer_entries = 1;
04360          i = 0;
04361       } else {
04362          /* check if buffer alreay is open */
04363          for (i = 0; i < _buffer_entries; i++)
04364             if (_buffer[i].attached && equal_ustring(_buffer[i].buffer_header->name, buffer_name)) {
04365                if (rpc_get_server_option(RPC_OSERVER_TYPE) == ST_SINGLE &&
04366                    _buffer[i].index != rpc_get_server_acception())
04367                   continue;
04368 
04369                if (rpc_get_server_option(RPC_OSERVER_TYPE) != ST_SINGLE && _buffer[i].index != ss_gettid())
04370                   continue;
04371 
04372                *buffer_handle = i + 1;
04373                return BM_SUCCESS;
04374             }
04375 
04376          /* check for a deleted entry */
04377          for (i = 0; i < _buffer_entries; i++)
04378             if (!_buffer[i].attached)
04379                break;
04380 
04381          /* if not found, create new one */
04382          if (i == _buffer_entries) {
04383             _buffer = (BUFFER *) realloc(_buffer, sizeof(BUFFER) * (_buffer_entries + 1));
04384             memset(&_buffer[_buffer_entries], 0, sizeof(BUFFER));
04385 
04386             _buffer_entries++;
04387             if (_buffer == NULL) {
04388                _buffer_entries--;
04389                *buffer_handle = 0;
04390                return BM_NO_MEMORY;
04391             }
04392          }
04393       }
04394 
04395       handle = i;
04396 
04397       if (strlen(buffer_name) >= NAME_LENGTH)
04398          buffer_name[NAME_LENGTH] = 0;
04399 
04400       /* reduce buffer size is larger than maximum */
04401 #ifdef MAX_SHM_SIZE
04402       if (buffer_size + sizeof(BUFFER_HEADER) > MAX_SHM_SIZE)
04403          buffer_size = MAX_SHM_SIZE - sizeof(BUFFER_HEADER);
04404 #endif
04405 
04406       /* open shared memory region */
04407       //status = ss_shm_open(buffer_name, sizeof(BUFFER_HEADER) + buffer_size,
04408       //               (void **) &(_buffer[handle].buffer_header), &shm_handle, FALSE);
04409       status = ss_shm_open(buffer_name, sizeof(BUFFER_HEADER) + buffer_size, &p, &shm_handle, FALSE);
04410       _buffer[handle].buffer_header = (BUFFER_HEADER *) p;
04411 
04412       if (status != SS_SUCCESS && status != SS_CREATED) {
04413          *buffer_handle = 0;
04414          _buffer_entries--;
04415          return BM_NO_SHM;
04416       }
04417 
04418       pheader = _buffer[handle].buffer_header;
04419 
04420       shm_created = (status == SS_CREATED);
04421 
04422       if (shm_created) {
04423          /* setup header info if buffer was created */
04424          memset(pheader, 0, sizeof(BUFFER_HEADER) + buffer_size);
04425 
04426          strcpy(pheader->name, buffer_name);
04427          pheader->size = buffer_size;
04428       } else {
04429          /* check if buffer size is identical */
04430          if (pheader->size != buffer_size) {
04431             cm_msg(MERROR, "bm_open_buffer", "Requested buffer size (%d) differs from existing size (%d)",
04432                    buffer_size, pheader->size);
04433             *buffer_handle = 0;
04434             _buffer_entries--;
04435             return BM_MEMSIZE_MISMATCH;
04436          }
04437       }
04438 
04439       /* create semaphore for the buffer */
04440       status = ss_semaphore_create(buffer_name, &(_buffer[handle].semaphore));
04441       if (status != SS_CREATED && status != SS_SUCCESS) {
04442          *buffer_handle = 0;
04443          _buffer_entries--;
04444          return BM_NO_SEMAPHORE;
04445       }
04446 
04447       /* first lock buffer */
04448       bm_lock_buffer(handle + 1);
04449 
04450       /*
04451          Now we have a BUFFER_HEADER, so let's setup a CLIENT
04452          structure in that buffer. The information there can also
04453          be seen by other processes.
04454        */
04455 
04456       for (i = 0; i < MAX_CLIENTS; i++)
04457          if (pheader->client[i].pid == 0)
04458             break;
04459 
04460       if (i == MAX_CLIENTS) {
04461          bm_unlock_buffer(handle + 1);
04462          *buffer_handle = 0;
04463          cm_msg(MERROR, "bm_open_buffer", "maximum number of clients exceeded");
04464          return BM_NO_SLOT;
04465       }
04466 
04467       /* store slot index in _buffer structure */
04468       _buffer[handle].client_index = i;
04469 
04470       /*
04471          Save the index of the last client of that buffer so that later only
04472          the clients 0..max_client_index-1 have to be searched through.
04473        */
04474       pheader->num_clients++;
04475       if (i + 1 > pheader->max_client_index)
04476          pheader->max_client_index = i + 1;
04477 
04478       /* setup buffer header and client structure */
04479       pclient = &pheader->client[i];
04480 
04481       memset(pclient, 0, sizeof(BUFFER_CLIENT));
04482       /* use client name previously set by bm_set_name */
04483       cm_get_client_info(pclient->name);
04484       if (pclient->name[0] == 0)
04485          strcpy(pclient->name, "unknown");
04486       pclient->pid = ss_getpid();
04487 
04488       ss_suspend_get_port(&pclient->port);
04489 
04490       pclient->read_pointer = pheader->write_pointer;
04491       pclient->last_activity = ss_millitime();
04492 
04493       cm_get_watchdog_params(NULL, &pclient->watchdog_timeout);
04494 
04495       bm_unlock_buffer(handle + 1);
04496 
04497       /* setup _buffer entry */
04498       _buffer[handle].buffer_data = _buffer[handle].buffer_header + 1;
04499       _buffer[handle].attached = TRUE;
04500       _buffer[handle].shm_handle = shm_handle;
04501       _buffer[handle].callback = FALSE;
04502 
04503       /* remember to which connection acutal buffer belongs */
04504       if (rpc_get_server_option(RPC_OSERVER_TYPE) == ST_SINGLE)
04505          _buffer[handle].index = rpc_get_server_acception();
04506       else
04507          _buffer[handle].index = ss_gettid();
04508 
04509       *buffer_handle = (handle + 1);
04510 
04511       /* initialize buffer counters */
04512       bm_init_buffer_counters(handle + 1);
04513 
04514       /* setup dispatcher for receive events */
04515       ss_suspend_set_dispatch(CH_IPC, 0, (int (*)(void)) cm_dispatch_ipc);
04516 
04517       bm_cleanup("bm_open_buffer", ss_millitime(), FALSE);
04518 
04519       if (shm_created)
04520          return BM_CREATED;
04521    }
04522 #endif                          /* LOCAL_ROUTINES */
04523 
04524    return BM_SUCCESS;
04525 }

INT bm_push_event ( char *  buffer_name  ) 

Check a buffer if an event is available and call the dispatch function if found.

Parameters:
buffer_name Name of buffer
Returns:
BM_SUCCESS, BM_INVALID_HANDLE, BM_TRUNCATED, BM_ASYNC_RETURN, RPC_NET_ERROR

Definition at line 7071 of file midas.c.

Referenced by bm_check_buffers().

07072 {
07073 #ifdef LOCAL_ROUTINES
07074    {
07075       BUFFER *pbuf;
07076       BUFFER_HEADER *pheader;
07077       BUFFER_CLIENT *pclient, *pc;
07078       char *pdata;
07079       INT i, size, buffer_handle;
07080       INT my_client_index;
07081       BOOL use_event_buffer = 0;
07082       BOOL cache_is_full = 0;
07083       int cycle = 0;
07084 
07085       for (i = 0; i < _buffer_entries; i++)
07086          if (strcmp(buffer_name, _buffer[i].buffer_header->name) == 0)
07087             break;
07088       if (i == _buffer_entries)
07089          return BM_INVALID_HANDLE;
07090 
07091       buffer_handle = i + 1;
07092       pbuf = &_buffer[buffer_handle - 1];
07093 
07094       if (!pbuf->attached)
07095          return BM_INVALID_HANDLE;
07096 
07097       /* return immediately if no callback routine is defined */
07098       if (!pbuf->callback)
07099          return BM_SUCCESS;
07100 
07101       if (_event_buffer_size == 0) {
07102          _event_buffer = (EVENT_HEADER *) M_MALLOC(1000);
07103          if (_event_buffer == NULL) {
07104             cm_msg(MERROR, "bm_push_event", "not enough memory to allocate cache buffer");
07105             return BM_NO_MEMORY;
07106          }
07107          _event_buffer_size = 1000;
07108       }
07109 
07110       /* look if there is anything in the cache */
07111       if (bm_read_cache_has_events(pbuf)) {
07112          bm_dispatch_from_cache(pbuf, buffer_handle);
07113          return BM_MORE_EVENTS;
07114       }
07115 
07116       /* calculate some shorthands */
07117       pheader = pbuf->buffer_header;
07118       pdata = (char *) (pheader + 1);
07119       my_client_index = bm_validate_client_index(pbuf);
07120       pclient = pheader->client;
07121       pc = pheader->client + my_client_index;
07122 
07123       /* first do a quick check without locking the buffer */
07124       if (pheader->write_pointer == pc->read_pointer)
07125          return BM_SUCCESS;
07126 
07127       /* lock the buffer */
07128       bm_lock_buffer(buffer_handle);
07129 
07130       if (pheader->write_pointer == pc->read_pointer) {
07131 
07132          bm_unlock_buffer(buffer_handle);
07133 
07134          /* return if no event available */
07135          return BM_SUCCESS;
07136       }
07137 
07138       /* loop over all events in the buffer */
07139 
07140       do {
07141          int new_read_pointer;
07142          int total_size;        /* size of the event */
07143          EVENT_REQUEST *prequest;
07144          EVENT_HEADER *pevent = (EVENT_HEADER *) (pdata + pc->read_pointer);
07145 
07146          assert(pc->read_pointer >= 0);
07147          assert(pc->read_pointer <= pheader->size);
07148 
07149          total_size = pevent->data_size + sizeof(EVENT_HEADER);
07150          total_size = ALIGN8(total_size);
07151 
07152          assert(total_size > 0);
07153          assert(total_size <= pheader->size);
07154 
07155          prequest = pc->event_request;
07156 
07157          /* loop over all requests: if this event matches a request,
07158           * copy it to the read cache */
07159 
07160          for (i = 0; i < pc->max_request_index; i++, prequest++)
07161             if (prequest->valid && bm_match_event(prequest->event_id, prequest->trigger_mask, pevent)) {
07162 
07163                /* check if this is a recent event */
07164                if (prequest->sampling_type == GET_RECENT) {
07165                   if (ss_time() - pevent->time_stamp > 1) {
07166                      /* skip that event */
07167                      continue;
07168                   }
07169 
07170                   printf("now: %d, event: %d\n", ss_time(), pevent->time_stamp);
07171                }
07172 
07173                /* we found a request for this event, so copy it */
07174 
07175                if (pbuf->read_cache_size > 0 && total_size < pbuf->read_cache_size) {
07176 
07177                   /* copy event to cache, if there is room */
07178 
07179                   if (pbuf->read_cache_wp + total_size >= pbuf->read_cache_size) {
07180                      cache_is_full = TRUE;
07181                      break;     /* exit loop over requests */
07182                   }
07183 
07184                   if (pc->read_pointer + total_size <= pheader->size) {
07185                      /* copy event to cache */
07186                      memcpy(pbuf->read_cache + pbuf->read_cache_wp, pevent, total_size);
07187                   } else {
07188                      /* event is splitted */
07189                      size = pheader->size - pc->read_pointer;
07190                      memcpy(pbuf->read_cache + pbuf->read_cache_wp, pevent, size);
07191                      memcpy((char *) pbuf->read_cache + pbuf->read_cache_wp + size, pdata, total_size - size);
07192                   }
07193 
07194                   pbuf->read_cache_wp += total_size;
07195 
07196                } else {
07197                   /* copy event to copy buffer */
07198 
07199                   /* if there are events in the read cache,
07200                    * we should dispatch them before we
07201                    * despatch this oversize event */
07202 
07203                   if (bm_read_cache_has_events(pbuf)) {
07204                      cache_is_full = TRUE;
07205                      break;     /* exit loop over requests */
07206                   }
07207 
07208                   use_event_buffer = TRUE;
07209 
07210                   if (total_size > _event_buffer_size) {
07211                      //printf("realloc event buffer %d -> %d\n", _event_buffer_size, total_size);
07212                      _event_buffer = (EVENT_HEADER *) realloc(_event_buffer, total_size);
07213                      _event_buffer_size = total_size;
07214                   }
07215 
07216                   if (pc->read_pointer + total_size <= pheader->size) {
07217                      memcpy(_event_buffer, pevent, total_size);
07218                   } else {
07219                      /* event is splitted */
07220                      size = pheader->size - pc->read_pointer;
07221 
07222                      memcpy(_event_buffer, pevent, size);
07223                      memcpy((char *) _event_buffer + size, pdata, total_size - size);
07224                   }
07225                }
07226 
07227                /* update statistics */
07228                pheader->num_out_events++;
07229                break;           /* exit loop over event requests */
07230 
07231             }
07232          /* end of loop over event requests */
07233          if (cache_is_full)
07234             break;              /* exit from loop over events in data buffer, leaving the current event untouched */
07235 
07236          /* shift read pointer */
07237 
07238          assert(total_size > 0);
07239          assert(total_size <= pheader->size);
07240 
07241          new_read_pointer = pc->read_pointer + total_size;
07242          if (new_read_pointer >= pheader->size) {
07243             new_read_pointer = new_read_pointer % pheader->size;
07244 
07245             /* make sure we loop over the data buffer no more than once */
07246             cycle++;
07247             assert(cycle < 2);
07248          }
07249 
07250          /* make sure we do not split the event header at the end of the buffer */
07251          if (new_read_pointer > pheader->size - (int) sizeof(EVENT_HEADER))
07252             new_read_pointer = 0;
07253 
07254 #ifdef DEBUG_MSG
07255          cm_msg(MDEBUG, "bm_push_event -> wp=%d, rp %d -> %d (found=%d,size=%d)",
07256                 pheader->write_pointer, pc->read_pointer, new_read_pointer, found, total_size);
07257 #endif
07258 
07259          pc->read_pointer = new_read_pointer;
07260 
07261          if (use_event_buffer)
07262             break;              /* exit from loop over events in data buffer */
07263 
07264       } while (pheader->write_pointer != pc->read_pointer);
07265 
07266       /* calculate global read pointer as "minimum" of client read pointers */
07267 
07268       bm_update_read_pointer("bm_push_event", pheader);
07269 
07270       /*
07271          If read pointer has been changed, it may have freed up some space
07272          for waiting producers. So check if free space is now more than 50%
07273          of the buffer size and wake waiting producers.
07274        */
07275 
07276       bm_wakeup_producers(pheader, pc);
07277 
07278       bm_unlock_buffer(buffer_handle);
07279 
07280       if (bm_read_cache_has_events(pbuf)) {
07281          assert(!use_event_buffer);     /* events only go into the _event_buffer when read cache is empty */
07282          bm_dispatch_from_cache(pbuf, buffer_handle);
07283          return BM_MORE_EVENTS;
07284       }
07285 
07286       if (use_event_buffer) {
07287          bm_dispatch_event(buffer_handle, _event_buffer);
07288          return BM_MORE_EVENTS;
07289       }
07290 
07291       return BM_SUCCESS;
07292    }
07293 #else                           /* LOCAL_ROUTINES */
07294 
07295    return BM_SUCCESS;
07296 #endif
07297 }

static int bm_read_cache_has_events ( const BUFFER pbuf  )  [static]

Definition at line 6117 of file midas.c.

Referenced by bm_push_event(), and bm_receive_event().

06118 {
06119    if (pbuf->read_cache_size == 0)
06120       return 0;
06121 
06122    if (pbuf->read_cache_rp == pbuf->read_cache_wp)
06123       return 0;
06124 
06125    return 1;
06126 }

INT bm_receive_event ( INT  buffer_handle,
void *  destination,
INT buf_size,
INT  async_flag 
)

Receives events directly. This function is an alternative way to receive events without a main loop.

It can be used in analysis systems which actively receive events, rather than using callbacks. A analysis package could for example contain its own command line interface. A command like "receive 1000 events" could make it necessary to call bm_receive_event() 1000 times in a row to receive these events and then return back to the command line prompt. The according bm_request_event() call contains NULL as the callback routine to indicate that bm_receive_event() is called to receive events.

#include <stdio.h>
#include "midas.h"
void process_event(EVENT_HEADER *pheader)
{
 printf("Received event #%d\r",
 pheader->serial_number);
}
main()
{
  INT status, request_id;
  HNDLE hbuf;
  char event_buffer[1000];
  status = cm_connect_experiment("", "Sample",
  "Simple Analyzer", NULL);
  if (status != CM_SUCCESS)
   return 1;
  bm_open_buffer(EVENT_BUFFER_NAME, 2*MAX_EVENT_SIZE, &hbuf);
  bm_request_event(hbuf, 1, TRIGGER_ALL, GET_ALL, request_id, NULL);

  do
  {
   size = sizeof(event_buffer);
   status = bm_receive_event(hbuf, event_buffer, &size, ASYNC);
  if (status == CM_SUCCESS)
   process_event((EVENT_HEADER *) event_buffer);
   <...do something else...>
   status = cm_yield(0);
  } while (status != RPC_SHUTDOWN &&
  status != SS_ABORT);
  cm_disconnect_experiment();
  return 0;
}
Parameters:
buffer_handle buffer handle
destination destination address where event is written to
buf_size size of destination buffer on input, size of event plus header on return.
async_flag Synchronous/asynchronous flag. If FALSE, the function blocks if no event is available. If TRUE, the function returns immediately with a value of BM_ASYNC_RETURN without receiving any event.
Returns:
BM_SUCCESS, BM_INVALID_HANDLE
BM_TRUNCATED The event is larger than the destination buffer and was therefore truncated
BM_ASYNC_RETURN No event available

Definition at line 6739 of file midas.c.

Referenced by handFlush(), rpc_server_dispatch(), and source_scan().

06740 {
06741    if (rpc_is_remote()) {
06742       int status, old_timeout = 0;
06743 
06744       status = resize_net_send_buffer("bm_receive_event", *buf_size);
06745       if (status != SUCCESS)
06746          return status;  
06747 
06748       if (!async_flag) {
06749          old_timeout = rpc_get_option(-1, RPC_OTIMEOUT);
06750          rpc_set_option(-1, RPC_OTIMEOUT, 0);
06751       }
06752 
06753       status = rpc_call(RPC_BM_RECEIVE_EVENT, buffer_handle, destination, buf_size, async_flag);
06754 
06755       if (!async_flag) {
06756          rpc_set_option(-1, RPC_OTIMEOUT, old_timeout);
06757       }
06758 
06759       return status;
06760    }
06761 #ifdef LOCAL_ROUTINES
06762    {
06763       BUFFER *pbuf;
06764       BUFFER_HEADER *pheader;
06765       BUFFER_CLIENT *pclient, *pc;
06766       char *pdata;
06767       INT convert_flags;
06768       INT i, size, max_size;
06769       INT status = 0;
06770       INT my_client_index;
06771       BOOL cache_is_full = FALSE;
06772       BOOL use_event_buffer = FALSE;
06773       int cycle = 0;
06774 
06775       pbuf = &_buffer[buffer_handle - 1];
06776 
06777       if (buffer_handle > _buffer_entries || buffer_handle <= 0) {
06778          cm_msg(MERROR, "bm_receive_event", "invalid buffer handle %d", buffer_handle);
06779          return BM_INVALID_HANDLE;
06780       }
06781 
06782       if (!pbuf->attached) {
06783          cm_msg(MERROR, "bm_receive_event", "invalid buffer handle %d", buffer_handle);
06784          return BM_INVALID_HANDLE;
06785       }
06786 
06787       max_size = *buf_size;
06788       *buf_size = 0;
06789 
06790       if (rpc_get_server_option(RPC_OSERVER_TYPE) != ST_REMOTE)
06791          convert_flags = rpc_get_server_option(RPC_CONVERT_FLAGS);
06792       else
06793          convert_flags = 0;
06794 
06795       /* look if there is anything in the cache */
06796       if (bm_read_cache_has_events(pbuf))
06797          return bm_copy_from_cache(pbuf, destination, max_size, buf_size, convert_flags);
06798 
06799     LOOP:
06800       /* make sure we do bm_validate_client_index() after sleeping */
06801 
06802       /* calculate some shorthands */
06803       pheader = pbuf->buffer_header;
06804       pdata = (char *) (pheader + 1);
06805       my_client_index = bm_validate_client_index(pbuf);
06806       pclient = pheader->client;
06807       pc = pheader->client + my_client_index;
06808 
06809       /* first do a quick check without locking the buffer */
06810       if (async_flag == ASYNC && pheader->write_pointer == pc->read_pointer)
06811          return BM_ASYNC_RETURN;
06812 
06813       /* lock the buffer */
06814       bm_lock_buffer(buffer_handle);
06815 
06816       while (pheader->write_pointer == pc->read_pointer) {
06817 
06818          bm_unlock_buffer(buffer_handle);
06819 
06820          /* return now in ASYNC mode */
06821          if (async_flag == ASYNC)
06822             return BM_ASYNC_RETURN;
06823 
06824          pc->read_wait = TRUE;
06825 
06826          /* check again pointers (may have moved in between) */
06827          if (pheader->write_pointer == pc->read_pointer) {
06828 #ifdef DEBUG_MSG
06829             cm_msg(MDEBUG, "Receive sleep: grp=%d, rp=%d wp=%d",
06830                    pheader->read_pointer, pc->read_pointer, pheader->write_pointer);
06831 #endif
06832 
06833             status = ss_suspend(1000, MSG_BM);
06834 
06835 #ifdef DEBUG_MSG
06836             cm_msg(MDEBUG, "Receive woke up: rp=%d, wp=%d", pheader->read_pointer, pheader->write_pointer);
06837 #endif
06838 
06839             /* return if TCP connection broken */
06840             if (status == SS_ABORT)
06841                return SS_ABORT;
06842          }
06843 
06844          pc->read_wait = FALSE;
06845 
06846          /* validate client_index: somebody may have disconnected us from the buffer */
06847          bm_validate_client_index(pbuf);
06848 
06849          bm_lock_buffer(buffer_handle);
06850       }
06851 
06852       /* check if event at current read pointer matches a request */
06853 
06854       do {
06855          int new_read_pointer;
06856          int total_size;        /* size of the event */
06857          EVENT_REQUEST *prequest;
06858          EVENT_HEADER *pevent = (EVENT_HEADER *) (pdata + pc->read_pointer);
06859 
06860          assert(pc->read_pointer >= 0);
06861          assert(pc->read_pointer <= pheader->size);
06862 
06863          total_size = pevent->data_size + sizeof(EVENT_HEADER);
06864          total_size = ALIGN8(total_size);
06865 
06866          assert(total_size > 0);
06867          assert(total_size <= pheader->size);
06868 
06869          prequest = pc->event_request;
06870 
06871          /* loop over all requests: if this event matches a request,
06872           * copy it to the read cache */
06873 
06874          for (i = 0; i < pc->max_request_index; i++, prequest++)
06875             if (prequest->valid && bm_match_event(prequest->event_id, prequest->trigger_mask, pevent)) {
06876 
06877                /* we found a request for this event, so copy it */
06878 
06879                if (pbuf->read_cache_size > 0 && total_size < pbuf->read_cache_size) {
06880 
06881                   /* copy event to cache, if there is room */
06882 
06883                   if (pbuf->read_cache_wp + total_size >= pbuf->read_cache_size) {
06884                      cache_is_full = TRUE;
06885                      break;     /* exit loop over requests */
06886                   }
06887 
06888                   if (pc->read_pointer + total_size <= pheader->size) {
06889                      /* copy event to cache */
06890                      memcpy(pbuf->read_cache + pbuf->read_cache_wp, pevent, total_size);
06891                   } else {
06892                      /* event is splitted */
06893                      size = pheader->size - pc->read_pointer;
06894                      memcpy(pbuf->read_cache + pbuf->read_cache_wp, pevent, size);
06895                      memcpy((char *) pbuf->read_cache + pbuf->read_cache_wp + size, pdata, total_size - size);
06896                   }
06897 
06898                   pbuf->read_cache_wp += total_size;
06899 
06900                } else {
06901                   int copy_size = total_size;
06902 
06903                   /* if there are events in the read cache,
06904                    * we should dispatch them before we
06905                    * despatch this oversize event */
06906 
06907                   if (bm_read_cache_has_events(pbuf)) {
06908                      cache_is_full = TRUE;
06909                      break;     /* exit loop over requests */
06910                   }
06911 
06912                   use_event_buffer = TRUE;
06913 
06914                   status = BM_SUCCESS;
06915                   if (copy_size > max_size) {
06916                      copy_size = max_size;
06917                      cm_msg(MERROR, "bm_receive_event",
06918                             "event size %d larger than buffer size %d", total_size, max_size);
06919                      status = BM_TRUNCATED;
06920                   }
06921 
06922                   if (pc->read_pointer + total_size <= pheader->size) {
06923                      /* event is not splitted */
06924                      memcpy(destination, pevent, copy_size);
06925                   } else {
06926                      /* event is splitted */
06927                      size = pheader->size - pc->read_pointer;
06928 
06929                      if (size > max_size)
06930                         memcpy(destination, pevent, max_size);
06931                      else
06932                         memcpy(destination, pevent, size);
06933 
06934                      if (total_size > max_size) {
06935                         if (size <= max_size)
06936                            memcpy((char *) destination + size, pdata, max_size - size);
06937                      } else
06938                         memcpy((char *) destination + size, pdata, total_size - size);
06939                   }
06940 
06941                   *buf_size = copy_size;
06942 
06943                   bm_convert_event_header((EVENT_HEADER *) destination, convert_flags);
06944                }
06945 
06946                /* update statistics */
06947                pheader->num_out_events++;
06948                break;           /* stop looping over requests */
06949             }
06950 
06951          if (cache_is_full)
06952             break;              /* exit from loop over events in data buffer, leaving the current event untouched */
06953 
06954          /* shift read pointer */
06955 
06956          assert(total_size > 0);
06957          assert(total_size <= pheader->size);
06958 
06959          new_read_pointer = pc->read_pointer + total_size;
06960          if (new_read_pointer >= pheader->size) {
06961             new_read_pointer = new_read_pointer % pheader->size;
06962 
06963             /* make sure we loop over the data buffer no more than once */
06964             cycle++;
06965             assert(cycle < 2);
06966          }
06967 
06968          /* make sure we do not split the event header at the end of the buffer */
06969          if (new_read_pointer > pheader->size - (int) sizeof(EVENT_HEADER))
06970             new_read_pointer = 0;
06971 
06972 #ifdef DEBUG_MSG
06973          cm_msg(MDEBUG, "bm_receive_event -> wp=%d, rp %d -> %d (found=%d,size=%d)",
06974                 pheader->write_pointer, pc->read_pointer, new_read_pointer, found, total_size);
06975 #endif
06976 
06977          pc->read_pointer = new_read_pointer;
06978 
06979          if (use_event_buffer)
06980             break;              /* exit from loop over events in data buffer */
06981 
06982       } while (pheader->write_pointer != pc->read_pointer);
06983 
06984       /* calculate global read pointer as "minimum" of client read pointers */
06985 
06986       bm_update_read_pointer("bm_receive_event", pheader);
06987 
06988       /*
06989          If read pointer has been changed, it may have freed up some space
06990          for waiting producers. So check if free space is now more than 50%
06991          of the buffer size and wake waiting producers.
06992        */
06993 
06994       bm_wakeup_producers(pheader, pc);
06995 
06996       bm_unlock_buffer(buffer_handle);
06997 
06998       if (bm_read_cache_has_events(pbuf)) {
06999          assert(!use_event_buffer);     /* events only go into the _event_buffer when read cache is empty */
07000          return bm_copy_from_cache(pbuf, destination, max_size, buf_size, convert_flags);
07001       }
07002 
07003       if (use_event_buffer)
07004          return status;
07005 
07006       goto LOOP;
07007    }
07008 #else                           /* LOCAL_ROUTINES */
07009 
07010    return SS_SUCCESS;
07011 #endif
07012 }

void bm_remove_client_locked ( BUFFER_HEADER pheader,
int  j 
)

Called to forcibly disconnect given client from a data buffer

Definition at line 4157 of file midas.c.

Referenced by bm_cleanup(), and cm_cleanup().

04158 {
04159    int k, nc;
04160    BUFFER_CLIENT *pbctmp;
04161 
04162    /* clear entry from client structure in buffer header */
04163    memset(&(pheader->client[j]), 0, sizeof(BUFFER_CLIENT));
04164 
04165    /* calculate new max_client_index entry */
04166    for (k = MAX_CLIENTS - 1; k >= 0; k--)
04167       if (pheader->client[k].pid != 0)
04168          break;
04169    pheader->max_client_index = k + 1;
04170 
04171    /* count new number of clients */
04172    for (k = MAX_CLIENTS - 1, nc = 0; k >= 0; k--)
04173       if (pheader->client[k].pid != 0)
04174          nc++;
04175    pheader->num_clients = nc;
04176 
04177    /* check if anyone is waiting and wake him up */
04178    pbctmp = pheader->client;
04179 
04180    for (k = 0; k < pheader->max_client_index; k++, pbctmp++)
04181       if (pbctmp->pid && (pbctmp->write_wait || pbctmp->read_wait))
04182          ss_resume(pbctmp->port, "B  ");
04183 }

INT bm_remove_event_request ( INT  buffer_handle,
INT  request_id 
)

Delete a previously placed request for a specific event type in the client structure of the buffer refereced by buffer_handle.

Parameters:
buffer_handle Handle to the buffer where the re- quest should be placed in
request_id Request id returned by bm_request_event
Returns:
BM_SUCCESS, BM_INVALID_HANDLE, BM_NOT_FOUND, RPC_NET_ERROR

Definition at line 5786 of file midas.c.

Referenced by bm_delete_request(), and rpc_server_dispatch().

05787 {
05788    if (rpc_is_remote())
05789       return rpc_call(RPC_BM_REMOVE_EVENT_REQUEST, buffer_handle, request_id);
05790 
05791 #ifdef LOCAL_ROUTINES
05792    {
05793       INT i, deleted;
05794       BUFFER_CLIENT *pclient;
05795 
05796       if (buffer_handle > _buffer_entries || buffer_handle <= 0) {
05797          cm_msg(MERROR, "bm_remove_event_request", "invalid buffer handle %d", buffer_handle);
05798          return BM_INVALID_HANDLE;
05799       }
05800 
05801       if (!_buffer[buffer_handle - 1].attached) {
05802          cm_msg(MERROR, "bm_remove_event_request", "invalid buffer handle %d", buffer_handle);
05803          return BM_INVALID_HANDLE;
05804       }
05805 
05806       /* get a pointer to the proper client structure */
05807       pclient = &(_buffer[buffer_handle - 1].buffer_header->
05808                   client[bm_validate_client_index(&_buffer[buffer_handle - 1])]);
05809 
05810       /* lock buffer */
05811       bm_lock_buffer(buffer_handle);
05812 
05813       /* check all requests and set to zero if matching */
05814       for (i = 0, deleted = 0; i < pclient->max_request_index; i++)
05815          if (pclient->event_request[i].valid && pclient->event_request[i].id == request_id) {
05816             memset(&pclient->event_request[i], 0, sizeof(EVENT_REQUEST));
05817             deleted++;
05818          }
05819 
05820       /* calculate new max_request_index entry */
05821       for (i = MAX_EVENT_REQUESTS - 1; i >= 0; i--)
05822          if (pclient->event_request[i].valid)
05823             break;
05824 
05825       pclient->max_request_index = i + 1;
05826 
05827       /* caluclate new all_flag */
05828       pclient->all_flag = FALSE;
05829 
05830       for (i = 0; i < pclient->max_request_index; i++)
05831          if (pclient->event_request[i].valid && (pclient->event_request[i].sampling_type & GET_ALL)) {
05832             pclient->all_flag = TRUE;
05833             break;
05834          }
05835 
05836       bm_unlock_buffer(buffer_handle);
05837 
05838       if (!deleted)
05839          return BM_NOT_FOUND;
05840    }
05841 #endif                          /* LOCAL_ROUTINES */
05842 
05843    return BM_SUCCESS;
05844 }

INT bm_request_event ( HNDLE  buffer_handle,
short int  event_id,
short int  trigger_mask,
INT  sampling_type,
HNDLE *  request_id,
void(*)(HNDLE, HNDLE, EVENT_HEADER *, void *)  func 
)

Place an event request based on certain characteristics. Multiple event requests can be placed for each buffer, which are later identified by their request ID. They can contain different callback routines. Example see bm_open_buffer() and bm_receive_event()

Parameters:
buffer_handle buffer handle obtained via bm_open_buffer()
event_id event ID for requested events. Use EVENTID_ALL to receive events with any ID.
trigger_mask trigger mask for requested events. The requested events must have at least one bit in its trigger mask common with the requested trigger mask. Use TRIGGER_ALL to receive events with any trigger mask.
sampling_type specifies how many events to receive. A value of GET_ALL receives all events which match the specified event ID and trigger mask. If the events are consumed slower than produced, the producer is automatically slowed down. A value of GET_NONBLOCKING receives as much events as possible without slowing down the producer. GET_ALL is typically used by the logger, while GET_NONBLOCKING is typically used by analyzers.
request_id request ID returned by the function. This ID is passed to the callback routine and must be used in the bm_delete_request() routine.
func allback routine which gets called when an event of the specified type is received.
Returns:
BM_SUCCESS, BM_INVALID_HANDLE
BM_NO_MEMORY too many requests. The value MAX_EVENT_REQUESTS in midas.h should be increased.

Definition at line 5722 of file midas.c.

Referenced by cm_msg_register(), register_requests(), source_booking(), tr_start(), and update_request().

05726 {
05727    INT idx, status;
05728 
05729    /* allocate new space for the local request list */
05730    if (_request_list_entries == 0) {
05731       _request_list = (REQUEST_LIST *) M_MALLOC(sizeof(REQUEST_LIST));
05732       memset(_request_list, 0, sizeof(REQUEST_LIST));
05733       if (_request_list == NULL) {
05734          cm_msg(MERROR, "bm_request_event", "not enough memory to allocate request list buffer");
05735          return BM_NO_MEMORY;
05736       }
05737 
05738       _request_list_entries = 1;
05739       idx = 0;
05740    } else {
05741       /* check for a deleted entry */
05742       for (idx = 0; idx < _request_list_entries; idx++)
05743          if (!_request_list[idx].buffer_handle)
05744             break;
05745 
05746       /* if not found, create new one */
05747       if (idx == _request_list_entries) {
05748          _request_list =
05749              (REQUEST_LIST *) realloc(_request_list, sizeof(REQUEST_LIST) * (_request_list_entries + 1));
05750          if (_request_list == NULL) {
05751             cm_msg(MERROR, "bm_request_event", "not enough memory to allocate request list buffer");
05752             return BM_NO_MEMORY;
05753          }
05754 
05755          memset(&_request_list[_request_list_entries], 0, sizeof(REQUEST_LIST));
05756 
05757          _request_list_entries++;
05758       }
05759    }
05760 
05761    /* initialize request list */
05762    _request_list[idx].buffer_handle = buffer_handle;
05763    _request_list[idx].event_id = event_id;
05764    _request_list[idx].trigger_mask = trigger_mask;
05765    _request_list[idx].dispatcher = func;
05766 
05767    *request_id = idx;
05768 
05769    /* add request in buffer structure */
05770    status = bm_add_event_request(buffer_handle, event_id, trigger_mask, sampling_type, func, idx);
05771    if (status != BM_SUCCESS)
05772       return status;
05773 
05774    return BM_SUCCESS;
05775 }

INT bm_send_event ( INT  buffer_handle,
void *  source,
INT  buf_size,
INT  async_flag 
)

Sends an event to a buffer. This function check if the buffer has enough space for the event, then copies the event to the buffer in shared memory. If clients have requests for the event, they are notified via an UDP packet.

char event[1000];
// create event with ID 1, trigger mask 0, size 100 bytes and serial number 1
bm_compose_event((EVENT_HEADER *) event, 1, 0, 100, 1);

// set first byte of event
*(event+sizeof(EVENT_HEADER)) = <...>
#include <stdio.h>
#include "midas.h"
main()
{
 INT status, i;
 HNDLE hbuf;
 char event[1000];
 status = cm_connect_experiment("", "Sample", "Producer", NULL);
 if (status != CM_SUCCESS)
 return 1;
 bm_open_buffer(EVENT_BUFFER_NAME, 2*MAX_EVENT_SIZE, &hbuf);

 // create event with ID 1, trigger mask 0, size 100 bytes and serial number 1
 bm_compose_event((EVENT_HEADER *) event, 1, 0, 100, 1);

 // set event data
 for (i=0 ; i<100 ; i++)
 *(event+sizeof(EVENT_HEADER)+i) = i;
 // send event
 bm_send_event(hbuf, event, 100+sizeof(EVENT_HEADER), SYNC);
 cm_disconnect_experiment();
 return 0;
}
Parameters:
buffer_handle Buffer handle obtained via bm_open_buffer()
source Address of event buffer
buf_size Size of event including event header in bytes
async_flag Synchronous/asynchronous flag. If FALSE, the function blocks if the buffer has not enough free space to receive the event. If TRUE, the function returns immediately with a value of BM_ASYNC_RETURN without writing the event to the buffer
Returns:
BM_SUCCESS, BM_INVALID_HANDLE, BM_INVALID_PARAM
BM_ASYNC_RETURN Routine called with async_flag == TRUE and buffer has not enough space to receive event
BM_NO_MEMORY Event is too large for network buffer or event buffer. One has to increase MAX_EVENT_SIZE in midas.h and recompile.

Definition at line 6353 of file midas.c.

Referenced by cm_msg(), cm_msg1(), rpc_send_event(), rpc_server_dispatch(), and send_event().

06354 {
06355    EVENT_HEADER *pevent;
06356 
06357    /* check if event size is invalid */
06358    if (buf_size < sizeof(EVENT_HEADER)) {
06359       cm_msg(MERROR, "bm_send_event", "event size (%d) it too small", buf_size);
06360       return BM_INVALID_PARAM;
06361    }
06362 
06363    /* check if event size defined in header matches buf_size */
06364    if (ALIGN8(buf_size) != (INT) ALIGN8(((EVENT_HEADER *) source)->data_size + sizeof(EVENT_HEADER))) {
06365       cm_msg(MERROR, "bm_send_event", "event size (%d) mismatch in header (%d)",
06366              ALIGN8(buf_size), (INT) ALIGN8(((EVENT_HEADER *) source)->data_size + sizeof(EVENT_HEADER)));
06367       return BM_INVALID_PARAM;
06368    }
06369 
06370    if (rpc_is_remote())
06371       return rpc_call(RPC_BM_SEND_EVENT, buffer_handle, source, buf_size, async_flag);
06372 
06373 #ifdef LOCAL_ROUTINES
06374    {
06375       BUFFER *pbuf;
06376       BUFFER_HEADER *pheader;
06377       BUFFER_CLIENT *pclient;
06378       EVENT_REQUEST *prequest;
06379       INT i, j, size, total_size, status;
06380       INT my_client_index;
06381       INT old_write_pointer;
06382       INT num_requests_client;
06383       char *pdata;
06384       INT request_id;
06385 
06386       pbuf = &_buffer[buffer_handle - 1];
06387 
06388       if (buffer_handle > _buffer_entries || buffer_handle <= 0) {
06389          cm_msg(MERROR, "bm_send_event", "invalid buffer handle %d", buffer_handle);
06390          return BM_INVALID_HANDLE;
06391       }
06392 
06393       if (!pbuf->attached) {
06394          cm_msg(MERROR, "bm_send_event", "invalid buffer handle %d", buffer_handle);
06395          return BM_INVALID_HANDLE;
06396       }
06397 
06398       pevent = (EVENT_HEADER *) source;
06399       total_size = buf_size;
06400 
06401       /* round up total_size to next DWORD boundary */
06402       total_size = ALIGN8(total_size);
06403 
06404       /* look if there is space in the cache */
06405       if (pbuf->write_cache_size) {
06406          status = BM_SUCCESS;
06407 
06408          if (pbuf->write_cache_size - pbuf->write_cache_wp < total_size)
06409             status = bm_flush_cache(buffer_handle, async_flag);
06410 
06411          if (status != BM_SUCCESS)
06412             return status;
06413 
06414          if (total_size < pbuf->write_cache_size) {
06415             memcpy(pbuf->write_cache + pbuf->write_cache_wp, source, total_size);
06416 
06417             pbuf->write_cache_wp += total_size;
06418             return BM_SUCCESS;
06419          }
06420       }
06421 
06422       /* we come here only for events that are too big to fit into the cache */
06423 
06424       /* calculate some shorthands */
06425       pheader = pbuf->buffer_header;
06426       pdata = (char *) (pheader + 1);
06427       my_client_index = bm_validate_client_index(pbuf);
06428       pclient = pheader->client;
06429 
06430       /* check if buffer is large enough */
06431       if (total_size >= pheader->size) {
06432          cm_msg(MERROR, "bm_send_event",
06433                 "total event size (%d) larger than size (%d) of buffer \'%s\'", total_size, pheader->size, pheader->name);
06434          return BM_NO_MEMORY;
06435       }
06436 
06437       /* lock the buffer */
06438       bm_lock_buffer(buffer_handle);
06439 
06440       status = bm_wait_for_free_space(buffer_handle, pbuf, async_flag, total_size);
06441       if (status != BM_SUCCESS) {
06442          bm_unlock_buffer(buffer_handle);
06443          return status;
06444       }
06445 
06446       /* we have space, so let's copy the event */
06447       old_write_pointer = pheader->write_pointer;
06448 
06449       if (pheader->write_pointer + total_size <= pheader->size) {
06450          memcpy(pdata + pheader->write_pointer, pevent, total_size);
06451          pheader->write_pointer = (pheader->write_pointer + total_size) % pheader->size;
06452          if (pheader->write_pointer > pheader->size - (int) sizeof(EVENT_HEADER))
06453             pheader->write_pointer = 0;
06454       } else {
06455          /* split event */
06456          size = pheader->size - pheader->write_pointer;
06457 
06458          memcpy(pdata + pheader->write_pointer, pevent, size);
06459          memcpy(pdata, (char *) pevent + size, total_size - size);
06460 
06461          pheader->write_pointer = total_size - size;
06462       }
06463 
06464       /* write pointer was incremented, but there should
06465        * always be some free space in the buffer and the
06466        * write pointer should never cacth up to the read pointer:
06467        * the rest of the code gets confused this happens (buffer 100% full)
06468        * as it is write_pointer == read_pointer can be either
06469        * 100% full or 100% empty. My solution: never fill
06470        * the buffer to 100% */
06471       assert(pheader->write_pointer != pheader->read_pointer);
06472 
06473       /* check which clients have a request for this event */
06474       for (i = 0; i < pheader->max_client_index; i++)
06475          if (pclient[i].pid) {
06476             prequest = pclient[i].event_request;
06477             num_requests_client = 0;
06478             request_id = -1;
06479 
06480             for (j = 0; j < pclient[i].max_request_index; j++, prequest++)
06481                if (prequest->valid && bm_match_event(prequest->event_id, prequest->trigger_mask, pevent)) {
06482                   if (prequest->sampling_type & GET_ALL)
06483                      pclient[i].num_waiting_events++;
06484 
06485                   num_requests_client++;
06486                   request_id = prequest->id;
06487                }
06488 
06489             /* if that client has a request and is suspended, wake it up */
06490             if (num_requests_client && pclient[i].read_wait) {
06491                char str[80];
06492 #ifdef DEBUG_MSG
06493                cm_msg(MDEBUG, "Send wake: rp=%d, wp=%d", pheader->read_pointer, pheader->write_pointer);
06494 #endif
06495                sprintf(str, "B %s %d", pheader->name, request_id);
06496                ss_resume(pclient[i].port, str);
06497             }
06498 
06499             /* if that client has no request, shift its read pointer */
06500             if (num_requests_client == 0 && pclient[i].read_pointer == old_write_pointer)
06501                pclient[i].read_pointer = pheader->write_pointer;
06502          }
06503 
06504       /* shift read pointer of own client */
06505       if (pclient[my_client_index].read_pointer == old_write_pointer)
06506          pclient[my_client_index].read_pointer = pheader->write_pointer;
06507 
06508       /* calculate global read pointer as "minimum" of client read pointers */
06509 
06510       bm_update_read_pointer("bm_send_event", pheader);
06511 
06512       /* update statistics */
06513       pheader->num_in_events++;
06514 
06515       /* unlock the buffer */
06516       bm_unlock_buffer(buffer_handle);
06517    }
06518 #endif                          /* LOCAL_ROUTINES */
06519 
06520    return BM_SUCCESS;
06521 }

INT bm_set_cache_size ( INT  buffer_handle,
INT  read_size,
INT  write_size 
)

Modifies buffer cache size. Without a buffer cache, events are copied to/from the shared memory event by event.

To protect processed from accessing the shared memory simultaneously, semaphores are used. Since semaphore operations are CPU consuming (typically 50-100us) this can slow down the data transfer especially for small events. By using a cache the number of semaphore operations is reduced dramatically. Instead writing directly to the shared memory, the events are copied to a local cache buffer. When this buffer is full, it is copied to the shared memory in one operation. The same technique can be used when receiving events.

The drawback of this method is that the events have to be copied twice, once to the cache and once from the cache to the shared memory. Therefore it can happen that the usage of a cache even slows down data throughput on a given environment (computer type, OS type, event size). The cache size has therefore be optimized manually to maximize data throughput.

Parameters:
buffer_handle buffer handle obtained via bm_open_buffer()
read_size cache size for reading events in bytes, zero for no cache
write_size cache size for writing events in bytes, zero for no cache
Returns:
BM_SUCCESS, BM_INVALID_HANDLE, BM_NO_MEMORY, BM_INVALID_PARAM

Definition at line 5461 of file midas.c.

Referenced by register_equipment(), register_requests(), rpc_server_dispatch(), and tr_start().

05463 {
05464    if (rpc_is_remote())
05465       return rpc_call(RPC_BM_SET_CACHE_SIZE, buffer_handle, read_size, write_size);
05466 
05467 #ifdef LOCAL_ROUTINES
05468    {
05469       BUFFER *pbuf;
05470 
05471       if (buffer_handle > _buffer_entries || buffer_handle <= 0) {
05472          cm_msg(MERROR, "bm_set_cache_size", "invalid buffer handle %d", buffer_handle);
05473          return BM_INVALID_HANDLE;
05474       }
05475 
05476       if (!_buffer[buffer_handle - 1].attached) {
05477          cm_msg(MERROR, "bm_set_cache_size", "invalid buffer handle %d", buffer_handle);
05478          return BM_INVALID_HANDLE;
05479       }
05480 
05481       if (read_size < 0 || read_size > 1E6) {
05482          cm_msg(MERROR, "bm_set_cache_size", "invalid read chache size");
05483          return BM_INVALID_PARAM;
05484       }
05485 
05486       if (write_size < 0 || write_size > 1E6) {
05487          cm_msg(MERROR, "bm_set_cache_size", "invalid write chache size");
05488          return BM_INVALID_PARAM;
05489       }
05490 
05491       /* manage read cache */
05492       pbuf = &_buffer[buffer_handle - 1];
05493 
05494       if (pbuf->read_cache_size > 0)
05495          M_FREE(pbuf->read_cache);
05496 
05497       if (read_size > 0) {
05498          pbuf->read_cache = (char *) M_MALLOC(read_size);
05499          if (pbuf->read_cache == NULL) {
05500             cm_msg(MERROR, "bm_set_cache_size", "not enough memory to allocate cache buffer");
05501             return BM_NO_MEMORY;
05502          }
05503       }
05504 
05505       pbuf->read_cache_size = read_size;
05506       pbuf->read_cache_rp = pbuf->read_cache_wp = 0;
05507 
05508       /* manage write cache */
05509       if (pbuf->write_cache_size > 0)
05510          M_FREE(pbuf->write_cache);
05511 
05512       if (write_size > 0) {
05513          pbuf->write_cache = (char *) M_MALLOC(write_size);
05514          if (pbuf->write_cache == NULL) {
05515             cm_msg(MERROR, "bm_set_cache_size", "not enough memory to allocate cache buffer");
05516             return BM_NO_MEMORY;
05517          }
05518       }
05519 
05520       pbuf->write_cache_size = write_size;
05521       pbuf->write_cache_rp = pbuf->write_cache_wp = 0;
05522 
05523    }
05524 #endif                          /* LOCAL_ROUTINES */
05525 
05526    return BM_SUCCESS;
05527 }

INT bm_skip_event ( INT  buffer_handle  ) 

Skip all events in current buffer.

Useful for single event displays to see the newest events

Parameters:
buffer_handle Handle of the buffer. Must be obtained via bm_open_buffer.
Returns:
BM_SUCCESS, BM_INVALID_HANDLE, RPC_NET_ERROR

Definition at line 7023 of file midas.c.

Referenced by rpc_server_dispatch().

07024 {
07025    if (rpc_is_remote())
07026       return rpc_call(RPC_BM_SKIP_EVENT, buffer_handle);
07027 
07028 #ifdef LOCAL_ROUTINES
07029    {
07030       BUFFER *pbuf;
07031       BUFFER_HEADER *pheader;
07032       BUFFER_CLIENT *pclient;
07033 
07034       if (buffer_handle > _buffer_entries || buffer_handle <= 0) {
07035          cm_msg(MERROR, "bm_skip_event", "invalid buffer handle %d", buffer_handle);
07036          return BM_INVALID_HANDLE;
07037       }
07038 
07039       pbuf = &_buffer[buffer_handle - 1];
07040       pheader = pbuf->buffer_header;
07041 
07042       if (!pbuf->attached) {
07043          cm_msg(MERROR, "bm_skip_event", "invalid buffer handle %d", buffer_handle);
07044          return BM_INVALID_HANDLE;
07045       }
07046 
07047       /* clear cache */
07048       if (pbuf->read_cache_wp > pbuf->read_cache_rp)
07049          pbuf->read_cache_rp = pbuf->read_cache_wp = 0;
07050 
07051       bm_lock_buffer(buffer_handle);
07052 
07053       /* forward read pointer to global write pointer */
07054       pclient = pheader->client + bm_validate_client_index(pbuf);
07055       pclient->read_pointer = pheader->write_pointer;
07056 
07057       bm_unlock_buffer(buffer_handle);
07058    }
07059 #endif
07060 
07061    return BM_SUCCESS;
07062 }

static BOOL bm_update_read_pointer ( const char *  caller_name,
BUFFER_HEADER pheader 
) [static]

Definition at line 5951 of file midas.c.

Referenced by bm_flush_cache(), and bm_send_event().

05952 {
05953    BOOL did_move;
05954    int i;
05955    int min_rp;
05956    BUFFER_CLIENT *pclient;
05957 
05958    assert(caller_name);
05959    pclient = pheader->client;
05960 
05961    /* calculate global read pointer as "minimum" of client read pointers */
05962    min_rp = pheader->write_pointer;
05963 
05964    for (i = 0; i < pheader->max_client_index; i++)
05965       if (pclient[i].pid) {
05966 #ifdef DEBUG_MSG
05967          cm_msg(MDEBUG, caller_name, "bm_update_read_pointer: client %d rp=%d", i, pclient[i].read_pointer);
05968 #endif
05969          bm_validate_client_pointers(pheader, &pclient[i]);
05970 
05971          if (pheader->read_pointer <= pheader->write_pointer) {
05972             if (pclient[i].read_pointer < min_rp)
05973                min_rp = pclient[i].read_pointer;
05974          } else {
05975             if (pclient[i].read_pointer <= pheader->write_pointer) {
05976                if (pclient[i].read_pointer < min_rp)
05977                   min_rp = pclient[i].read_pointer;
05978             } else {
05979                int xptr = pclient[i].read_pointer - pheader->size;
05980                if (xptr < min_rp)
05981                   min_rp = xptr;
05982             }
05983          }
05984       }
05985 
05986    if (min_rp < 0)
05987       min_rp += pheader->size;
05988 
05989    assert(min_rp >= 0);
05990    assert(min_rp < pheader->size);
05991 
05992 #ifdef DEBUG_MSG
05993    if (min_rp == pheader->read_pointer)
05994       cm_msg(MDEBUG, caller_name, "bm_update_read_pointer -> wp=%d", pheader->write_pointer);
05995    else
05996       cm_msg(MDEBUG, caller_name, "bm_update_read_pointer -> wp=%d, rp %d -> %d, size=%d",
05997              pheader->write_pointer, pheader->read_pointer, min_rp, pheader->size);
05998 #endif
05999 
06000    did_move = (pheader->read_pointer != min_rp);
06001 
06002    pheader->read_pointer = min_rp;
06003 
06004    return did_move;
06005 }

static void bm_validate_client_pointers ( BUFFER_HEADER pheader,
BUFFER_CLIENT pclient 
) [static]

Definition at line 5887 of file midas.c.

Referenced by bm_update_read_pointer().

05888 {
05889    assert(pheader->read_pointer >= 0 && pheader->read_pointer <= pheader->size);
05890    assert(pclient->read_pointer >= 0 && pclient->read_pointer <= pheader->size);
05891 
05892    if (pheader->read_pointer <= pheader->write_pointer) {
05893 
05894       if (pclient->read_pointer < pheader->read_pointer) {
05895          cm_msg(MINFO, "bm_validate_client_pointers",
05896                 "Corrected read pointer for client \'%s\' on buffer \'%s\' from %d to %d", pclient->name,
05897                 pheader->name, pclient->read_pointer, pheader->read_pointer);
05898 
05899          pclient->read_pointer = pheader->read_pointer;
05900       }
05901 
05902       if (pclient->read_pointer > pheader->write_pointer) {
05903          cm_msg(MINFO, "bm_validate_client_pointers",
05904                 "Corrected read pointer for client \'%s\' on buffer \'%s\' from %d to %d", pclient->name,
05905                 pheader->name, pclient->read_pointer, pheader->write_pointer);
05906 
05907          pclient->read_pointer = pheader->write_pointer;
05908       }
05909 
05910    } else {
05911 
05912       if (pclient->read_pointer < 0) {
05913          cm_msg(MINFO, "bm_validate_client_pointers",
05914                 "Corrected read pointer for client \'%s\' on buffer \'%s\' from %d to %d", pclient->name,
05915                 pheader->name, pclient->read_pointer, pheader->read_pointer);
05916 
05917          pclient->read_pointer = pheader->read_pointer;
05918       }
05919 
05920       if (pclient->read_pointer >= pheader->size) {
05921          cm_msg(MINFO, "bm_validate_client_pointers",
05922                 "Corrected read pointer for client \'%s\' on buffer \'%s\' from %d to %d", pclient->name,
05923                 pheader->name, pclient->read_pointer, pheader->read_pointer);
05924 
05925          pclient->read_pointer = pheader->read_pointer;
05926       }
05927 
05928       if (pclient->read_pointer > pheader->write_pointer && pclient->read_pointer < pheader->read_pointer) {
05929          cm_msg(MINFO, "bm_validate_client_pointers",
05930                 "Corrected read pointer for client \'%s\' on buffer \'%s\' from %d to %d", pclient->name,
05931                 pheader->name, pclient->read_pointer, pheader->read_pointer);
05932 
05933          pclient->read_pointer = pheader->read_pointer;
05934       }
05935    }
05936 }

static int bm_wait_for_free_space ( int  buffer_handle,
BUFFER pbuf,
int  async_flag,
int  requested_space 
) [static]

Definition at line 6128 of file midas.c.

Referenced by bm_flush_cache(), and bm_send_event().

06129 {
06130    int status;
06131    BUFFER_HEADER *pheader = pbuf->buffer_header;
06132    char *pdata = (char *) (pheader + 1);
06133 
06134    /* make sure the buffer never completely full:
06135     * read pointer and write pointer would coincide
06136     * and the code cannot tell if it means the
06137     * buffer is 100% full or 100% empty. It will explode
06138     * or lose events */
06139    requested_space += 100;
06140 
06141    if (requested_space >= pheader->size)
06142       return BM_NO_MEMORY;
06143 
06144    while (1) {
06145 
06146       BUFFER_CLIENT *pc;
06147       int n_blocking;
06148       int i;
06149       int size;
06150 
06151       /* check if enough space in buffer */
06152 
06153       size = pheader->read_pointer - pheader->write_pointer;
06154       if (size <= 0)
06155          size += pheader->size;
06156 
06157 #if 0
06158       printf
06159           ("bm_send_event: buffer pointers: read: %d, write: %d, free space: %d, bufsize: %d, event size: %d\n",
06160            pheader->read_pointer, pheader->write_pointer, size, pheader->size, requested_space);
06161 #endif
06162 
06163       if (requested_space < size)       /* note the '<' to avoid 100% filling */
06164          return BM_SUCCESS;
06165 
06166       /* if not enough space, find out who's blocking */
06167       n_blocking = 0;
06168 
06169       for (i = 0, pc = pheader->client; i < pheader->max_client_index; i++, pc++)
06170          if (pc->pid) {
06171             if (pc->read_pointer == pheader->read_pointer) {
06172                /*
06173                   First assume that the client with the "minimum" read pointer
06174                   is not really blocking due to a GET_ALL request.
06175                 */
06176                BOOL blocking = FALSE;
06177                int blocking_request_id = 0;
06178                int j;
06179 
06180                /* check if this request blocks */
06181 
06182                EVENT_REQUEST *prequest = pc->event_request;
06183                EVENT_HEADER *pevent_test = (EVENT_HEADER *) (pdata + pc->read_pointer);
06184 
06185                assert(pc->read_pointer >= 0);
06186                assert(pc->read_pointer <= pheader->size);
06187 
06188                for (j = 0; j < pc->max_request_index; j++, prequest++)
06189                   if (prequest->valid
06190                       && bm_match_event(prequest->event_id, prequest->trigger_mask, pevent_test)) {
06191                      if (prequest->sampling_type & GET_ALL) {
06192                         blocking = TRUE;
06193                         blocking_request_id = prequest->id;
06194                         break;
06195                      }
06196                   }
06197 
06198                if (blocking) {
06199                   n_blocking++;
06200 
06201                   if (pc->read_wait) {
06202                      char str[80];
06203 #ifdef DEBUG_MSG
06204                      cm_msg(MDEBUG, "Send wake: rp=%d, wp=%d", pheader->read_pointer, pheader->write_pointer);
06205 #endif
06206                      sprintf(str, "B %s %d", pheader->name, blocking_request_id);
06207                      ss_resume(pc->port, str);
06208                   }
06209 
06210                } else {
06211                   /*
06212                      The blocking guy has no GET_ALL request for this event
06213                      -> shift its read pointer.
06214                    */
06215 
06216                   int new_read_pointer;
06217                   int increment =
06218                       sizeof(EVENT_HEADER) + ((EVENT_HEADER *) (pdata + pc->read_pointer))->data_size;
06219 
06220                   /* correct increment for DWORD boundary */
06221                   increment = ALIGN8(increment);
06222 
06223                   assert(increment > 0);
06224                   assert(increment <= pheader->size);
06225 
06226                   new_read_pointer = (pc->read_pointer + increment) % pheader->size;
06227 
06228                   if (new_read_pointer > pheader->size - (int) sizeof(EVENT_HEADER))
06229                      new_read_pointer = 0;
06230 
06231                   pc->read_pointer = new_read_pointer;
06232                }
06233             }
06234          }
06235       /* client loop */
06236       if (n_blocking == 0) {
06237 
06238          BOOL moved;
06239          /*
06240             calculate new global read pointer as "minimum" of
06241             client read pointers
06242           */
06243 
06244          moved = bm_update_read_pointer("bm_send_event", pheader);
06245 
06246          if (!moved) {
06247             cm_msg(MERROR, "bm_wait_for_free_space",
06248                    "BUG: read pointer did not move while waiting for %d bytes, bytes available: %d, buffer size: %d",
06249                    requested_space, size, pheader->size);
06250             return BM_NO_MEMORY;
06251          }
06252 
06253          continue;
06254       }
06255 
06256       /* at least one client is blocking */
06257 
06258       bm_unlock_buffer(buffer_handle);
06259 
06260       /* return now in ASYNC mode */
06261       if (async_flag)
06262          return BM_ASYNC_RETURN;
06263 
06264 #ifdef DEBUG_MSG
06265       cm_msg(MDEBUG, "Send sleep: rp=%d, wp=%d, level=%1.1lf",
06266              pheader->read_pointer, pheader->write_pointer, 100 - 100.0 * size / pheader->size);
06267 #endif
06268 
06269       /* signal other clients wait mode */
06270       pheader->client[bm_validate_client_index(pbuf)].write_wait = requested_space;
06271 
06272       bm_cleanup("bm_wait_for_free_space", ss_millitime(), FALSE);
06273 
06274       status = ss_suspend(1000, MSG_BM);
06275 
06276       /* make sure we do sleep in this loop:
06277        * if we are the mserver receiving data on the event
06278        * socket and the data buffer is full, ss_suspend() will
06279        * never sleep: it will detect data on the event channel,
06280        * call rpc_server_receive() (recursively, we already *are* in
06281        * rpc_server_receive()) and return without sleeping. Result
06282        * is a busy loop waiting for free space in data buffer */
06283       if (status != SS_TIMEOUT)
06284          ss_sleep(10);
06285 
06286       /* validate client index: we could have been removed from the buffer */
06287       pheader->client[bm_validate_client_index(pbuf)].write_wait = 0;
06288 
06289       /* return if TCP connection broken */
06290       if (status == SS_ABORT)
06291          return SS_ABORT;
06292 
06293 #ifdef DEBUG_MSG
06294       cm_msg(MDEBUG, "Send woke up: rp=%d, wp=%d, level=%1.1lf",
06295              pheader->read_pointer, pheader->write_pointer, 100 - 100.0 * size / pheader->size);
06296 #endif
06297 
06298       bm_lock_buffer(buffer_handle);
06299    }
06300 }

static void bm_wakeup_producers ( const BUFFER_HEADER pheader,
const BUFFER_CLIENT pc 
) [static]

Definition at line 6007 of file midas.c.

06008 {
06009    int i;
06010    int size;
06011    const BUFFER_CLIENT *pctmp = pheader->client;
06012 
06013    /*
06014       If read pointer has been changed, it may have freed up some space
06015       for waiting producers. So check if free space is now more than 50%
06016       of the buffer size and wake waiting producers.
06017     */
06018 
06019    size = pc->read_pointer - pheader->write_pointer;
06020    if (size <= 0)
06021       size += pheader->size;
06022 
06023    if (size >= pheader->size * 0.5)
06024       for (i = 0; i < pheader->max_client_index; i++, pctmp++)
06025         if (pctmp->pid)
06026            if (pctmp->write_wait < size) {
06027 #ifdef DEBUG_MSG
06028             cm_msg(MDEBUG, "Receive wake: rp=%d, wp=%d, level=%1.1lf",
06029                    pheader->read_pointer, pheader->write_pointer, 100 - 100.0 * size / pheader->size);
06030 #endif
06031             ss_resume(pctmp->port, "B  ");
06032             }
06033 }


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