Esempio n. 1
0
// This is the entry point for the file watcher thread. It scans local files
// for changes and processes the diffs with processFileEntryDeltas.
static int fileWatcherThread(void *payload)
{
    // Start with a sane state so we don't stream everything.
    utArray<FileEntry> *oldState = generateFileState(".");

    // Loop forever looking for changes.
    for ( ; ; )
    {
        int startTime = platform_getMilliseconds();

        utArray<FileEntry>      *newState = generateFileState(".");
        utArray<FileEntryDelta> *deltas   = compareFileEntries(oldState, newState);

        int endTime = platform_getMilliseconds();

        if (endTime - startTime > 250)
        {
            lmLogWarn(gAssetAgentLogGroup, "Scanning files took %dms, consider removing unused files", endTime - startTime);
        }

        processFileEntryDeltas(deltas);

        lmDelete(NULL, deltas);

        // Make the new state the old state and clean up the old state.
        lmDelete(NULL, oldState);
        oldState = newState;

        // Wait a bit so we don't saturate disk or CPU.
        loom_thread_sleep(gFileCheckInterval);
    }
}
Esempio n. 2
0
int loom_net_writeTCPSocket(loom_socketId_t s, void *buffer, int bytesToWrite)
{
#if LOOM_PLATFORM == LOOM_PLATFORM_WIN32
    int winsockErrorCode;
#endif

    int bytesLeft = bytesToWrite;
    for ( ; ; )
    {
        int result = send((SOCKET)s, buffer, bytesLeft, MSG_NOSIGNAL);

        if (result >= 0)
        {
            bytesLeft -= result;
            if (bytesLeft != 0)
            {
                lmLogDebug(netLogGroup, "Partial write on socket %d, expected %d but wrote %d! Retrying...", s, bytesToWrite, result);

                // Set up to try again by advancing into the buffer.
                buffer = (void *)((char *)buffer + result);
                continue;
            }

            return bytesToWrite - bytesLeft;
        }

#if LOOM_PLATFORM == LOOM_PLATFORM_WIN32
        winsockErrorCode = WSAGetLastError();
        if (winsockErrorCode != WSAEWOULDBLOCK)
        {
            break;
        }
#else
        if (errno != EAGAIN)
        {
            break;
        }
#endif

        if (loom_net_isSocketDead(s))
        {
            break;
        }

        loom_thread_sleep(5);
    }

    return -1;
}
Esempio n. 3
0
void loom_asset_waitForConnection(int msToWait)
{
    // be extra agressive before starting up
    gAssetServerConnectTryInterval = 10;

    int startTime = platform_getMilliseconds();
    while (!gAssetConnectionOpen && (platform_getMilliseconds() - startTime) < msToWait)
    {
        loom_asset_pump();
        loom_thread_sleep(10);
    }

    // Go back to pinging every 3 seconds
    gAssetServerConnectTryInterval = 3000;
}
Esempio n. 4
0
void loom_net_readTCPSocket(loom_socketId_t s, void *buffer, int *bytesToRead, int peek /*= 0*/)
{
    int errorCode;

    int waiting;

    int tmp = *bytesToRead;

    int bytesLeft;

    if (loom_net_isSocketDead(s))
    {
        *bytesToRead = 0;
        return;
    }

    if (peek) {
        *bytesToRead = recv((SOCKET)s, buffer, tmp, MSG_PEEK);
        return;
    }

    bytesLeft = *bytesToRead;

    while (bytesLeft > 0)
    {
        int received = recv((SOCKET)s, buffer, bytesLeft, 0);
        if (received == -1) {
            waiting = 0;
#if LOOM_PLATFORM == LOOM_PLATFORM_WIN32
            errorCode = WSAGetLastError();
            if (errorCode == WSAEWOULDBLOCK)
            {
                waiting = 1;
            }
#else
            errorCode = errno;
            if (errorCode == EAGAIN)
            {
                waiting = 1;
            }
#endif
            if (waiting)
            {
                // TODO figure out a better way to do this?
                //lmLogDebug(netLogGroup, "Waiting for receive buffer %d / %d", *bytesToRead - bytesLeft, *bytesToRead);
                loom_thread_sleep(5);
                continue;
            }
            else
            {
                lmLogError(netLogGroup, "Read socket error (%d)", errorCode);
                *bytesToRead = -1;
                return;
            }
        }
        bytesLeft -= received;
        buffer = (char*)buffer + received;
    }

    lmAssert(bytesLeft == 0, "Internal recv error, read too much data? %d", bytesLeft);
}
Esempio n. 5
0
void DLLEXPORT assetAgent_run(IdleCallback idleCb, LogCallback logCb, FileChangeCallback changeCb)
{
    loom_log_initialize();
    platform_timeInitialize();
    stringtable_initialize();
    loom_net_initialize();

    // Put best effort towards closing our listen socket when we shut down, to
    // avoid bugs on OSX where the OS won't release it for a while.

#if LOOM_PLATFORM == LOOM_PLATFORM_OSX || LOOM_PLATFORM == LOOM_PLATFORM_LINUX
    atexit(shutdownListenSocket);
    signal(SIGINT, shutdownListenSocketSignalHandler);
#endif

    // Set up mutexes.
    gActiveSocketsMutex = loom_mutex_create();
    gFileScannerLock    = loom_mutex_create();
    gCallbackLock       = loom_mutex_create();

    // Note callbacks.
    gLogCallback        = logCb;
    gFileChangeCallback = changeCb;


    utString *sdkPath = optionGet("sdk");
    if (sdkPath != NULL) TelemetryServer::setClientRootFromSDK(sdkPath->c_str());
    const char *ltcPath = getenv("LoomTelemetry");
    if (ltcPath != NULL) TelemetryServer::setClientRoot(ltcPath);

    if (optionEquals("telemetry", "true")) TelemetryServer::start();



    // Set up the log callback.
    loom_log_addListener(fileWatcherLogListener, NULL);

    lmLogDebug(gAssetAgentLogGroup, "Starting file watcher thread...");
    gFileWatcherThread = loom_thread_start((ThreadFunction)fileWatcherThread, NULL);
    lmLogDebug(gAssetAgentLogGroup, "   o OK!");

    lmLogDebug(gAssetAgentLogGroup, "Starting socket listener thread...");
    gSocketListenerThread = loom_thread_start((ThreadFunction)socketListeningThread, NULL);
    lmLogDebug(gAssetAgentLogGroup, "   o OK!");

    // Loop till it's time to quit.
    while (!gQuitFlag)
    {
        // Serve the idle callback.
        if (idleCb)
        {
            idleCb();
        }

        // And anything in the queue.
        while (CallbackQueueNote *cqn = dequeueCallback())
        {
            if (!cqn)
            {
                break;
            }

            // Issue the call.
            if (cqn->type == QNT_Change)
            {
                gFileChangeCallback(cqn->text.c_str());
            }
            else if (cqn->type == QNT_Log)
            {
                gLogCallback(cqn->text.c_str());
            }
            else
            {
                lmAssert(false, "Unknown callback queue note type.");
            }

            // Clean it up.
            //free((void *)cqn->text);
            lmDelete(NULL, cqn);
        }
        // Pump any remaining socket writes
        loom_net_pump();

        // Poll at about 60hz.
        loom_thread_sleep(16);
    }

    // Clean up the socket.
    shutdownListenSocket();
}
Esempio n. 6
0
// Entry point for the socket thread. Listen for connections and incoming data,
// and route it to the protocol handlers.
static int socketListeningThread(void *payload)
{
    // Listen for incoming connections.
    int listenPort = 12340;

    gListenSocket = (loom_socketId_t)-1;
    for ( ; ; )
    {
        gListenSocket = loom_net_listenTCPSocket(listenPort);

        if (gListenSocket != (loom_socketId_t)-1)
        {
            break;
        }

        lmLogWarn(gAssetAgentLogGroup, "   - Failed to acquire port %d, trying port %d", listenPort, listenPort + 1);
        listenPort++;
    }

    lmLog(gAssetAgentLogGroup, "Listening on port %d", listenPort);

    while (loom_socketId_t acceptedSocket = loom_net_acceptTCPSocket(gListenSocket))
    {
        // Check to see if we got anybody...
        if (!acceptedSocket || ((int)(long)acceptedSocket == -1))
        {
            // Process the connections.
            loom_mutex_lock(gActiveSocketsMutex);
            
            for (UTsize i = 0; i < gActiveHandlers.size(); i++)
            {
                AssetProtocolHandler* aph = gActiveHandlers[i];
                aph->process();

                // Check for ping timeout
                int msSincePing = loom_readTimer(aph->lastActiveTime);
                if (msSincePing > socketPingTimeoutMs)
                {
                    gActiveHandlers.erase(i);
                    i--;
                    lmLog(gAssetAgentLogGroup, "Client timed out (%x)", aph->socket);
                    loom_net_closeTCPSocket(aph->socket);
                    lmDelete(NULL, aph);
                }
            }

            loom_mutex_unlock(gActiveSocketsMutex);

            loom_thread_sleep(10);
            continue;
        }

        lmLog(gAssetAgentLogGroup, "Client connected (%x)", acceptedSocket);

        loom_mutex_lock(gActiveSocketsMutex);
        gActiveHandlers.push_back(lmNew(NULL) AssetProtocolHandler(acceptedSocket));

        AssetProtocolHandler *handler = gActiveHandlers.back();
        handler->registerListener(lmNew(NULL) TelemetryListener());
        if (TelemetryServer::isRunning()) handler->sendCommand("telemetryEnable");

        // Send it all of our files.
        // postAllFiles(gActiveHandlers[gActiveHandlers.size()-1]->getId());

        loom_mutex_unlock(gActiveSocketsMutex);
    }

    return 0;
}
Esempio n. 7
0
task_t *dummyChildTask(void *payload, task_t *task)
{
    atomic_increment(&gChildWorkCount);
    loom_thread_sleep(2);
    return NULL;
}
Esempio n. 8
0
void loom_tick()
{
    if (atomic_load32(&gLoomTicking) < 1)
    {

        // Signal that the app has really stopped execution
        if (atomic_load32(&gLoomPaused) == 0)
        {
            atomic_store32(&gLoomPaused, 1);
        }

        // Sleep for longer while paused.
        // Since graphics aren't running in a paused state, there is no yielding
        // we would otherwise run in a busy loop without sleeping.
        loom_thread_sleep(30);

        return;
    }

    atomic_store32(&gLoomPaused, 0);

    Telemetry::beginTick();
    
    LOOM_PROFILE_START(loom_tick);

    LSLuaState *vm = NULL;

    vm = LoomApplication::getReloadQueued() ? NULL : LoomApplication::getRootVM();

    // Mark the main thread for NativeDelegates. On some platforms this
    // may change so we remark every frame.
    NativeDelegate::markMainThread();
    if (vm) NativeDelegate::executeDeferredCalls(vm->VM());

    performance_tick();

    profilerBlock_t p = { "loom_tick", platform_getMilliseconds(), 17 };
    
    if (LoomApplication::getReloadQueued())
    {
        LoomApplication::reloadMainAssembly();
    }
    else
    {
        if (vm)
        {
            // https://theengineco.atlassian.net/browse/LOOM-468
            // decouple debugger enabled from connection time
            // as the debugger matures this may change a bit
            if (LoomApplicationConfig::waitForDebugger() > 0)
            {
                vm->invokeStaticMethod("system.debugger.DebuggerClient", "update");
            }

            LoomApplication::ticks.invoke();
        }
    }
    
    loom_asset_pump();
    
    platform_HTTPUpdate();
    
    GFX::Texture::tick();
    
    if (Loom2D::Stage::smMainStage) Loom2D::Stage::smMainStage->invokeRenderStage();
    
    finishProfilerBlock(&p);
    
    LOOM_PROFILE_END(loom_tick);
    
    LOOM_PROFILE_ZERO_CHECK()
    
    Telemetry::endTick();

}