Ignore:
Timestamp:
Apr 2, 2013, 1:31:30 PM (12 years ago)
Author:
ldelgass
Message:

Add writer thread to nanovis (set USE_THREADS in Makefile), more refactoring.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/packages/vizservers/nanovis/Command.cpp

    r3597 r3605  
    4545#include <vrmath/Vector3f.h>
    4646
     47#include "nanovisServer.h"
    4748#include "nanovis.h"
     49#include "ReadBuffer.h"
     50#ifdef USE_THREADS
     51#include "ResponseQueue.h"
     52#endif
     53#include "Command.h"
    4854#include "CmdProc.h"
    4955#include "FlowCmd.h"
    50 #include "Trace.h"
    51 #ifdef USE_POINTSET_RENDERER
    52 #include "PointSet.h"
    53 #endif
    5456#include "dxReader.h"
    5557#include "VtkReader.h"
     58#include "BMPWriter.h"
     59#include "PPMWriter.h"
    5660#include "Grid.h"
    5761#include "HeightMap.h"
    5862#include "NvCamera.h"
    5963#include "NvZincBlendeReconstructor.h"
     64#include "OrientationIndicator.h"
    6065#include "Unirect.h"
    6166#include "Volume.h"
    6267#include "VolumeRenderer.h"
    63 
     68#include "Trace.h"
     69
     70using namespace nv;
    6471using namespace nv::graphics;
    6572using namespace vrmath;
     
    102109}";
    103110
     111static int lastCmdStatus;
     112
     113#ifdef USE_THREADS
     114void
     115nv::queueResponse(const void *bytes, size_t len,
     116                  Response::AllocationType allocType,
     117                  Response::ResponseType type)
     118{
     119    Response *response = new Response(type);
     120    response->setMessage((unsigned char *)bytes, len, allocType);
     121    g_queue->enqueue(response);
     122}
     123#else
     124
     125ssize_t
     126nv::SocketWrite(const void *bytes, size_t len)
     127{
     128    size_t ofs = 0;
     129    ssize_t bytesWritten;
     130    while ((bytesWritten = write(g_fdOut, (const char *)bytes + ofs, len - ofs)) > 0) {
     131        ofs += bytesWritten;
     132        if (ofs == len)
     133            break;
     134    }
     135    if (bytesWritten < 0) {
     136        ERROR("write: %s", strerror(errno));
     137    }
     138    return bytesWritten;
     139}
     140
     141#endif  /*USE_THREADS*/
     142
     143bool
     144nv::SocketRead(char *bytes, size_t len)
     145{
     146    ReadBuffer::BufferStatus status;
     147    status = g_inBufPtr->followingData((unsigned char *)bytes, len);
     148    TRACE("followingData status: %d", status);
     149    return (status == ReadBuffer::OK);
     150}
     151
     152bool
     153nv::SocketRead(Rappture::Buffer &buf, size_t len)
     154{
     155    ReadBuffer::BufferStatus status;
     156    status = g_inBufPtr->followingData(buf, len);
     157    TRACE("followingData status: %d", status);
     158    return (status == ReadBuffer::OK);
     159}
     160
     161static int
     162ExecuteCommand(Tcl_Interp *interp, Tcl_DString *dsPtr)
     163{
     164    int result;
     165#ifdef WANT_TRACE
     166    char *str = Tcl_DStringValue(dsPtr);
     167    std::string cmd(str);
     168    cmd.erase(cmd.find_last_not_of(" \n\r\t")+1);
     169    TRACE("command %lu: '%s'", g_stats.nCommands+1, cmd.c_str());
     170#endif
     171    lastCmdStatus = TCL_OK;
     172    result = Tcl_EvalEx(interp, Tcl_DStringValue(dsPtr),
     173                        Tcl_DStringLength(dsPtr),
     174                        TCL_EVAL_DIRECT | TCL_EVAL_GLOBAL);
     175    Tcl_DStringSetLength(dsPtr, 0);
     176    if (lastCmdStatus == TCL_BREAK) {
     177        return TCL_BREAK;
     178    }
     179    lastCmdStatus = result;
     180    if (result != TCL_OK) {
     181        TRACE("Error: %d", result);
     182    }
     183    return result;
     184}
     185
    104186bool
    105187GetBooleanFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, bool *boolPtr)
     
    276358 * TCL_ERROR to indicate an error.
    277359 */
    278 static int
     360int
    279361GetVolumeFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, Volume **volPtrPtr)
    280362{
     
    454536GetDataStream(Tcl_Interp *interp, Rappture::Buffer &buf, int nBytes)
    455537{
    456     char buffer[8096];
    457 
    458     clearerr(NanoVis::stdin);
    459     while (nBytes > 0) {
    460         unsigned int chunk;
    461         int nRead;
    462 
    463         chunk = (sizeof(buffer) < (unsigned int) nBytes) ?
    464             sizeof(buffer) : nBytes;
    465         nRead = fread(buffer, sizeof(char), chunk, NanoVis::stdin);
    466         if (ferror(NanoVis::stdin)) {
    467             Tcl_AppendResult(interp, "while reading data stream: ",
    468                              Tcl_PosixError(interp), (char*)NULL);
    469             return TCL_ERROR;
    470         }
    471         if (feof(NanoVis::stdin)) {
    472             Tcl_AppendResult(interp, "premature EOF while reading data stream",
    473                              (char*)NULL);
    474             return TCL_ERROR;
    475         }
    476         buf.append(buffer, nRead);
    477         nBytes -= nRead;
    478     }
    479     if (NanoVis::recfile != NULL) {
    480         ssize_t nWritten;
    481 
    482         nWritten = fwrite(buf.bytes(), sizeof(char), buf.size(),
    483                           NanoVis::recfile);
    484         assert(nWritten == (ssize_t)buf.size());
    485         fflush(NanoVis::recfile);
     538    if (!SocketRead(buf, nBytes)) {
     539        return TCL_ERROR;
    486540    }
    487541    Rappture::Outcome err;
     
    621675            Tcl_Obj *const *objv)
    622676{
    623     int w, h;
    624 
    625     w = NanoVis::winWidth, h = NanoVis::winHeight;
    626 
    627     NanoVis::resizeOffscreenBuffer(2048, 2048);
    628 #ifdef notdef
    629     NanoVis::cam->setScreenSize(0, 0, NanoVis::winWidth, NanoVis::winHeight);
    630     NanoVis::cam->setScreenSize(30, 90, 2048 - 60, 2048 - 120);
    631 #endif
    632     NanoVis::bindOffscreenBuffer();  //enable offscreen render
     677    int origWidth, origHeight, width, height;
     678
     679    origWidth = NanoVis::winWidth;
     680    origHeight = NanoVis::winHeight;
     681    width = 2048;
     682    height = 2048;
     683
     684    NanoVis::resizeOffscreenBuffer(width, height);
     685    NanoVis::bindOffscreenBuffer();
    633686    NanoVis::render();
    634687    NanoVis::readScreen();
    635 
    636     NanoVis::ppmWrite("nv>image -type print -bytes %d");
    637     NanoVis::resizeOffscreenBuffer(w, h);
     688#ifdef USE_THREADS
     689    queuePPM(g_queue, "nv>image -type print -bytes",
     690             NanoVis::screenBuffer, width, height);
     691#else
     692    writePPM(g_fdOut, "nv>image -type print -bytes",
     693             NanoVis::screenBuffer, width, height);
     694#endif
     695    NanoVis::resizeOffscreenBuffer(origWidth, origHeight);
    638696
    639697    return TCL_OK;
     
    753811static int
    754812ClientInfoCmd(ClientData clientData, Tcl_Interp *interp, int objc,
    755         Tcl_Obj *const *objv)
     813              Tcl_Obj *const *objv)
    756814{
    757815    Tcl_DString ds;
     
    769827    }
    770828#ifdef KEEPSTATS
    771     int f;
    772 
    773829    /* Use the initial client key value pairs as the parts for a generating
    774830     * a unique file name. */
    775     f = NanoVis::getStatsFile(objv[1]);
     831    int f = nv::getStatsFile(interp, objv[1]);
    776832    if (f < 0) {
    777833        Tcl_AppendResult(interp, "can't open stats file: ",
     
    809865    /* date */
    810866    Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewStringObj("date", 4));
    811     strcpy(buf, ctime(&NanoVis::startTime.tv_sec));
     867    strcpy(buf, ctime(&nv::g_stats.start.tv_sec));
    812868    buf[strlen(buf) - 1] = '\0';
    813869    Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewStringObj(buf, -1));
     
    816872                Tcl_NewStringObj("date_secs", 9));
    817873    Tcl_ListObjAppendElement(interp, listObjPtr,
    818                 Tcl_NewLongObj(NanoVis::startTime.tv_sec));
     874                Tcl_NewLongObj(nv::g_stats.start.tv_sec));
    819875    /* Client arguments. */
    820876    if (Tcl_ListObjGetElements(interp, objv[1], &numItems, &items) != TCL_OK) {
     
    829885    Tcl_DStringAppend(&ds, "\n", 1);
    830886#ifdef KEEPSTATS
    831     result = NanoVis::writeToStatsFile(f, Tcl_DStringValue(&ds),
    832                                        Tcl_DStringLength(&ds));
     887    result = nv::writeToStatsFile(f, Tcl_DStringValue(&ds),
     888                                  Tcl_DStringLength(&ds));
    833889#else
    834890    TRACE("clientinfo: %s", Tcl_DStringValue(&ds));
     
    860916    }
    861917
    862     const char *name;
    863     name = Tcl_GetString(objv[1]);
    864     TransferFunction *tf = NanoVis::getTransferFunction(name);
     918    const char *tfName = Tcl_GetString(objv[1]);
     919    TransferFunction *tf = NanoVis::getTransferFunction(tfName);
    865920    if (tf == NULL) {
    866         Tcl_AppendResult(interp, "unknown transfer function \"", name, "\"",
     921        Tcl_AppendResult(interp, "unknown transfer function \"", tfName, "\"",
    867922                             (char*)NULL);
    868923        return TCL_ERROR;
     
    876931        NanoVis::setVolumeRanges();
    877932    }
    878     NanoVis::renderLegend(tf, Volume::valueMin, Volume::valueMax, w, h, name);
     933    NanoVis::renderLegend(tf, Volume::valueMin, Volume::valueMax, w, h, tfName);
    879934    return TCL_OK;
    880935}
     
    10801135        return TCL_ERROR;
    10811136    }
    1082     VolumeInterpolator* interpolator;
    1083     interpolator = NanoVis::volRenderer->getVolumeInterpolator();
     1137    VolumeInterpolator *interpolator =
     1138        NanoVis::volRenderer->getVolumeInterpolator();
    10841139    interpolator->start();
    10851140    if (interpolator->isStarted()) {
    1086         const char *fileName = (objc < 5) ? NULL : Tcl_GetString(objv[4]);
    1087         for (int frame_num = 0; frame_num < total; ++frame_num) {
     1141        const char *dirName = (objc < 5) ? NULL : Tcl_GetString(objv[4]);
     1142        for (int frameNum = 0; frameNum < total; ++frameNum) {
    10881143            float fraction;
    10891144
    1090             fraction = ((float)frame_num) / (total - 1);
     1145            fraction = ((float)frameNum) / (total - 1);
    10911146            TRACE("fraction : %f", fraction);
    1092             //interpolator->update(((float)frame_num) / (total - 1));
    10931147            interpolator->update(fraction);
    10941148
     
    11031157            glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboOrig);
    11041158
    1105             NanoVis::bmpWriteToFile(frame_num, fileName);
     1159            /* FIXME: this function requires 4-byte aligned RGB rows,
     1160             * but screen buffer is now 1 byte aligned for PPM images.
     1161             */
     1162            nv::writeBMPFile(frameNum, dirName,
     1163                             NanoVis::screenBuffer,
     1164                             NanoVis::winWidth, NanoVis::winHeight);
    11061165        }
    11071166    }
     
    11851244    }
    11861245    const char *tag = Tcl_GetString(objv[4]);
    1187     Rappture::Buffer buf;
     1246
     1247    Rappture::Buffer buf(nbytes);
    11881248    if (GetDataStream(interp, buf, nbytes) != TCL_OK) {
    11891249        return TCL_ERROR;
    11901250    }
    1191     const char *bytes;
    1192     size_t nBytes;
    1193 
    1194     bytes = buf.bytes();
    1195     nBytes = buf.size();
     1251    const char *bytes = buf.bytes();
     1252    size_t nBytes = buf.size();
    11961253
    11971254    TRACE("Checking header[%.20s]", bytes);
     
    12011258    if ((nBytes > 5) && (strncmp(bytes, "<HDR>", 5) == 0)) {
    12021259        TRACE("ZincBlende Stream loading...");
    1203          //std::stringstream fdata(std::ios_base::out|std::ios_base::in|std::ios_base::binary);
    1204         //fdata.write(buf.bytes(),buf.size());
    1205         //vol = NvZincBlendeReconstructor::getInstance()->loadFromStream(fdata);
    1206 
    1207         volume = NvZincBlendeReconstructor::getInstance()->loadFromMemory((void*) buf.bytes());
     1260        volume = NvZincBlendeReconstructor::getInstance()->loadFromMemory(const_cast<char *>(bytes));
    12081261        if (volume == NULL) {
    12091262            Tcl_AppendResult(interp, "can't get volume instance", (char *)NULL);
     
    12671320        volume->visible(true);
    12681321
    1269         char info[1024];
    1270         ssize_t nWritten;
    1271 
    12721322        if (Volume::updatePending) {
    12731323            NanoVis::setVolumeRanges();
    12741324        }
    12751325
     1326        char info[1024];
    12761327        // FIXME: strlen(info) is the return value of sprintf
    1277         sprintf(info, "nv>data tag %s min %g max %g vmin %g vmax %g\n", tag,
    1278                 volume->wAxis.min(), volume->wAxis.max(),
    1279                 Volume::valueMin, Volume::valueMax);
    1280         nWritten  = write(1, info, strlen(info));
    1281         assert(nWritten == (ssize_t)strlen(info));
    1282     }
     1328        int cmdLength =
     1329            sprintf(info, "nv>data tag %s min %g max %g vmin %g vmax %g\n", tag,
     1330                    volume->wAxis.min(), volume->wAxis.max(),
     1331                    Volume::valueMin, Volume::valueMax);
     1332#ifdef USE_THREADS
     1333        queueResponse(info, cmdLength, Response::VOLATILE);
     1334#else
     1335        ssize_t nWritten  = SocketWrite(info, (size_t)cmdLength);
     1336        if (nWritten != (ssize_t)cmdLength) {
     1337            ERROR("Short write");
     1338             return TCL_ERROR;
     1339        }
     1340#endif
     1341    }
     1342
    12831343    return TCL_OK;
    12841344}
     
    13041364
    13051365static Rappture::CmdSpec volumeDataOps[] = {
    1306     {"follows",   1, VolumeDataFollowsOp, 5, 5, "size tag",},
     1366    {"follows",   1, VolumeDataFollowsOp, 5, 5, "nbytes tag",},
    13071367    {"state",     1, VolumeDataStateOp,   4, 0, "bool ?indices?",},
    13081368};
     
    14071467}
    14081468
    1409 
    14101469static Rappture::CmdSpec volumeOutlineOps[] = {
    14111470    {"color",     1, VolumeOutlineColorOp,  6, 0, "r g b ?indices?",},
     
    15961655               tf->name());
    15971656        (*iter)->transferFunction(tf);
    1598 #ifdef USE_POINTSET_RENDERER
    1599         // TBD..
    1600         if ((*iter)->pointsetIndex != -1) {
    1601             NanoVis::pointSet[(*iter)->pointsetIndex]->updateColor(tf->getData(), 256);
    1602         }
    1603 #endif
    16041657    }
    16051658    return TCL_OK;
     
    16561709    {"delete",    2, VolumeDeleteOp,      3, 0, "?name...?",},
    16571710    {"exists",    1, VolumeExistsOp,      3, 3, "name",},
    1658     {"names",     1, VolumeNamesOp,       2, 3, "?pattern?",},
     1711    {"names",     1, VolumeNamesOp,       2, 2, "",},
    16591712    {"outline",   1, VolumeOutlineOp,     3, 0, "oper ?args?",},
    16601713    {"shading",   2, VolumeShadingOp,     3, 0, "oper ?args?",},
     
    16631716static int nVolumeOps = NumCmdSpecs(volumeOps);
    16641717
    1665 /*
    1666  * ----------------------------------------------------------------------
    1667  * CLIENT COMMAND:
    1668  *   volume data state on|off ?<volumeId> ...?
    1669  *   volume outline state on|off ?<volumeId> ...?
    1670  *   volume outline color on|off ?<volumeId> ...?
    1671  *   volume shading transfunc <name> ?<volumeId> ...?
    1672  *   volume shading diffuse <value> ?<volumeId> ...?
    1673  *   volume shading specular <value> ?<volumeId> ...?
    1674  *   volume shading opacity <value> ?<volumeId> ...?
    1675  *   volume state on|off ?<volumeId> ...?
    1676  *
    1677  * Clients send these commands to manipulate the volumes.
    1678  * ----------------------------------------------------------------------
    1679  */
    16801718static int
    16811719VolumeCmd(ClientData clientData, Tcl_Interp *interp, int objc,
     
    17021740    const char *tag = Tcl_GetString(objv[4]);
    17031741
    1704     Rappture::Buffer buf;
     1742    Rappture::Buffer buf(nBytes);
    17051743    if (GetDataStream(interp, buf, nBytes) != TCL_OK) {
    17061744        return TCL_ERROR;
     
    17611799
    17621800static Rappture::CmdSpec heightMapDataOps[] = {
    1763     {"follows",  1, HeightMapDataFollowsOp, 5, 5, "size tag",},
    1764     {"visible",  1, HeightMapDataVisibleOp, 4, 0, "bool ?indices?",},
     1801    {"follows",  1, HeightMapDataFollowsOp, 5, 5, "size heightmapName",},
     1802    {"visible",  1, HeightMapDataVisibleOp, 4, 0, "bool ?heightmapNames...?",},
    17651803};
    17661804static int nHeightMapDataOps = NumCmdSpecs(heightMapDataOps);
     
    18221860
    18231861static Rappture::CmdSpec heightMapLineContourOps[] = {
    1824     {"color",   1, HeightMapLineContourColorOp,   4, 4, "length",},
    1825     {"visible", 1, HeightMapLineContourVisibleOp, 4, 0, "bool ?indices?",},
     1862    {"color",   1, HeightMapLineContourColorOp,   6, 0, "r g b ?heightmapNames...?",},
     1863    {"visible", 1, HeightMapLineContourVisibleOp, 4, 0, "bool ?heightmapNames...?",},
    18261864};
    18271865static int nHeightMapLineContourOps = NumCmdSpecs(heightMapLineContourOps);
     
    19561994}
    19571995
    1958 
    19591996static int
    19601997HeightMapOpacityOp(ClientData clientData, Tcl_Interp *interp, int objc,
     
    19782015
    19792016static Rappture::CmdSpec heightMapOps[] = {
    1980     {"create",       2, HeightMapCreateOp,      10, 10, "tag xmin ymin xmax ymax xnum ynum values",},
     2017    {"create",       2, HeightMapCreateOp,      10, 10, "heightmapName xmin ymin xmax ymax xnum ynum values",},
    19812018    {"cull",         2, HeightMapCullOp,        3, 3, "mode",},
    19822019    {"data",         1, HeightMapDataOp,        3, 0, "oper ?args?",},
    1983     {"legend",       2, HeightMapLegendOp,      5, 5, "index width height",},
     2020    {"legend",       2, HeightMapLegendOp,      5, 5, "heightmapName width height",},
    19842021    {"linecontour",  2, HeightMapLineContourOp, 2, 0, "oper ?args?",},
    1985     {"opacity",      1, HeightMapOpacityOp,     3, 0, "value ?heightmap...? ",},
     2022    {"opacity",      1, HeightMapOpacityOp,     3, 0, "value ?heightmapNames...? ",},
    19862023    {"polygon",      1, HeightMapPolygonOp,     3, 3, "mode",},
    19872024    {"shading",      1, HeightMapShadingOp,     3, 3, "model",},
    1988     {"transfunc",    2, HeightMapTransFuncOp,   3, 0, "name ?heightmap...?",},
     2025    {"transfunc",    2, HeightMapTransFuncOp,   3, 0, "name ?heightmapNames...?",},
    19892026};
    19902027static int nHeightMapOps = NumCmdSpecs(heightMapOps);
     
    21182155            return TCL_ERROR;
    21192156        }
    2120         NanoVis::axisOn = visible;
     2157        NanoVis::orientationIndicator->setVisible(visible);
    21212158    } else {
    21222159        Tcl_AppendResult(interp, "bad axis option \"", string,
     
    21272164}
    21282165
    2129 /*
    2130  * This command should be Tcl procedure instead of a C command.  The reason
    2131  * for this that 1) we are using a safe interpreter so we would need a master
    2132  * interpreter to load the Tcl environment properly (including our "unirect2d"
    2133  * procedure). And 2) the way nanovis is currently deployed doesn't make it
    2134  * easy to add new directories for procedures, since it's loaded into /tmp.
    2135  *
    2136  * Ideally, the "unirect2d" proc would do a rundimentary parsing of the data
    2137  * to verify the structure and then pass it to the appropiate Tcl command
    2138  * (heightmap, volume, etc). Our C command always creates a heightmap.
     2166static int
     2167ImageFlushCmd(ClientData clientData, Tcl_Interp *interp, int objc,
     2168              Tcl_Obj *const *objv)
     2169{
     2170    lastCmdStatus = TCL_BREAK;
     2171    return TCL_OK;
     2172}
     2173
     2174/**
     2175 * \brief Execute commands from client in Tcl interpreter
     2176 *
     2177 * In this threaded model, the select call is for event compression.  We
     2178 * want to execute render server commands as long as they keep coming. 
     2179 * This lets us execute a stream of many commands but render once.  This
     2180 * benefits camera movements, screen resizing, and opacity changes
     2181 * (using a slider on the client).  The down side is you don't render
     2182 * until there's a lull in the command stream.  If the client needs an
     2183 * image, it can issue an "imgflush" command.  That breaks us out of the
     2184 * read loop.
    21392185 */
    2140 static int
    2141 Unirect2dCmd(ClientData clientData, Tcl_Interp *interp, int objc,
    2142              Tcl_Obj *const *objv)
    2143 {
    2144     Rappture::Unirect2d *dataPtr = (Rappture::Unirect2d *)clientData;
    2145 
    2146     return dataPtr->loadData(interp, objc, objv);
    2147 }
    2148 
    2149 /*
    2150  * This command should be Tcl procedure instead of a C command.  The reason
    2151  * for this that 1) we are using a safe interpreter so we would need a master
    2152  * interpreter to load the Tcl environment properly (including our "unirect2d"
    2153  * procedure). And 2) the way nanovis is currently deployed doesn't make it
    2154  * easy to add new directories for procedures, since it's loaded into /tmp.
    2155  *
    2156  * Ideally, the "unirect2d" proc would do a rundimentary parsing of the data
    2157  * to verify the structure and then pass it to the appropiate Tcl command
    2158  * (heightmap, volume, etc). Our C command always creates a heightmap.
     2186int
     2187nv::processCommands(Tcl_Interp *interp,
     2188                    ReadBuffer *inBufPtr, int fdOut)
     2189{
     2190    int ret = 1;
     2191    int status = TCL_OK;
     2192
     2193    Tcl_DString command;
     2194    Tcl_DStringInit(&command);
     2195    fd_set readFds;
     2196    struct timeval tv, *tvPtr;
     2197
     2198    FD_ZERO(&readFds);
     2199    FD_SET(inBufPtr->file(), &readFds);
     2200    tvPtr = NULL;                       /* Wait for the first read. This is so
     2201                                         * that we don't spin when no data is
     2202                                         * available. */
     2203    while (inBufPtr->isLineAvailable() ||
     2204           (select(1, &readFds, NULL, NULL, tvPtr) > 0)) {
     2205        size_t numBytes;
     2206        unsigned char *buffer;
     2207
     2208        /* A short read is treated as an error here because we assume that we
     2209         * will always get commands line by line. */
     2210        if (inBufPtr->getLine(&numBytes, &buffer) != ReadBuffer::OK) {
     2211            /* Terminate the server if we can't communicate with the client
     2212             * anymore. */
     2213            if (inBufPtr->status() == ReadBuffer::ENDFILE) {
     2214                TRACE("Exiting server on EOF from client");
     2215                return -1;
     2216            } else {
     2217                ERROR("Exiting server, failed to read from client: %s",
     2218                      strerror(errno));
     2219                return -1;
     2220            }
     2221        }
     2222        Tcl_DStringAppend(&command, (char *)buffer, numBytes);
     2223        if (Tcl_CommandComplete(Tcl_DStringValue(&command))) {
     2224            struct timeval start, finish;
     2225            gettimeofday(&start, NULL);
     2226            status = ExecuteCommand(interp, &command);
     2227            gettimeofday(&finish, NULL);
     2228            g_stats.cmdTime += (MSECS_ELAPSED(start, finish) / 1.0e+3);
     2229            g_stats.nCommands++;
     2230            if (status == TCL_BREAK) {
     2231                return 1;               /* This was caused by a "imgflush"
     2232                                         * command. Break out of the read loop
     2233                                         * and allow a new image to be
     2234                                         * rendered. */
     2235            } else { //if (status != TCL_OK) {
     2236                ret = 0;
     2237                if (handleError(interp, status, fdOut) < 0) {
     2238                    return -1;
     2239                }
     2240            }
     2241        }
     2242
     2243        tv.tv_sec = tv.tv_usec = 0L;    /* On successive reads, we break out
     2244                                         * if no data is available. */
     2245        FD_SET(inBufPtr->file(), &readFds);
     2246        tvPtr = &tv;
     2247    }
     2248
     2249    return ret;
     2250}
     2251
     2252/**
     2253 * \brief Send error message to client socket
    21592254 */
    2160 
    2161 static int
    2162 Unirect3dCmd(ClientData clientData, Tcl_Interp *interp, int objc,
    2163              Tcl_Obj *const *objv)
    2164 {
    2165     Rappture::Unirect3d *dataPtr = (Rappture::Unirect3d *)clientData;
    2166 
    2167     return dataPtr->loadData(interp, objc, objv);
    2168 }
    2169 
    2170 Tcl_Interp *
    2171 initTcl()
     2255int
     2256nv::handleError(Tcl_Interp *interp, int status, int fdOut)
     2257{
     2258    const char *string;
     2259    int nBytes;
     2260
     2261    if (status != TCL_OK) {
     2262        string = Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY);
     2263        nBytes = strlen(string);
     2264        if (nBytes > 0) {
     2265            TRACE("status=%d errorInfo=(%s)", status, string);
     2266
     2267            std::ostringstream oss;
     2268            oss << "nv>viserror -type internal_error -token " << g_stats.nCommands << " -bytes " << nBytes << "\n" << string;
     2269            nBytes = oss.str().length();
     2270
     2271#ifdef USE_THREADS
     2272            queueResponse(oss.str().c_str(), nBytes, Response::VOLATILE, Response::ERROR);
     2273#else
     2274            if (write(fdOut, oss.str().c_str(), nBytes) < 0) {
     2275                ERROR("write failed: %s", strerror(errno));
     2276                return -1;
     2277            }
     2278#endif
     2279        }
     2280    }
     2281
     2282    string = getUserMessages();
     2283    nBytes = strlen(string);
     2284    if (nBytes > 0) {
     2285        TRACE("userError=(%s)", string);
     2286
     2287        std::ostringstream oss;
     2288        oss << "nv>viserror -type error -token " << g_stats.nCommands << " -bytes " << nBytes << "\n" << string;
     2289        nBytes = oss.str().length();
     2290
     2291#ifdef USE_THREADS
     2292        queueResponse(oss.str().c_str(), nBytes, Response::VOLATILE, Response::ERROR);
     2293#else
     2294        if (write(fdOut, oss.str().c_str(), nBytes) < 0) {
     2295            ERROR("write failed: %s", strerror(errno));
     2296            return -1;
     2297        }
     2298#endif
     2299        clearUserMessages();
     2300    }
     2301
     2302    return 0;
     2303}
     2304
     2305void
     2306nv::initTcl(Tcl_Interp *interp, ClientData clientData)
    21722307{
    21732308    /*
     
    21782313     * a test harness through the interpreter for nanovis.
    21792314     */
    2180     Tcl_Interp *interp;
    2181     interp = Tcl_CreateInterp();
    2182     /*
     2315
    21832316    Tcl_MakeSafe(interp);
    2184     */
    2185     Tcl_CreateObjCommand(interp, "axis",        AxisCmd,        NULL, NULL);
    2186     Tcl_CreateObjCommand(interp, "camera",      CameraCmd,      NULL, NULL);
    2187     Tcl_CreateObjCommand(interp, "clientinfo",  ClientInfoCmd,  NULL, NULL);
    2188     Tcl_CreateObjCommand(interp, "cutplane",    CutplaneCmd,    NULL, NULL);
    2189     if (FlowCmdInitProc(interp) != TCL_OK) {
    2190         return NULL;
    2191     }
    2192     Tcl_CreateObjCommand(interp, "grid",        GridCmd,        NULL, NULL);
    2193     Tcl_CreateObjCommand(interp, "heightmap",   HeightMapCmd,   NULL, NULL);
    2194     Tcl_CreateObjCommand(interp, "legend",      LegendCmd,      NULL, NULL);
    2195     Tcl_CreateObjCommand(interp, "screen",      ScreenCmd,      NULL, NULL);
    2196     Tcl_CreateObjCommand(interp, "snapshot",    SnapshotCmd,    NULL, NULL);
    2197     Tcl_CreateObjCommand(interp, "transfunc",   TransfuncCmd,   NULL, NULL);
    2198     Tcl_CreateObjCommand(interp, "unirect2d",   Unirect2dCmd,   NULL, NULL);
    2199     Tcl_CreateObjCommand(interp, "unirect3d",   Unirect3dCmd,   NULL, NULL);
    2200     Tcl_CreateObjCommand(interp, "up",          UpCmd,          NULL, NULL);
    2201     Tcl_CreateObjCommand(interp, "volume",      VolumeCmd,      NULL, NULL);
     2317
     2318    Tcl_CreateObjCommand(interp, "axis",        AxisCmd,        clientData, NULL);
     2319    Tcl_CreateObjCommand(interp, "camera",      CameraCmd,      clientData, NULL);
     2320    Tcl_CreateObjCommand(interp, "clientinfo",  ClientInfoCmd,  clientData, NULL);
     2321    Tcl_CreateObjCommand(interp, "cutplane",    CutplaneCmd,    clientData, NULL);
     2322    FlowCmdInitProc(interp, clientData);
     2323    Tcl_CreateObjCommand(interp, "grid",        GridCmd,        clientData, NULL);
     2324    Tcl_CreateObjCommand(interp, "heightmap",   HeightMapCmd,   clientData, NULL);
     2325    Tcl_CreateObjCommand(interp, "imgflush",    ImageFlushCmd,  clientData, NULL);
     2326    Tcl_CreateObjCommand(interp, "legend",      LegendCmd,      clientData, NULL);
     2327    Tcl_CreateObjCommand(interp, "screen",      ScreenCmd,      clientData, NULL);
     2328    Tcl_CreateObjCommand(interp, "snapshot",    SnapshotCmd,    clientData, NULL);
     2329    Tcl_CreateObjCommand(interp, "transfunc",   TransfuncCmd,   clientData, NULL);
     2330    Tcl_CreateObjCommand(interp, "up",          UpCmd,          clientData, NULL);
     2331    Tcl_CreateObjCommand(interp, "volume",      VolumeCmd,      clientData, NULL);
    22022332
    22032333    // create a default transfer function
     
    22062336             Tcl_GetStringResult(interp));
    22072337    }
    2208     return interp;
    2209 }
     2338}
Note: See TracChangeset for help on using the changeset viewer.