VirtualBox

Changeset 1741 in vbox


Ignore:
Timestamp:
Mar 27, 2007 4:29:56 PM (18 years ago)
Author:
vboxsync
Message:

Use a seperate thread for writing.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Serial/DrvChar.cpp

    r1736 r1741  
    3131
    3232#include <VBox/log.h>
     33#include <iprt/asm.h>
    3334#include <iprt/assert.h>
    3435#include <iprt/stream.h>
     36#include <iprt/semaphore.h>
    3537
    3638#include "Builtins.h"
    3739
     40
     41/** Size of the send fifo queue (in bytes) */
     42#define CHAR_MAX_SEND_QUEUE             0x80
     43#define CHAR_MAX_SEND_QUEUE_MASK        0x7f
    3844
    3945/*******************************************************************************
     
    5864    /** Receive thread ID. */
    5965    RTTHREAD                    ReceiveThread;
     66    /** Send thread ID. */
     67    RTTHREAD                    SendThread;
     68    /** Send event semephore */
     69    RTSEMEVENT                  SendSem;
     70
     71    /** Internal send FIFO queue */
     72    uint8_t                     aSendQueue[CHAR_MAX_SEND_QUEUE];
     73    uint32_t                    iSendQueueHead;
     74    uint32_t                    iSendQueueTail;
    6075} DRVCHAR, *PDRVCHAR;
    6176
     
    97112{
    98113    PDRVCHAR pData = PDMICHAR_2_DRVCHAR(pInterface);
     114    const char *pBuffer = (const char *)pvBuf;
    99115    int rc = VINF_SUCCESS;
    100116
    101117    LogFlow(("%s: pvBuf=%#p cbWrite=%d\n", __FUNCTION__, pvBuf, cbWrite));
    102118
    103     /*
    104      * Write the character to the attached stream (if present).
    105      */
    106     if (pData->pDrvStream)
     119    for (uint32_t i=0;i<cbWrite;i++)
    107120    {
    108         const char *pBuffer = (const char *)pvBuf;
    109         size_t cbProcessed = cbWrite;
    110 
    111         while (cbWrite)
     121        uint32_t idx = pData->iSendQueueHead;
     122
     123        pData->aSendQueue[idx] = pBuffer[i];
     124        idx = (idx + 1) & CHAR_MAX_SEND_QUEUE_MASK;
     125
     126        ASMAtomicXchgU32(&pData->iSendQueueHead, idx);
     127    }
     128    RTSemEventSignal(pData->SendSem);
     129    return VINF_SUCCESS;
     130}
     131
     132
     133/* -=-=-=-=- receive thread -=-=-=-=- */
     134
     135/**
     136 * Send thread loop.
     137 *
     138 * @returns 0 on success.
     139 * @param   ThreadSelf  Thread handle to this thread.
     140 * @param   pvUser      User argument.
     141 */
     142static DECLCALLBACK(int) drvCharSendLoop(RTTHREAD ThreadSelf, void *pvUser)
     143{
     144    PDRVCHAR pData = (PDRVCHAR)pvUser;
     145
     146    for(;;)
     147    {
     148        int rc = RTSemEventWait(pData->SendSem, RT_INDEFINITE_WAIT);
     149        if (VBOX_FAILURE(rc))
     150            break;
     151
     152        /*
     153         * Write the character to the attached stream (if present).
     154         */
     155        if (    !pData->fShutdown
     156            &&  pData->pDrvStream)
    112157        {
    113             rc = pData->pDrvStream->pfnWrite(pData->pDrvStream, pBuffer, &cbProcessed);
    114             if (VBOX_SUCCESS(rc))
    115             {
    116                 Assert(cbProcessed);
    117                 cbWrite -= cbProcessed;
    118                 pBuffer += cbProcessed;
    119             }
    120             else if (rc == VERR_TIMEOUT)
    121             {
    122                 /* Normal case, just means that the stream didn't accept a new
    123                  * character before the timeout elapsed. Just retry. */
    124                 rc = VINF_SUCCESS;
    125             }
    126             else
    127             {
    128                 Log(("Write failed with %Vrc; skipping\n", rc));
    129                 break;
     158            while (pData->iSendQueueTail != pData->iSendQueueHead)
     159            {
     160                size_t cbProcessed = 1;
     161
     162                rc = pData->pDrvStream->pfnWrite(pData->pDrvStream, &pData->aSendQueue[pData->iSendQueueTail], &cbProcessed);
     163                if (VBOX_SUCCESS(rc))
     164                {
     165                    Assert(cbProcessed);
     166                    pData->iSendQueueTail++;
     167                    pData->iSendQueueTail &= CHAR_MAX_SEND_QUEUE_MASK;
     168                }
     169                else if (rc == VERR_TIMEOUT)
     170                {
     171                    /* Normal case, just means that the stream didn't accept a new
     172                     * character before the timeout elapsed. Just retry. */
     173                    rc = VINF_SUCCESS;
     174                }
     175                else
     176                {
     177                    Log(("Write failed with %Vrc; skipping\n", rc));
     178                    break;
     179                }
    130180            }
    131181        }
     182        else
     183            break;
    132184    }
    133     else
    134         rc = VERR_PDM_NO_ATTACHED_DRIVER;
    135 
    136     LogFlow(("%s: returns rc=%Vrc\n", __FUNCTION__, rc));
    137     return rc;
     185
     186    pData->SendThread = NIL_RTTHREAD;
     187
     188    return VINF_SUCCESS;
    138189}
    139190
     
    251302        return PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_MISSING_INTERFACE_BELOW, RT_SRC_POS, N_("Char#%d has no stream interface below"), pDrvIns->iInstance);
    252303
    253     rc = RTThreadCreate(&pData->ReceiveThread, drvCharReceiveLoop, (void *)pData, 0, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "Char");
     304    rc = RTThreadCreate(&pData->ReceiveThread, drvCharReceiveLoop, (void *)pData, 0, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "Char Receive");
    254305    if (VBOX_FAILURE(rc))
    255306        return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("Char#%d cannot create receive thread"), pDrvIns->iInstance);
    256307
     308    rc = RTSemEventCreate(&pData->SendSem);
     309    AssertRC(rc);
     310
     311    rc = RTThreadCreate(&pData->SendThread, drvCharSendLoop, (void *)pData, 0, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "Char Send");
     312    if (VBOX_FAILURE(rc))
     313        return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("Char#%d cannot create send thread"), pDrvIns->iInstance);
     314
    257315    return VINF_SUCCESS;
    258316}
     
    274332
    275333    pData->fShutdown = true;
    276     RTThreadWait(pData->ReceiveThread, 5000, NULL);
     334    RTThreadWait(pData->ReceiveThread, 1000, NULL);
    277335    if (pData->ReceiveThread != NIL_RTTHREAD)
    278336        LogRel(("Char%d: receive thread did not terminate\n", pDrvIns->iInstance));
     337
     338    /* Empty the send queue */
     339    pData->iSendQueueTail = pData->iSendQueueHead = 0;
     340
     341    RTSemEventDestroy(pData->SendSem);
     342    pData->SendSem = NIL_RTSEMEVENT;
     343
     344    RTThreadWait(pData->SendThread, 1000, NULL);
     345    if (pData->SendThread != NIL_RTTHREAD)
     346        LogRel(("Char%d: send thread did not terminate\n", pDrvIns->iInstance));
    279347}
    280348
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette