/* ** DPI blocking pipes for messages of arbitrary size. ** ** Copyright (C) 2006 Zaiq Technologies, Inc. All Rights Reserved. ** ** Author: Per Bojsen ** ** Filename: dpi_pipes_nobuflimit_sysc.cxx ** ** Created: Tue Mar 21 21:19:19 EST 2006 ** ** Note: This code is an example of DPI blocking pipes implementation ** that allows messages to be any size, i.e., not limited by the ** buffer size in the underlying non-blocking calls. ** ** $Id$ ** */ #include "svdpi.h" #include "dpi_pipes.h" // NOTE: This is a newly proposed function. It is not yet included in // dpi_pipes.h. extern "C" int dpi_pipe_c_get_depth(void *pipe_handle); // // dpi_pipe_c_send_nl() is based on John Stickley's version. The comment // below is John's. // // This is the no limit blocking send function for the C endpoint of a // transaction input pipe. It handles messages of any size regardless // of the pipe buffer depth setting. Messages larger than the pipe // buffer can handle will be segmented into chunks that are less than // or equal to the pipe buffer size. Each of these segments will be // sent with the dpi_pipe_c_send() function. // // This code shows how this function can be implemented at the application // layer assuming we adopt the dpi_pipe_c_get_depth() function. Even though // this is possible this does not necessarily imply that it is not desirable // to include this functionality in the interface. // void dpi_pipe_c_send_nl(void *pipe_handle, // in: pipe handle int bytes_per_element, // in: #bytes/element int num_elements, // in: #elems to write const svBitVecVal *data, // in: data svBit eom) // in: end-of-message { unsigned pipeDepth = dpi_pipe_c_get_depth(pipe_handle); unsigned elementsRemaining = bytes_per_element; if (elementsRemaining <= pipeDepth) { // If transfer size is less than pipe depth // dpi_pipe_c_send() can handle it directly. dpi_pipe_c_send(pipe_handle, bytes_per_element, num_elements, data, eom); } else if (pipeDepth >= 4) { // If pipe depth is greater than or equal to 4 elements we can // always come up with a transfer size that is an integer multiple // of 4 elements. Integer multiples of 4 elements have the property // that they will always consist of an integer number of svBitVecVal // words, i.e., one can trivially get a pointer to the next segment of // data to be transferred. const svBitVecVal *dataP = data; unsigned pipeDepthAdj = pipeDepth & ~0x3; // Round down to nearest // multiple of 4. unsigned bitVecValWordsPerSegment = (pipeDepthAdj / 4) * bytes_per_element; // Transfer segments of the message until it is complete. Each // segment is less than or equal to the pipe depth in size. Hence // dpi_pipe_c_send() can handle each segment directly. while (elementsRemaining > 0) { int elemsToTransfer = elementsRemaining < pipeDepthAdj ? elementsRemaining : pipeDepthAdj; int lastSegment = elementsRemaining < pipeDepthAdj ? 1 : 0; // Transfer segment. Take care to ensure the eom flag is only // valid on the last transfer as it is tied to the last element // of the message. dpi_pipe_c_send(pipe_handle, bytes_per_element, elemsToTransfer, dataP, lastSegment ? eom : 0); // Advance data pointer to the start of the next segment. dataP += bitVecValWordsPerSegment; elementsRemaining -= elemsToTransfer; } } else { // This case is nasty. Since the pipe depth is less than 4 // elements we cannoot guarantee that we can find a segment size // that consists of an integer multiple of svBitVecVal words. We // transfer segments of maximum size, i.e., pipe depth. The data // is copied to a locally allocated buffer and realigned using the // svGetPartSelBit() function. // Bytes per segment. unsigned bytesPerSegment = pipeDepth * bytes_per_element; // Number of svBitVecVal words per segment. Note that we round up // here as the last svBitVecVal word may be fractional. unsigned bitVecValWordsPerSegment = (bytesPerSegment + sizeof(svBitVecVal)) / sizeof(svBitVecVal); unsigned bytesInLastWord = bytesPerSegment % sizeof(svBitVecVal); // Allocate buffer for segment data. Note in a real // implementation this should be done somewhere else as part of // initialization rather than on the fly. One good place to do // this is in the data structures stored off of the pipe handle. svBitVecVal *segmentData = new svBitVecVal[bitVecValWordsPerSegment]; svBitVecVal *segmentDataP = segmentData; // Current bit offset in data buffer. Used by svGetPartSelBit() // function. unsigned bitOffset = 0; // Transfer segments of the message until it is complete. Each // segment is less than or equal to the pipe depth in size. Hence // dpi_pipe_c_send() can handle each segment directly. while (elementsRemaining > 0) { int elemsToTransfer = elementsRemaining < pipeDepth ? elementsRemaining : pipeDepth; int lastSegment = elementsRemaining < pipeDepth ? 1 : 0; unsigned i; // Recalculate bitVecValWordsPerSegment and bytesInLastWord for // the last segment. Since this is the last segment and the // loop will exit after this, we do not need to retain the // original values of these variables. if (elemsToTransfer < (int) pipeDepth) { bytesPerSegment = elemsToTransfer * bytes_per_element; bitVecValWordsPerSegment = (bytesPerSegment + sizeof(svBitVecVal)) / sizeof(svBitVecVal); bytesInLastWord = bytesPerSegment % sizeof(svBitVecVal); } // Copy all words of segment data except the last one which may // be partial. for (i = 0; i < bitVecValWordsPerSegment - 1; i++, bitOffset += 8 * sizeof(svBitVecVal)) { svGetPartselBit(segmentDataP++, data, bitOffset, 8 * sizeof (svBitVecVal)); } // Handle last word of segment data here. svGetPartselBit(segmentDataP, data, bitOffset, 8 * bytesInLastWord); // Transfer segment. Take care to ensure the eom flag is only // valid on the last transfer as it is tied to the last element // of the message. dpi_pipe_c_send(pipe_handle, bytes_per_element, elemsToTransfer, segmentData, lastSegment ? eom : 0); // Keep track of elements transferred. elementsRemaining -= elemsToTransfer; } delete [] segmentData; } } /* dpi_pipe_c_send_nl */ /* ** Local Variables: ** tab-width: 8 ** End: */ /* ** End of file dpi_pipes_nobuflimit_sysc.cxx. */