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 () |
INT bm_check_buffers | ( | ) |
Check if any requested event is waiting in a buffer
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 }
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
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 }
Closes an event buffer previously opened with bm_open_buffer().
buffer_handle | buffer 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)) = <...>
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 |
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 }
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
request_id | request identifier given by bm_request_event() |
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.
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 }
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.
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. |
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
event_id | Event ID of request | |
trigger_mask | Trigger mask of request | |
pevent | Pointer to event to check |
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 }
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; }
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 |
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.
buffer_name | Name of buffer |
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 }
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; }
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. |
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 }
Delete a previously placed request for a specific event type in the client structure of the buffer refereced by buffer_handle.
buffer_handle | Handle to the buffer where the re- quest should be placed in | |
request_id | Request id returned by bm_request_event |
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()
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. |
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 }
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; }
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 |
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 }
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.
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 |
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 }
Skip all events in current buffer.
Useful for single event displays to see the newest events
buffer_handle | Handle of the buffer. Must be obtained via bm_open_buffer. |
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 }