Esempio n. 1
0
static void removeWorker(EjsWorker *worker) 
{
    Ejs     *ejs;

    assert(!worker->inside);
    assert(worker);

    ejs = worker->ejs;
    if (ejs) {
        lock(ejs);
        if (ejs->workers) {
            mprRemoveItem(ejs->workers, worker);
        }
        if (ejs->joining) {
            mprSignalDispatcher(ejs->dispatcher);
        }
        /* Accelerate GC */
        if (worker->pair) {
            worker->pair->ejs = 0;
            worker->pair->pair = 0;
            worker->pair = 0;
        }
        worker->ejs = 0;        
        unlock(ejs);
    }
}
Esempio n. 2
0
PUBLIC void mprSignalCompletion(MprDispatcher *dispatcher)
{
    if (dispatcher == 0) {
        dispatcher = MPR->dispatcher;
    }
    dispatcher->flags |= MPR_DISPATCHER_COMPLETE;
    mprSignalDispatcher(dispatcher);
}
Esempio n. 3
0
/*
    Schedule a dispatcher to run but don't disturb an already running dispatcher. If the event queue is empty,
    the dispatcher is moved to the idleQ. If there is a past-due event, it is moved to the readyQ. If there is a future
    event pending, it is put on the waitQ.
 */
PUBLIC void mprScheduleDispatcher(MprDispatcher *dispatcher)
{
    MprEventService     *es;
    MprEvent            *event;
    int                 mustWakeWaitService, mustWakeCond;

    assert(dispatcher);
    if (dispatcher->flags & MPR_DISPATCHER_DESTROYED) {
        return;
    }
    if ((es = dispatcher->service) == 0) {
        return;
    }
    lock(es);
    mustWakeWaitService = es->waiting;

    if (isRunning(dispatcher)) {
        mustWakeCond = dispatcher->flags & MPR_DISPATCHER_WAITING;

    } else if (isEmpty(dispatcher)) {
        queueDispatcher(es->idleQ, dispatcher);
        mustWakeCond = dispatcher->flags & MPR_DISPATCHER_WAITING;

    } else {
        event = dispatcher->eventQ->next;
        mustWakeWaitService = mustWakeCond = 0;
        if (event->due > es->now) {
            queueDispatcher(es->waitQ, dispatcher);
            if (event->due < es->willAwake) {
                mustWakeWaitService = 1;
                mustWakeCond = dispatcher->flags & MPR_DISPATCHER_WAITING;
            }
        } else {
            queueDispatcher(es->readyQ, dispatcher);
            mustWakeWaitService = es->waiting;
            mustWakeCond = dispatcher->flags & MPR_DISPATCHER_WAITING;
        }
    }
    unlock(es);
    if (mustWakeCond) {
        mprSignalDispatcher(dispatcher);
    }
    if (mustWakeWaitService) {
        mprWakeEventService();
    }
}
Esempio n. 4
0
/*
    function terminate(): Void
 */
static EjsObj *workerTerminate(Ejs *ejs, EjsWorker *worker, int argc, EjsObj **argv)
{    
    if (worker->state == EJS_WORKER_BEGIN) {
        ejsThrowStateError(ejs, "Worker has not yet started");
        return 0;
    }
    if (worker->state >= EJS_WORKER_COMPLETE) {
        return 0;
    }
    /*
        Switch to the inside worker if called from outside
     */
    assert(worker->pair && worker->pair->ejs);
    ejs = (!worker->inside) ? worker->pair->ejs : ejs;
    ejs->exiting = 1;
    mprSignalDispatcher(ejs->dispatcher);
    return 0;
}
Esempio n. 5
0
/*
    Process a message sent from postMessage. This may run inside the worker or outside in the parent depending on the
    direction of the message. But it ALWAYS runs in the appropriate thread for the interpreter.
 */
static int doMessage(Message *msg, MprEvent *mprEvent)
{
    Ejs         *ejs;
    EjsObj      *event, *frame;
    EjsWorker   *worker;
    EjsFunction *callback;
    EjsObj      *argv[1];

    worker = msg->worker;
    worker->gotMessage = 1;
    ejs = worker->ejs;
    assert(!ejs->exception);

    event = 0;
    ejsBlockGC(ejs);

    callback = ejsGetProperty(ejs, worker, msg->callbackSlot);

    switch (msg->callbackSlot) {
    case ES_Worker_onerror:
        event = ejsCreateObj(ejs, ESV(ErrorEvent), 0);
        break;
            
    case ES_Worker_onclose:
    case ES_Worker_onmessage:
        event = ejsCreateObj(ejs, ESV(Event), 0);
        break;
            
    default:
        assert(msg->callbackSlot == 0);
        return 0;
    }
    worker->event = event;
    if (msg->data) {
        ejsSetProperty(ejs, event, ES_Event_data, ejsCreateStringFromAsc(ejs, msg->data));
    }
    if (msg->message) {
        ejsSetProperty(ejs, event, ES_ErrorEvent_message, msg->message);
    }
    if (msg->stack) {
        ejsSetProperty(ejs, event, ES_ErrorEvent_stack, msg->stack);
        if ((frame = ejsGetProperty(ejs, msg->stack, 0)) != 0 && !ejsIs(ejs, frame, Void)) {
            ejsSetProperty(ejs, event, ES_ErrorEvent_filename, ejsGetPropertyByName(ejs, frame, EN("filename")));
            ejsSetProperty(ejs, event, ES_ErrorEvent_lineno, ejsGetPropertyByName(ejs, frame, EN("lineno")));
        }
    }
    assert(!ejs->exception);

    if (callback == 0 || ejsIs(ejs, callback, Null)) {
        if (msg->callbackSlot == ES_Worker_onmessage) {
            mprTrace(6, "Discard message as no onmessage handler defined for worker");
            
        } else if (msg->callbackSlot == ES_Worker_onerror) {
            if (ejsIs(ejs, msg->message, String)) {
                ejsThrowError(ejs, "Exception in Worker: %@", ejsToString(ejs, msg->message));
            } else {
                ejsThrowError(ejs, "Exception in Worker: %s", ejsGetErrorMsg(worker->pair->ejs, 1));
            }
        } else {
            /* Ignore onclose message */
        }

    } else if (!ejsIsFunction(ejs, callback)) {
        ejsThrowTypeError(ejs, "Worker callback %s is not a function", msg->callback);

    } else {
        assert(!ejs->exception);
        argv[0] = event;
        ejsRunFunction(ejs, callback, worker, 1, argv);
    }
    if (msg->callbackSlot == ES_Worker_onclose) {
        assert(!worker->inside);
        worker->state = EJS_WORKER_COMPLETE;
        mprTrace(5, "Worker.doMessage: complete");
        /* Worker and insider interpreter are now eligible for garbage collection */
        removeWorker(worker);
    }
    mprSignalDispatcher(ejs->dispatcher);
    worker->event = 0;
    return 0;
}