server_stream.c revision b33adb47420a64d534fc2e956e6db5ba363bcb3f
/* Copyright (c) 2001, Stanford University
* All rights reserved
*
* See the file LICENSE.txt for information on redistributing this software.
*/
#include "server.h"
#include "cr_unpack.h"
#include "cr_error.h"
#include "cr_mem.h"
#include "server_dispatch.h"
/**
* Accept a new client connection, create a new CRClient and add to run queue.
*/
void
crServerAddNewClient(void)
{
if (newClient) {
/* add to array */
}
}
/**
* Check if client is in the run queue.
*/
static GLboolean
{
while (q) {
return 1;
}
q = q->next;
return 0; /* back head */
}
return 0;
}
#if 0
static int
PrintQueue(void)
{
int count = 0;
crDebug("Queue entries:");
while (q) {
count++;
q = q->next;
return count;
}
return count;
}
#endif
{
#ifdef VBOX_WITH_CRHGSMI
#endif
/* give this client a unique number if needed */
}
if (FindClientInQueue(client)) {
}
q->blocked = 0;
{
/* adding to empty queue */
q->next = q;
q->prev = q;
}
else
{
/* insert in doubly-linked list */
}
}
{
/* Destroy any windows created by the client */
{
{
}
}
/* Check if we have context(s) made by this client left, could happen if client side code is lazy */
{
{
}
}
}
{
while (pNode)
{
{
{
}
else
{
}
{
}
}
else
{
}
}
}
void
{
int i, j;
int cleanup=1;
#if 0
crDebug("Delay destroying client: message still pending");
return;
}
#endif
if (!FindClientInQueue(client)) {
/* this should never happen */
}
/* remove from clients[] array */
for (i = 0; i < cr_server.numClients; i++) {
/* found it */
break;
}
}
/* check if there're any other guest threads in same process */
for (i=0; i < cr_server.numClients; i++)
{
{
cleanup=0;
break;
}
}
if (cleanup)
{
}
/* remove from the run queue */
{
do {
{
/* this test seems a bit excessive */
{
crFree(q);
crDebug("Last client deleted - empty run queue.");
}
else
{
/* remove from doubly linked list and free the node */
crFree(q);
}
break;
}
q = q->next;
} while (q != qStart);
}
if (cleanup)
{
}
else
{
if (!pNode)
{
crWarning("Not enough memory, forcing client cleanup");
return;
}
}
if (!cr_server.numClients)
{
/* if no clients, the guest driver may be unloaded,
* and thus the visible regions situation might not be under control anymore,
* so cleanup the 3D framebuffer data here
* @todo: what really should happen is that guest driver on unload
* posts some request to host that would copy the current framebuffer 3D data to the 2D buffer
* (i.e. to the memory used by the standard IFramebuffer API) */
{
if (RT_SUCCESS(rc))
{
}
else
}
}
}
/**
* This is used to test if we can advance to the next client.
* \return GL_TRUE if so, GL_FALSE otherwise.
*/
{
if (client->currentCtxInfo
return GL_TRUE;
}
else {
return GL_FALSE;
}
}
/**
* Find the next client in the run queue that's not blocked and has a
* waiting message.
* Check if all clients are blocked (on barriers, semaphores), if so we've
* deadlocked!
* If no clients have a waiting message, call crNetRecv to get something
* if 'block' is true, else return NULL if 'block' if false.
*/
static RunQueue *
{
while (1)
{
{
/* check if this client's connection has gone away */
{
}
/* empty queue */
return NULL;
}
/* We _must_ service this client and no other.
* If we've got a message waiting on this client's connection we'll
* service it. Else, return NULL.
*/
else
return NULL;
}
/* loop over entries in run queue, looking for next one that's ready */
{
{
}
{
/* OK, this client isn't blocked and has a queued message */
}
}
if (all_blocked)
{
crError( "crserver: DEADLOCK! (numClients=%d, all blocked)",
crError("Waiting for more clients!!!");
crNetRecv();
}
}
}
}
if (!block)
return NULL;
/* no one had any work, get some! */
crNetRecv();
} /* while */
/* UNREACHED */
/* return NULL; */
}
typedef struct CR_SERVER_PENDING_MSG
{
{
if (!cbMsg)
{
WARN(("cbMsg is null!"));
return VERR_INVALID_PARAMETER;
}
if (!pMsg)
{
WARN(("RTMemAlloc failed"));
return VERR_NO_MEMORY;
}
return VINF_SUCCESS;
}
{
int i, rc;
for (i = 0; i < cr_server.numClients; i++)
{
{
WARN(("invalid client state"));
continue;
}
continue;
{
}
}
return VINF_SUCCESS;
}
{
int rc;
return VINF_SUCCESS;
if (!u32)
return VINF_SUCCESS;
do {
for(;;)
{
if (!u32)
break;
if (!pMsg)
{
WARN(("RTMemAlloc failed"));
return VERR_NO_MEMORY;
}
}
} while (u32);
return VINF_SUCCESS;
}
{
{
const CRMessageOpcodes *msg_opcodes;
int opcodeBytes;
const char *data_ptr;
}
}
/**
* This function takes the given message (which should be a buffer of
* rendering commands) and executes it.
*/
static void
{
const CRMessageOpcodes *msg_opcodes;
int opcodeBytes;
const char *data_ptr;
#ifdef VBOX_WITH_CRHGSMI
#endif
bool fUnpack = true;
{
#ifdef VBOX_WITH_CRHGSMI
#endif
}
#ifdef VBOXCR_LOGFPS
CRASSERT(cr_server.curClient && cr_server.curClient->conn && cr_server.curClient->conn->id == msg->header.conn_id);
#endif
switch (enmType)
{
{
break;
{
fUnpack = false;
break;
}
WARN(("crServerPendMsg failed"));
break;
}
{
{
{
fUnpack = false;
break;
}
else
WARN(("crServerPendMsg failed"));
}
else
WARN(("Pend List is NOT empty, drain the current list, and ignore this command"));
break;
}
{
break;
}
default:
WARN(("unsupported buffer type"));
break;
}
if (fUnpack)
{
}
#ifdef VBOX_WITH_CRHGSMI
if (pCmdData)
{
int rc = VINF_SUCCESS;
{
}
}
#endif
}
typedef enum
{
} ClientStatus;
/**
* CLIENT_NEXT if we can advance to the next client
* CLIENT_MORE if we have to process more messages for this client.
*/
static ClientStatus
{
/* set current client pointer */
/* service current client as long as we can */
crNetNumMessages(conn) > 0) {
unsigned int len;
/*
crDebug("%d messages on %p",
crNetNumMessages(conn), (void *) conn);
*/
/* Don't use GetMessage, because we want to do our own crNetRecv() calls
* here ourself.
* Note that crNetPeekMessage() DOES remove the message from the queue
* if there is one.
*/
crError( "SPU %d sent me CRAP (type=0x%x)",
}
/* Do the context switch here. No sense in switching before we
* really have any work to process. This is a no-op if we're
* not really switching contexts.
*
* XXX This isn't entirely sound. The crStateMakeCurrent() call
* will compute the state difference and dispatch it using
* the head SPU's dispatch table.
*
* This is a problem if this is the first buffer coming in,
* and the head SPU hasn't had a chance to do a MakeCurrent()
* yet (likely because the MakeCurrent() command is in the
* buffer itself).
*
* At best, in this case, the functions are no-ops, and
* are essentially ignored by the SPU. In the typical
* case, things aren't too bad; if the SPU just calls
* crState*() functions to update local state, everything
* will work just fine.
*
* In the worst (but unusual) case where a nontrivial
* SPU is at the head of a crserver's SPU chain (say,
* in a multiple-tiered "tilesort" arrangement, as
* seen in the "multitilesort.conf" configuration), the
* SPU may rely on state set during the MakeCurrent() that
* may not be present yet, because no MakeCurrent() has
* yet been dispatched.
*
* This headache will have to be revisited in the future;
* for now, SPUs that could head a crserver's SPU chain
* will have to detect the case that their functions are
* being called outside of a MakeCurrent(), and will have
* to handle the situation gracefully. (This is currently
* the case with the "tilesort" SPU.)
*/
#if 0
#else
/* Check if the current window is the one that the client wants to
* draw into. If not, dispatch a MakeCurrent to activate the proper
* window.
*/
/*
CRASSERT(cr_server.currentWindow == clientWindow);
*/
}
}
#endif
/* Force scissor, viewport and projection matrix update in
* crServerSetOutputBounds().
*/
cr_server.currentSerialNo = 0;
/* Commands get dispatched here */
* glEndList pair at this time!
*/
CRASSERT(0);
return CLIENT_NEXT;
}
} /* while */
/*
* Check if client/connection is gone
*/
return CLIENT_GONE;
}
/*
* Determine if we can advance to next client.
* list we can't service another client until we're done with the
*/
/* The next message has to come from the current client's connection. */
return CLIENT_MORE;
}
else {
/* get next client */
return CLIENT_NEXT;
}
}
/**
* Check if any of the clients need servicing.
* If so, service one client and return.
* Else, just return.
*/
void
crServerServiceClients(void)
{
RunQueue *q;
while (q)
{
/* advance to next client */
}
q = getNextClient(GL_FALSE);
}
}
/**
* Main crserver loop. Service connections from all connected clients.
* XXX add a config option to specify whether the crserver
* should exit when there's no more clients.
*/
void
{
/*MSG msg;*/
{
/*if (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
{
if (msg.message == WM_QUIT)
{
PostQuitMessage((int)msg.wParam);
break;
}
TranslateMessage( &msg );
DispatchMessage( &msg );
}*/
}
}
/**
* This will be called by the network layer when it's received a new message.
*/
int
{
(void) len;
{
/* Called when using multiple threads */
case CR_MESSAGE_NEWCLIENT:
return 1; /* msg handled */
default:
/*crWarning( "Why is the crserver getting a message of type 0x%x?",
msg->header.type ); */
;
}
return 0; /* not handled */
}