/* Copyright (c) 2001, Stanford University
* All rights reserved
*
* See the file LICENSE.txt for information on redistributing this software.
*/
#include "server_dispatch.h"
#include "server.h"
#include "cr_error.h"
#include "cr_mem.h"
#include "state/cr_statetypes.h"
#define DEBUG_BARRIERS 1
void SERVER_DISPATCH_APIENTRY crServerDispatchBarrierCreateCR( GLuint name, GLuint count )
{
CRServerBarrier *barrier;
#if DEBUG_BARRIERS
char debug_buf[4096];
#endif
if (cr_server.ignore_papi)
{
cr_server.head_spu->dispatch_table.BarrierCreateCR( name, count );
return;
}
barrier = (CRServerBarrier *) crHashtableSearch( cr_server.barriers, name );
#if DEBUG_BARRIERS
sprintf( debug_buf, "BarrierCreateCR( %d, %d )", name, count );
cr_server.head_spu->dispatch_table.ChromiumParametervCR( GL_PRINT_STRING_CR, GL_UNSIGNED_BYTE, sizeof(debug_buf), debug_buf );
#endif
if (count == 0)
{
count = cr_server.numClients;
#if DEBUG_BARRIERS
sprintf( debug_buf, "changing count to %d", count );
cr_server.head_spu->dispatch_table.ChromiumParametervCR( GL_PRINT_STRING_CR, GL_UNSIGNED_BYTE, sizeof(debug_buf), debug_buf );
#endif
}
/* we use maxBarrierCount in Clear() and SwapBuffers() and also use it
* in __getNextClient() for deadlock detection. The issue is that all
* the existing clients may be blocked, but we might soon get another
* client connection to break the apparent deadlock.
*/
if (count > cr_server.maxBarrierCount)
cr_server.maxBarrierCount = count;
if ( barrier == NULL )
{
barrier = (CRServerBarrier *) crAlloc( sizeof(*barrier) );
barrier->count = count;
barrier->num_waiting = 0;
barrier->waiting = (RunQueue **)
crAlloc( count * sizeof(*(barrier->waiting)) );
crHashtableAdd( cr_server.barriers, name, barrier );
#if DEBUG_BARRIERS
sprintf( debug_buf, "This was a new barrier!" );
cr_server.head_spu->dispatch_table.ChromiumParametervCR( GL_PRINT_STRING_CR, GL_UNSIGNED_BYTE, sizeof(debug_buf), debug_buf );
#endif
}
else
{
/* HACK -- this allows everybody to create a barrier, and all
but the first creation are ignored, assuming the count
match. */
#if DEBUG_BARRIERS
sprintf( debug_buf, "I already knew about this barrier." );
cr_server.head_spu->dispatch_table.ChromiumParametervCR( GL_PRINT_STRING_CR, GL_UNSIGNED_BYTE, sizeof(debug_buf), debug_buf );
#endif
if ( barrier->count != count )
{
#if DEBUG_BARRIERS
sprintf( debug_buf, "And someone messed up the count!." );
cr_server.head_spu->dispatch_table.ChromiumParametervCR( GL_PRINT_STRING_CR, GL_UNSIGNED_BYTE, sizeof(debug_buf), debug_buf );
#endif
crError( "Barrier name=%u created with count=%u, but already "
"exists with count=%u", name, count, barrier->count );
}
}
if (cr_server.debug_barriers)
crDebug("crserver: BarrierCreate(id=%d, count=%d)", name, barrier->count);
}
void SERVER_DISPATCH_APIENTRY crServerDispatchBarrierDestroyCR( GLuint name )
{
if (cr_server.ignore_papi)
{
cr_server.head_spu->dispatch_table.BarrierDestroyCR( name );
return;
}
crError( "NO BARRIER DESTROY FOR YOU! (name=%u)", name );
}
void SERVER_DISPATCH_APIENTRY crServerDispatchBarrierExecCR( GLuint name )
{
CRServerBarrier *barrier;
#if DEBUG_BARRIERS
char debug_buf[4096];
#endif
if (cr_server.ignore_papi)
{
cr_server.head_spu->dispatch_table.BarrierExecCR( name );
return;
}
barrier = (CRServerBarrier *) crHashtableSearch( cr_server.barriers, name );
if ( barrier == NULL )
{
crError( "crServerDispatchBarrierExec: No such barrier: %d", name );
}
#if DEBUG_BARRIERS
sprintf( debug_buf, "BarrierExec( %d )", name );
cr_server.head_spu->dispatch_table.ChromiumParametervCR( GL_PRINT_STRING_CR, GL_UNSIGNED_BYTE, sizeof(debug_buf), debug_buf );
sprintf( debug_buf, "num_waiting = %d", barrier->num_waiting );
cr_server.head_spu->dispatch_table.ChromiumParametervCR( GL_PRINT_STRING_CR, GL_UNSIGNED_BYTE, sizeof(debug_buf), debug_buf );
#endif
barrier->waiting[barrier->num_waiting++] = cr_server.run_queue;
cr_server.run_queue->blocked = 1;
if ( barrier->num_waiting == barrier->count )
{
GLuint i;
if (cr_server.debug_barriers)
crDebug("crserver: BarrierExec(client=%p, id=%d, num_waiting=%d/%d) - release",
cr_server.curClient, name, barrier->num_waiting,
barrier->count);
for ( i = 0; i < barrier->count; i++ )
{
barrier->waiting[i]->blocked = 0;
}
barrier->num_waiting = 0;
}
else if (cr_server.debug_barriers)
crDebug("crserver: BarrierExec(client=%p, id=%d, num_waiting=%d/%d) - block",
cr_server.curClient, name, barrier->num_waiting,
barrier->count);
}
void SERVER_DISPATCH_APIENTRY crServerDispatchSemaphoreCreateCR( GLuint name, GLuint count )
{
CRServerSemaphore *sema;
if (cr_server.ignore_papi)
{
cr_server.head_spu->dispatch_table.SemaphoreCreateCR( name, count );
return;
}
sema = crHashtableSearch(cr_server.semaphores, name);
if (sema)
return; /* already created */
sema = (CRServerSemaphore *) crAlloc( sizeof( *sema ) );
crHashtableAdd( cr_server.semaphores, name, sema );
sema->count = count;
sema->waiting = sema->tail = NULL;
if (cr_server.debug_barriers)
crDebug("crserver: SemaphoreCreate(id=%d, count=%d)", name, count);
}
void SERVER_DISPATCH_APIENTRY crServerDispatchSemaphoreDestroyCR( GLuint name )
{
if (cr_server.ignore_papi)
{
cr_server.head_spu->dispatch_table.SemaphoreDestroyCR( name );
return;
}
crError( "NO DESTROY FOR YOU! (name=%u)", name );
}
/* Semaphore wait */
void SERVER_DISPATCH_APIENTRY crServerDispatchSemaphorePCR( GLuint name )
{
CRServerSemaphore *sema;
if (cr_server.ignore_papi)
{
cr_server.head_spu->dispatch_table.SemaphorePCR( name );
return;
}
sema = (CRServerSemaphore *) crHashtableSearch( cr_server.semaphores, name );
if (!sema)
{
crError( "No such semaphore: %d", name );
}
if (sema->count)
{
/* go */
if (cr_server.debug_barriers)
crDebug("crserver: SemaphoreP(client=%p, id=%d, count=%d) decrement to %d",
cr_server.curClient, name, sema->count, sema->count - 1);
sema->count--;
}
else
{
/* block */
wqnode *node;
if (cr_server.debug_barriers)
crDebug("crserver: SemaphoreP(client=%p, id=%d, count=%d) - block.",
cr_server.curClient, name, sema->count);
cr_server.run_queue->blocked = 1;
node = (wqnode *) crAlloc( sizeof( *node ) );
node->q = cr_server.run_queue;
node->next = NULL;
if (sema->tail)
{
sema->tail->next = node;
}
else
{
sema->waiting = node;
}
sema->tail = node;
}
}
/* Semaphore signal */
void SERVER_DISPATCH_APIENTRY crServerDispatchSemaphoreVCR( GLuint name )
{
CRServerSemaphore *sema;
if (cr_server.ignore_papi)
{
cr_server.head_spu->dispatch_table.SemaphoreVCR( name );
return;
}
sema = (CRServerSemaphore *) crHashtableSearch( cr_server.semaphores, name );
if (!sema)
{
crError( "No such semaphore: %d", name );
}
if (sema->waiting)
{
wqnode *temp = sema->waiting;
if (cr_server.debug_barriers)
crDebug("crserver: SemaphoreV(client=%p, id=%d, count=%d) - unblock.",
cr_server.curClient, name, sema->count);
/* unblock one waiter */
temp->q->blocked = 0;
sema->waiting = temp->next;
crFree( temp );
if (!sema->waiting)
{
sema->tail = NULL;
}
}
else
{
/* nobody's waiting */
if (cr_server.debug_barriers)
crDebug("crserver: SemaphoreV(client=%p, id=%d, count=%d) - increment to %d",
cr_server.curClient, name, sema->count, sema->count + 1);
sema->count++;
}
}