示例#1
0
/**
 * Process incoming/pending message for the given client (queue entry).
 * \return CLIENT_GONE if this client has gone away/exited,
 *         CLIENT_NEXT if we can advance to the next client
 *         CLIENT_MORE if we have to process more messages for this client. 
 */
static ClientStatus
glStubServiceClient(const RunQueue *qEntry)
{
	CRMessage *msg;
	CRConnection *conn;

	/* set current client pointer */
	cr_server.curClient = qEntry->client;

	conn = cr_server.run_queue->client->conn;

	/* service current client as long as we can */
	while (conn && conn->type != CR_NO_CONNECTION &&
				 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.
		 */
		len = crNetPeekMessage( conn, &msg );
		CRASSERT(len > 0);
		if (msg->header.type != CR_MESSAGE_OPCODES) {
			crError( "SPU %d sent me CRAP (type=0x%x)",
							 cr_server.curClient->spu_id, msg->header.type );
		}

		/* 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 gl stub'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 gl stub'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
		crStateMakeCurrent( cr_server.curClient->currentCtx );
#else
		crStateMakeCurrent( cr_server.curClient->currentCtx );

		/* 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.
		 */
		if (cr_server.curClient) {
			 int clientWindow = cr_server.curClient->currentWindow;
			 int clientContext = cr_server.curClient->currentContextNumber;
			 if (clientWindow && clientWindow != cr_server.currentWindow) {
				 glStubDispatchMakeCurrent(clientWindow, 0, clientContext);
				 /*
				 CRASSERT(cr_server.currentWindow == clientWindow);
				 */
			 }
		}
#endif

		/* Force scissor, viewport and projection matrix update in
		 * glStubSetOutputBounds().
		 */
		cr_server.currentSerialNo = 0;

		/* Commands get dispatched here */
		glStubDispatchMessage(msg);

		crNetFree( conn, msg );

		if (qEntry->blocked) {
			/* Note/assert: we should not be inside a glBegin/End or glNewList/
			 * glEndList pair at this time!
			 */
			return CLIENT_NEXT;
		}

	} /* while */

	/*
	 * Check if client/connection is gone
	 */
	if (!conn || conn->type == CR_NO_CONNECTION) {
		crDebug("Delete client %p at %d", cr_server.run_queue->client, __LINE__);
		glStubDeleteClient( cr_server.run_queue->client );
		return CLIENT_GONE;
	}

	/*
	 * Determine if we can advance to next client.
	 * If we're currently inside a glBegin/End primitive or building a display
	 * list we can't service another client until we're done with the
	 * primitive/list.
	 */
	if (glStubClientInBeginEnd(cr_server.curClient)) {
		/* The next message has to come from the current client's connection. */
		CRASSERT(!qEntry->blocked);
		return CLIENT_MORE;
	}
	else {
		/* get next client */
		return CLIENT_NEXT;
	}
}
示例#2
0
/**
 * 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 *
getNextClient(GLboolean block)
{
	while (1)
	{
		if (cr_server.run_queue) 
		{
			GLboolean all_blocked = GL_TRUE;
			GLboolean done_something = GL_FALSE;
			RunQueue *start = cr_server.run_queue;

			/* check if this client's connection has gone away */
 			if (!cr_server.run_queue->client->conn
					 || (cr_server.run_queue->client->conn->type == CR_NO_CONNECTION
							 && crNetNumMessages(cr_server.run_queue->client->conn) == 0)) {
 				glStubDeleteClient( cr_server.run_queue->client );
				start = cr_server.run_queue;
			}
 
 			if (cr_server.run_queue == NULL) {
				/* empty queue */
 				return NULL;
			}

			if (glStubClientInBeginEnd(cr_server.run_queue->client)) {
				/* 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.
				 */
				if (crNetNumMessages(cr_server.run_queue->client->conn) > 0)
					return cr_server.run_queue;
				else
					return NULL;
			}

			/* loop over entries in run queue, looking for next one that's ready */
			while (!done_something || cr_server.run_queue != start)
			{
				done_something = GL_TRUE;
				if (!cr_server.run_queue->blocked)
				{
					all_blocked = GL_FALSE;
				}
				if (!cr_server.run_queue->blocked
						&& cr_server.run_queue->client->conn
						&& crNetNumMessages(cr_server.run_queue->client->conn) > 0)
				{
					/* OK, this client isn't blocked and has a queued message */
					return cr_server.run_queue;
				}
				cr_server.run_queue = cr_server.run_queue->next;
			}

			if (all_blocked)
			{
				crWarning( "GLStub: DEADLOCK! (numClients=%d, all blocked)",
									 cr_server.numClients );
				if (cr_server.numClients < (int) cr_server.maxBarrierCount) {
					if (cr_server.exitIfNoClients) {
						crWarning("GLStub: exiting.");
						exit(0);
					}
					crWarning("GLStub: Waiting for more clients.");
					while (cr_server.numClients < (int) cr_server.maxBarrierCount) {
						crNetRecv();
					}
				}
			}
		}

		if (!block)
			 return NULL;

		/* no one had any work, get some! */
		crNetRecv();

	} /* while */

	/* UNREACHED */
	/* return NULL; */
}
示例#3
0
static void
glStubDeleteClient( CRClient *client )
{
	int i, j;

	crDebug("Deleting client %p (%d msgs left)", client,
					crNetNumMessages(client->conn));

#if 0
	if (crNetNumMessages(client->conn) > 0) {
		crDebug("Delay destroying client: message still pending");
		return;
	}
#endif

	if (!FindClientInQueue(client)) {
		/* this should never happen */
		crError("GLStub: client %p not found in the queue!", client);
	}

	/* remove from clients[] array */
	for (i = 0; i < cr_server.numClients; i++) {
		if (cr_server.clients[i] == client) {
			/* found it */
			for (j = i; j < cr_server.numClients - 1; j++)
				cr_server.clients[j] = cr_server.clients[j + 1];
			cr_server.numClients--;
			break;
		}
	}

	/* remove from the run queue */
	if (cr_server.run_queue)
	{
		RunQueue *q = cr_server.run_queue;
		RunQueue *qStart = cr_server.run_queue; 
		do {
			if (q->client == client)
			{
				/* this test seems a bit excessive */
				if ((q->next == q->prev) && (q->next == q) && (cr_server.run_queue == q))
				{
					/* We're removing/deleting the only client */
					CRASSERT(cr_server.numClients == 0);
					crFree(q);
					cr_server.run_queue = NULL;
					cr_server.curClient = NULL;
					crDebug("Last client deleted - empty run queue.");
				} 
				else
				{
					/* remove from doubly linked list and free the node */
					if (cr_server.curClient == q->client)
						cr_server.curClient = NULL;
					if (cr_server.run_queue == q)
						cr_server.run_queue = q->next;
					q->prev->next = q->next;
					q->next->prev = q->prev;
					crFree(q);
				}
				break;
			}
			q = q->next;
		} while (q != qStart);
	}

	crNetFreeConnection(client->conn);
	crFree(client);
}
void
crServerDeleteClient( CRClient *client )
{
    int i, j;
    int cleanup=1;

    crDebug("Deleting client %p (%d msgs left)", client, crNetNumMessages(client->conn));

#if 0
    if (crNetNumMessages(client->conn) > 0) {
        crDebug("Delay destroying client: message still pending");
        return;
    }
#endif

    if (!FindClientInQueue(client)) {
        /* this should never happen */
        crError("CRServer: client %p not found in the queue!", client);
    }

    /* remove from clients[] array */
    for (i = 0; i < cr_server.numClients; i++) {
        if (cr_server.clients[i] == client) {
            /* found it */
            for (j = i; j < cr_server.numClients - 1; j++)
                cr_server.clients[j] = cr_server.clients[j + 1];
            cr_server.numClients--;
            break;
        }
    }

    /* check if there're any other guest threads in same process */
    for (i=0; i < cr_server.numClients; i++)
    {
        if (cr_server.clients[i]->pid==client->pid)
        {
            cleanup=0;
            break;
        }
    }

    if (cleanup)
    {
        crServerCleanupClient(client);
    }

    /* remove from the run queue */
    if (cr_server.run_queue)
    {
        RunQueue *q = cr_server.run_queue;
        RunQueue *qStart = cr_server.run_queue; 
        do {
            if (q->client == client)
            {
                /* this test seems a bit excessive */
                if ((q->next == q->prev) && (q->next == q) && (cr_server.run_queue == q))
                {
                    /* We're removing/deleting the only client */
                    CRASSERT(cr_server.numClients == 0);
                    crFree(q);
                    cr_server.run_queue = NULL;
                    cr_server.curClient = NULL;
                    crDebug("Last client deleted - empty run queue.");
                } 
                else
                {
                    /* remove from doubly linked list and free the node */
                    if (cr_server.curClient == q->client)
                        cr_server.curClient = NULL;
                    if (cr_server.run_queue == q)
                        cr_server.run_queue = q->next;
                    q->prev->next = q->next;
                    q->next->prev = q->prev;
                    crFree(q);
                }
                break;
            }
            q = q->next;
        } while (q != qStart);
    }

    crNetFreeConnection(client->conn);
    client->conn = NULL;

    if (cleanup)
    {
        crServerCleanupByPID(client->pid);
        crFree(client);
    }
    else
    {
        CRClientNode *pNode = (CRClientNode *)crAlloc(sizeof(CRClientNode));
        if (!pNode)
        {
            crWarning("Not enough memory, forcing client cleanup");
            crServerCleanupClient(client);
            crServerCleanupByPID(client->pid);
            crFree(client);
            return;
        }
        pNode->pClient = client;
        pNode->prev = NULL;
        pNode->next = cr_server.pCleanupClient;
        cr_server.pCleanupClient = pNode;
    }
}
示例#5
0
void
crServerDeleteClient( CRClient *client )
{
    int i, j;
    int cleanup=1;

    crDebug("Deleting client %p (%d msgs left)", client, crNetNumMessages(client->conn));

#if 0
    if (crNetNumMessages(client->conn) > 0) {
        crDebug("Delay destroying client: message still pending");
        return;
    }
#endif

    if (!FindClientInQueue(client)) {
        /* this should never happen */
        crError("CRServer: client %p not found in the queue!", client);
    }

    /* remove from clients[] array */
    for (i = 0; i < cr_server.numClients; i++) {
        if (cr_server.clients[i] == client) {
            /* found it */
            for (j = i; j < cr_server.numClients - 1; j++)
                cr_server.clients[j] = cr_server.clients[j + 1];
            cr_server.numClients--;
            break;
        }
    }

    /* check if there're any other guest threads in same process */
    for (i=0; i < cr_server.numClients; i++)
    {
        if (cr_server.clients[i]->pid==client->pid)
        {
            cleanup=0;
            break;
        }
    }

    if (cleanup)
    {
        crServerCleanupClient(client);
    }

    /* remove from the run queue */
    if (cr_server.run_queue)
    {
        RunQueue *q = cr_server.run_queue;
        RunQueue *qStart = cr_server.run_queue; 
        do {
            if (q->client == client)
            {
                /* this test seems a bit excessive */
                if ((q->next == q->prev) && (q->next == q) && (cr_server.run_queue == q))
                {
                    /* We're removing/deleting the only client */
                    CRASSERT(cr_server.numClients == 0);
                    crFree(q);
                    cr_server.run_queue = NULL;
                    cr_server.curClient = NULL;
                    crDebug("Last client deleted - empty run queue.");
                } 
                else
                {
                    /* remove from doubly linked list and free the node */
                    if (cr_server.curClient == q->client)
                        cr_server.curClient = NULL;
                    if (cr_server.run_queue == q)
                        cr_server.run_queue = q->next;
                    q->prev->next = q->next;
                    q->next->prev = q->prev;
                    crFree(q);
                }
                break;
            }
            q = q->next;
        } while (q != qStart);
    }

    crNetFreeConnection(client->conn);
    client->conn = NULL;

    if (cleanup)
    {
        crServerCleanupByPID(client->pid);
        crFree(client);
    }
    else
    {
        CRClientNode *pNode = (CRClientNode *)crAlloc(sizeof(CRClientNode));
        if (!pNode)
        {
            crWarning("Not enough memory, forcing client cleanup");
            crServerCleanupClient(client);
            crServerCleanupByPID(client->pid);
            crFree(client);
            return;
        }
        pNode->pClient = client;
        pNode->prev = NULL;
        pNode->next = cr_server.pCleanupClient;
        cr_server.pCleanupClient = pNode;
    }

    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) */
        HCR_FRAMEBUFFER hFb;
        for (hFb = CrPMgrFbGetFirstEnabled(); hFb; hFb = CrPMgrFbGetNextEnabled(hFb))
        {
            int rc = CrFbUpdateBegin(hFb);
            if (RT_SUCCESS(rc))
            {
                CrFbRegionsClear(hFb);
                CrFbUpdateEnd(hFb);
            }
            else
                WARN(("CrFbUpdateBegin failed %d", rc));
        }
    }
}
示例#6
0
int32_t crVBoxServerClientWrite(uint32_t u32ClientID, uint8_t *pBuffer, uint32_t cbBuffer)
{
    CRClient *pClient = NULL;
    int32_t i;
#ifdef VBOXCR_LOGFPS
    uint64_t tstart, tend;
#endif

    /*crDebug("=>crServer: ClientWrite u32ClientID=%d", u32ClientID);*/

    for (i = 0; i < cr_server.numClients; i++)
    {
        if (cr_server.clients[i] && cr_server.clients[i]->conn
            && cr_server.clients[i]->conn->u32ClientID==u32ClientID)
        {
            pClient = cr_server.clients[i];
            break;
        }
    }
    if (!pClient) return VERR_INVALID_PARAMETER;

    if (!pClient->conn->vMajor) return VERR_NOT_SUPPORTED;

#ifdef VBOXCR_LOGFPS
    tstart = RTTimeNanoTS();
#endif

    CRASSERT(pBuffer);

    /* This should never fire unless we start to multithread */
    CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);

    /* Check if there's a blocker in queue and it's not this client */
    if (cr_server.run_queue->client != pClient
        && crServerClientInBeginEnd(cr_server.run_queue->client))
    {
        crDebug("crServer: client %d blocked, allow_redir_ptr = 0", u32ClientID);
        pClient->conn->allow_redir_ptr = 0;
    }
    else
    {
        pClient->conn->allow_redir_ptr = 1;
    }

    pClient->conn->pBuffer = pBuffer;
    pClient->conn->cbBuffer = cbBuffer;

    crNetRecv();
    CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);

    crServerServiceClients();

#if 0
        if (pClient->currentMural) {
            crStateViewport( 0, 0, 500, 500 );
            pClient->currentMural->viewportValidated = GL_FALSE;
            cr_server.head_spu->dispatch_table.Viewport( 0, 0, 500, 500 );
            crStateViewport( 0, 0, 600, 600 );
            pClient->currentMural->viewportValidated = GL_FALSE;
            cr_server.head_spu->dispatch_table.Viewport( 0, 0, 600, 600 );

            crStateMatrixMode(GL_PROJECTION);
            cr_server.head_spu->dispatch_table.MatrixMode(GL_PROJECTION);
            crServerDispatchLoadIdentity();
            crStateFrustum(-0.6, 0.6, -0.5, 0.5, 1.5, 150.0);
            cr_server.head_spu->dispatch_table.Frustum(-0.6, 0.6, -0.5, 0.5, 1.5, 150.0);
            crServerDispatchLoadIdentity();
            crStateFrustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
            cr_server.head_spu->dispatch_table.Frustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);

            crStateMatrixMode(GL_MODELVIEW);
            cr_server.head_spu->dispatch_table.MatrixMode(GL_MODELVIEW);
            crServerDispatchLoadIdentity();
            crStateFrustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
            cr_server.head_spu->dispatch_table.Frustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
            crServerDispatchLoadIdentity();
        }
#endif

    crStateResetCurrentPointers(&cr_server.current);

    CRASSERT(!pClient->conn->allow_redir_ptr || crNetNumMessages(pClient->conn)==0);

#ifdef VBOXCR_LOGFPS
    tend = RTTimeNanoTS();
    pClient->timeUsed += tend-tstart;
#endif
    /*crDebug("<=crServer: ClientWrite u32ClientID=%d", u32ClientID);*/

    return VINF_SUCCESS;
}