/* * QBufPipe_Finish * * Blocks until the reader thread handles all commands * or terminates with an error. */ void QBufPipe_Finish( qbufPipe_t *pipe ) { while( Sys_Atomic_CAS( &pipe->cmdbuf_len, 0, 0, pipe->cmdbuf_mutex ) == false && !pipe->terminated ) { QMutex_Lock( pipe->nonempty_mutex ); QBufPipe_Wake( pipe ); QMutex_Unlock( pipe->nonempty_mutex ); QThread_Yield(); } }
/* * QBufPipe_WriteCmd * * Add new command to buffer. Never allow the distance between the reader * and the writer to grow beyond the size of the buffer. * * Note that there are race conditions here but in the worst case we're going * to erroneously drop cmd's instead of stepping on the reader's toes. */ void QBufPipe_WriteCmd( qbufPipe_t *pipe, const void *cmd, unsigned cmd_size ) { void *buf; unsigned write_remains; bool was_empty; if( !pipe ) { return; } if( pipe->terminated ) { return; } assert( pipe->bufSize >= pipe->write_pos ); if( pipe->bufSize < pipe->write_pos ) { pipe->write_pos = 0; } was_empty = Sys_Atomic_CAS( &pipe->cmdbuf_len, 0, 0, pipe->cmdbuf_mutex ) == true; write_remains = pipe->bufSize - pipe->write_pos; if( sizeof( int ) > write_remains ) { while( pipe->cmdbuf_len + cmd_size + write_remains > pipe->bufSize ) { if( pipe->blockWrite ) { QThread_Yield(); continue; } return; } // not enough space to enpipe even the reset cmd, rewind QBufPipe_BufLenAdd( pipe, write_remains ); // atomic pipe->write_pos = 0; } else if( cmd_size > write_remains ) { int *cmd; while( pipe->cmdbuf_len + sizeof( int ) + cmd_size + write_remains > pipe->bufSize ) { if( pipe->blockWrite ) { QThread_Yield(); continue; } return; } // explicit pointer reset cmd cmd = QBufPipe_AllocCmd( pipe, sizeof( int ) ); *cmd = -1; QBufPipe_BufLenAdd( pipe, sizeof( *cmd ) + write_remains ); // atomic pipe->write_pos = 0; } else { while( pipe->cmdbuf_len + cmd_size > pipe->bufSize ) { if( pipe->blockWrite ) { QThread_Yield(); continue; } return; } } buf = QBufPipe_AllocCmd( pipe, cmd_size ); memcpy( buf, cmd, cmd_size ); QBufPipe_BufLenAdd( pipe, cmd_size ); // atomic // wake the other thread waiting for signal if( was_empty ) { QMutex_Lock( pipe->nonempty_mutex ); QBufPipe_Wake( pipe ); QMutex_Unlock( pipe->nonempty_mutex ); } }