Exemplo n.º 1
0
/*
* QBufPipe_Wait
*/
void QBufPipe_Wait( qbufPipe_t *pipe, int (*read)( qbufPipe_t *, unsigned( ** )(const void *), bool ), 
	unsigned (**cmdHandlers)( const void * ), unsigned timeout_msec )
{
	while( !pipe->terminated ) {
		int res;
		bool result = false;

		while( Sys_Atomic_CAS( &pipe->cmdbuf_len, 0, 0, pipe->cmdbuf_mutex ) == true ) {
			QMutex_Lock( pipe->nonempty_mutex );

			result = QCondVar_Wait( pipe->nonempty_condvar, pipe->nonempty_mutex, timeout_msec );

			// don't hold the mutex, changes to cmdbuf_len are atomic anyway
			QMutex_Unlock( pipe->nonempty_mutex );
			break;
		}

		// we're guaranteed at this point that either cmdbuf_len is > 0
		// or that waiting on the condition variable has timed out
		res = read( pipe, cmdHandlers, result );
		if( res < 0 ) {
			// done
			return;
		}
	}
}
Exemplo n.º 2
0
/*
* 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();
	}
}
Exemplo n.º 3
0
/*
* QBufPipe_ReadCmds
*/
int QBufPipe_ReadCmds( qbufPipe_t *pipe, unsigned (**cmdHandlers)( const void * ) )
{
	int read = 0;

	if( !pipe ) {
		return -1;
	}

	while( Sys_Atomic_CAS( &pipe->cmdbuf_len, 0, 0, pipe->cmdbuf_mutex ) == false && !pipe->terminated ) {
		int cmd;
		int cmd_size;
		int read_remains;
	
		assert( pipe->bufSize >= pipe->read_pos );
		if( pipe->bufSize < pipe->read_pos ) {
			pipe->read_pos = 0;
		}

		read_remains = pipe->bufSize - pipe->read_pos;

		if( sizeof( int ) > read_remains ) {
			// implicit reset
			pipe->read_pos = 0;
			QBufPipe_BufLenAdd( pipe, -read_remains );
		}

		cmd = *((int *)(pipe->buf + pipe->read_pos));
		if( cmd == -1 ) {
			// this cmd is special
			pipe->read_pos = 0;
			QBufPipe_BufLenAdd( pipe, -((int)(sizeof(int) + read_remains)) ); // atomic
			continue;
		}

		cmd_size = cmdHandlers[cmd](pipe->buf + pipe->read_pos);
		read++;

		if( !cmd_size ) {
			pipe->terminated = 1;
			return -1;
		}
		
		if( cmd_size > pipe->cmdbuf_len ) {
			assert( 0 );
			pipe->terminated = 1;
			return -1;
		}

		pipe->read_pos += cmd_size;
		QBufPipe_BufLenAdd( pipe, -cmd_size ); // atomic
		break;
	}

	return read;
}
Exemplo n.º 4
0
/*
* 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 );
	}
}
Exemplo n.º 5
0
/*
* QAtomic_CAS
*/
bool QAtomic_CAS( volatile int *value, int oldval, int newval, qmutex_t *mutex ) {
	return Sys_Atomic_CAS( value, oldval, newval, mutex );
}