Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 26 Dec 2018 20:36:58 +0000 (UTC)
From:      Steve Wills <swills@FreeBSD.org>
To:        ports-committers@freebsd.org, svn-ports-all@freebsd.org, svn-ports-head@freebsd.org
Subject:   svn commit: r488434 - in head/games/oolite: . files
Message-ID:  <201812262036.wBQKawYj055784@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: swills
Date: Wed Dec 26 20:36:58 2018
New Revision: 488434
URL: https://svnweb.freebsd.org/changeset/ports/488434

Log:
  games/oolite: Update to 1.88
  
  PR:		234408
  Submitted by:	lightside <lightside@gmx.com>

Modified:
  head/games/oolite/Makefile   (contents, props changed)
  head/games/oolite/distinfo   (contents, props changed)
  head/games/oolite/files/patch-deps_mozilla-bug771281   (contents, props changed)

Modified: head/games/oolite/Makefile
==============================================================================
--- head/games/oolite/Makefile	Wed Dec 26 20:34:47 2018	(r488433)
+++ head/games/oolite/Makefile	Wed Dec 26 20:36:58 2018	(r488434)
@@ -2,10 +2,9 @@
 # $FreeBSD$
 
 PORTNAME=		oolite
-PORTVERSION=		1.86
-PORTREVISION=	1
+PORTVERSION=		1.88
 CATEGORIES=		games gnustep
-MASTER_SITES=		https://github.com/OoliteProject/oolite/releases/download/1.86/
+MASTER_SITES=		https://github.com/OoliteProject/oolite/releases/download/1.88/
 DISTNAME=		${PORTNAME}-source-${PORTVERSION}
 DIST_SUBDIR=		oolite
 
@@ -24,7 +23,7 @@ LIB_DEPENDS=		libespeak.so:audio/espeak \
 			libpng.so:graphics/png \
 			libminizip.so:archivers/minizip
 
-USES=			gnustep openal:al perl5 python:build tar:bzip2
+USES=			gl gnustep openal:al perl5 python:build tar:bzip2
 USE_CXXSTD=		gnu++98
 USE_GL=			gl glu
 USE_SDL=		sdl
@@ -47,7 +46,7 @@ DATADIR=	${GNUSTEP_LOCAL_APPS}/oolite.app
 PORTDATA=	Resources
 PORTDOCS=	*.pdf CHANGELOG.TXT contributors.txt
 
-PLIST_FILES+=	bin/oolite %%DATADIR%%/oolite \
+PLIST_FILES+=	bin/oolite ${DATADIR}/oolite \
 		share/applications/oolite.desktop \
 		share/pixmaps/oolite-icon.png
 

Modified: head/games/oolite/distinfo
==============================================================================
--- head/games/oolite/distinfo	Wed Dec 26 20:34:47 2018	(r488433)
+++ head/games/oolite/distinfo	Wed Dec 26 20:36:58 2018	(r488434)
@@ -1,3 +1,3 @@
-TIMESTAMP = 1508936871
-SHA256 (oolite/oolite-source-1.86.tar.bz2) = 9f99c72f433fbbad972abdac5104775b29994d73c0b35f05130b31522b70ec9a
-SIZE (oolite/oolite-source-1.86.tar.bz2) = 144561828
+TIMESTAMP = 1540654199
+SHA256 (oolite/oolite-source-1.88.tar.bz2) = 298abec5f9192b121003bf8d84fbf22eb137e5ce66f1a1469ca24fd582ab97e9
+SIZE (oolite/oolite-source-1.88.tar.bz2) = 145146957

Modified: head/games/oolite/files/patch-deps_mozilla-bug771281
==============================================================================
--- head/games/oolite/files/patch-deps_mozilla-bug771281	Wed Dec 26 20:34:47 2018	(r488433)
+++ head/games/oolite/files/patch-deps_mozilla-bug771281	Wed Dec 26 20:36:58 2018	(r488434)
@@ -84,1291 +84,6 @@ diff -ruN deps.orig/mozilla/js/src/shell/js.cpp deps/m
  #ifdef JSDEBUGGER
      if (jsdc) {
  #ifdef JSDEBUGGER_C_UI
-diff -ruN deps.orig/mozilla/js/src/shell/jsworkers.cpp.rej deps/mozilla/js/src/shell/jsworkers.cpp.rej
---- deps.orig/mozilla/js/src/shell/jsworkers.cpp.rej	1970-01-01 00:00:00 UTC
-+++ deps/mozilla/js/src/shell/jsworkers.cpp.rej
-@@ -0,0 +1,1281 @@
-+@@ -1,1280 +0,0 @@
-+-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
-+- * vim: set ts=8 sw=4 et tw=99:
-+- *
-+- * ***** BEGIN LICENSE BLOCK *****
-+- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
-+- *
-+- * The contents of this file are subject to the Mozilla Public License Version
-+- * 1.1 (the "License"); you may not use this file except in compliance with
-+- * the License. You may obtain a copy of the License at
-+- * http://www.mozilla.org/MPL/
-+- *
-+- * Software distributed under the License is distributed on an "AS IS" basis,
-+- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
-+- * for the specific language governing rights and limitations under the
-+- * License.
-+- *
-+- * The Original Code is JavaScript shell workers.
-+- *
-+- * The Initial Developer of the Original Code is
-+- * Mozilla Corporation.
-+- * Portions created by the Initial Developer are Copyright (C) 2010
-+- * the Initial Developer. All Rights Reserved.
-+- *
-+- * Contributor(s):
-+- *   Jason Orendorff <jorendorff@mozilla.com>
-+- *
-+- * Alternatively, the contents of this file may be used under the terms of
-+- * either of the GNU General Public License Version 2 or later (the "GPL"),
-+- * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
-+- * in which case the provisions of the GPL or the LGPL are applicable instead
-+- * of those above. If you wish to allow use of your version of this file only
-+- * under the terms of either the GPL or the LGPL, and not to allow others to
-+- * use your version of this file under the terms of the MPL, indicate your
-+- * decision by deleting the provisions above and replace them with the notice
-+- * and other provisions required by the GPL or the LGPL. If you do not delete
-+- * the provisions above, a recipient may use your version of this file under
-+- * the terms of any one of the MPL, the GPL or the LGPL.
-+- *
-+- * ***** END LICENSE BLOCK ***** */
-+-
-+-#ifdef JS_THREADSAFE
-+-
-+-#include <algorithm>
-+-#include <string.h>
-+-#include "prthread.h"
-+-#include "prlock.h"
-+-#include "prcvar.h"
-+-#include "jsapi.h"
-+-#include "jscntxt.h"
-+-#include "jshashtable.h"
-+-#include "jsstdint.h"
-+-#include "jslock.h"
-+-#include "jsvector.h"
-+-#include "jsworkers.h"
-+-
-+-extern size_t gMaxStackSize;
-+-
-+-/*
-+- * JavaScript shell workers.
-+- *
-+- * == Object lifetime rules ==
-+- *
-+- *   - The ThreadPool lasts from init() to finish().
-+- *
-+- *   - The ThreadPool owns the MainQueue and the WorkerQueue. Those live from
-+- *     the time the first Worker is created until finish().
-+- *
-+- *   - Each JS Worker object has the same lifetime as the corresponding C++
-+- *     Worker object. A Worker is live if (a) the Worker JSObject is still
-+- *     live; (b) the Worker has an incoming event pending or running; (c) it
-+- *     has sent an outgoing event to its parent that is still pending; or (d)
-+- *     it has any live child Workers.
-+- *
-+- *   - finish() continues to wait for events until all threads are idle.
-+- *
-+- * Event objects, however, are basically C++-only. The JS Event objects are
-+- * just plain old JSObjects. They don't keep anything alive.
-+- *
-+- * == Locking scheme ==
-+- *
-+- * When mixing mutexes and the JSAPI request model, there are two choices:
-+- *
-+- *   - Always nest the mutexes in requests. Since threads in requests are not
-+- *     supposed to block, this means the mutexes must be only briefly held.
-+- *
-+- *   - Never nest the mutexes in requests. Since this allows threads to race
-+- *     with the GC, trace() methods must go through the mutexes just like
-+- *     everyone else.
-+- *
-+- * This code uses the latter approach for all locks.
-+- *
-+- * In one case, a thread holding a Worker's mutex can acquire the mutex of one
-+- * of its child Workers. See Worker::terminateSelf. (This can't deadlock because
-+- * the parent-child relationship is a partial order.)
-+- */
-+-
-+-namespace js {
-+-namespace workers {
-+-
-+-template <class T, class AllocPolicy>
-+-class Queue {
-+-  private:
-+-    typedef Vector<T, 4, AllocPolicy> Vec;
-+-    Vec v1;
-+-    Vec v2;
-+-    Vec *front;
-+-    Vec *back;
-+-
-+-    // Queue is not copyable.
-+-    Queue(const Queue &);
-+-    Queue & operator=(const Queue &);
-+-
-+-  public:
-+-    Queue() : front(&v1), back(&v2) {}
-+-    bool push(T t) { return back->append(t); }
-+-    bool empty() { return front->empty() && back->empty(); }
-+-
-+-    T pop() {
-+-        if (front->empty()) {
-+-            std::reverse(back->begin(), back->end());
-+-            Vec *tmp = front;
-+-            front = back;
-+-            back = tmp;
-+-        }
-+-        T item = front->back();
-+-        front->popBack();
-+-        return item;
-+-    }        
-+-
-+-    void clear() {
-+-        v1.clear();
-+-        v2.clear();
-+-    }
-+-
-+-    void trace(JSTracer *trc) {
-+-        for (T *p = v1.begin(); p != v1.end(); p++)
-+-            (*p)->trace(trc);
-+-        for (T *p = v2.begin(); p != v2.end(); p++)
-+-            (*p)->trace(trc);
-+-    }
-+-};
-+-
-+-class Event;
-+-class ThreadPool;
-+-class Worker;
-+-
-+-class WorkerParent {
-+-  protected:
-+-    typedef HashSet<Worker *, DefaultHasher<Worker *>, SystemAllocPolicy> ChildSet;
-+-    ChildSet children;
-+-
-+-    bool initWorkerParent() { return children.init(8); }
-+-
-+-  public:
-+-    virtual JSLock *getLock() = 0;
-+-    virtual ThreadPool *getThreadPool() = 0;
-+-    virtual bool post(Event *item) = 0;  // false on OOM or queue closed
-+-    virtual void trace(JSTracer *trc) = 0;
-+-
-+-    bool addChild(Worker *w) {
-+-        AutoLock hold(getLock());
-+-        return children.put(w) != NULL;
-+-    }
-+-
-+-    // This must be called only from GC or when all threads are shut down. It
-+-    // does not bother with locking.
-+-    void removeChild(Worker *w) {
-+-        ChildSet::Ptr p = children.lookup(w);
-+-        JS_ASSERT(p);
-+-        children.remove(p);
-+-    }
-+-
-+-    void disposeChildren();
-+-};
-+-
-+-template <class T>
-+-class ThreadSafeQueue
-+-{
-+-  protected:
-+-    Queue<T, SystemAllocPolicy> queue;
-+-    JSLock *lock;
-+-    PRCondVar *condvar;
-+-    bool closed;
-+-
-+-  private:
-+-    Vector<T, 8, SystemAllocPolicy> busy;
-+-
-+-  protected:
-+-    ThreadSafeQueue() : lock(NULL), condvar(NULL), closed(false) {}
-+-
-+-    ~ThreadSafeQueue() {
-+-        if (condvar)
-+-            JS_DESTROY_CONDVAR(condvar);
-+-        if (lock)
-+-            JS_DESTROY_LOCK(lock);
-+-    }
-+-
-+-    // Called by take() with the lock held.
-+-    virtual bool shouldStop() { return closed; }
-+-
-+-  public:
-+-    bool initThreadSafeQueue() {
-+-        JS_ASSERT(!lock);
-+-        JS_ASSERT(!condvar);
-+-        return (lock = JS_NEW_LOCK()) && (condvar = JS_NEW_CONDVAR(lock));
-+-    }
-+-
-+-    bool post(T t) {
-+-        AutoLock hold(lock);
-+-        if (closed)
-+-            return false;
-+-        if (queue.empty())
-+-            JS_NOTIFY_ALL_CONDVAR(condvar);
-+-        return queue.push(t);
-+-    }
-+-
-+-    void close() {
-+-        AutoLock hold(lock);
-+-        closed = true;
-+-        queue.clear();
-+-        JS_NOTIFY_ALL_CONDVAR(condvar);
-+-    }
-+-
-+-    // The caller must hold the lock.
-+-    bool take(T *t) {
-+-        while (queue.empty()) {
-+-            if (shouldStop())
-+-                return false;
-+-            JS_WAIT_CONDVAR(condvar, JS_NO_TIMEOUT);
-+-        }
-+-        *t = queue.pop();
-+-        busy.append(*t);
-+-        return true;
-+-    }
-+-
-+-    // The caller must hold the lock.
-+-    void drop(T item) {
-+-        for (T *p = busy.begin(); p != busy.end(); p++) {
-+-            if (*p == item) {
-+-                *p = busy.back();
-+-                busy.popBack();
-+-                return;
-+-            }
-+-        }
-+-        JS_NOT_REACHED("removeBusy");
-+-    }
-+-
-+-    bool lockedIsIdle() { return busy.empty() && queue.empty(); }
-+-
-+-    bool isIdle() {
-+-        AutoLock hold(lock);
-+-        return lockedIsIdle();
-+-    }
-+-
-+-    void wake() {
-+-        AutoLock hold(lock);
-+-        JS_NOTIFY_ALL_CONDVAR(condvar);
-+-    }
-+-
-+-    void trace(JSTracer *trc) {
-+-        AutoLock hold(lock);
-+-        for (T *p = busy.begin(); p != busy.end(); p++)
-+-            (*p)->trace(trc);
-+-        queue.trace(trc);
-+-    }
-+-};
-+-
-+-class MainQueue;
-+-
-+-class Event
-+-{
-+-  protected:
-+-    virtual ~Event() { JS_ASSERT(!data); }
-+-
-+-    WorkerParent *recipient;
-+-    Worker *child;
-+-    uint64 *data;
-+-    size_t nbytes;
-+-
-+-  public:
-+-    enum Result { fail = JS_FALSE, ok = JS_TRUE, forwardToParent };
-+-
-+-    virtual void destroy(JSContext *cx) { 
-+-        JS_free(cx, data);
-+-#ifdef DEBUG
-+-        data = NULL;
-+-#endif
-+-        delete this;
-+-    }
-+-
-+-    void setChildAndRecipient(Worker *aChild, WorkerParent *aRecipient) {
-+-        child = aChild;
-+-        recipient = aRecipient;
-+-    }
-+-
-+-    bool deserializeData(JSContext *cx, jsval *vp) {
-+-        return !!JS_ReadStructuredClone(cx, data, nbytes, JS_STRUCTURED_CLONE_VERSION, vp,
-+-                                        NULL, NULL);
-+-    }
-+-
-+-    virtual Result process(JSContext *cx) = 0;
-+-
-+-    inline void trace(JSTracer *trc);
-+-
-+-    template <class EventType>
-+-    static EventType *createEvent(JSContext *cx, WorkerParent *recipient, Worker *child,
-+-                                  jsval v)
-+-    {
-+-        uint64 *data;
-+-        size_t nbytes;
-+-        if (!JS_WriteStructuredClone(cx, v, &data, &nbytes, NULL, NULL))
-+-            return NULL;
-+-
-+-        EventType *event = new EventType;
-+-        if (!event) {
-+-            JS_ReportOutOfMemory(cx);
-+-            return NULL;
-+-        }
-+-        event->recipient = recipient;
-+-        event->child = child;
-+-        event->data = data;
-+-        event->nbytes = nbytes;
-+-        return event;
-+-    }
-+-
-+-    Result dispatch(JSContext *cx, JSObject *thisobj, const char *dataPropName,
-+-                    const char *methodName, Result noHandler)
-+-    {
-+-        if (!data)
-+-            return fail;
-+-
-+-        JSBool found;
-+-        if (!JS_HasProperty(cx, thisobj, methodName, &found))
-+-            return fail;
-+-        if (!found)
-+-            return noHandler;
-+-
-+-        // Create event object.
-+-        jsval v;
-+-        if (!deserializeData(cx, &v))
-+-            return fail;
-+-        JSObject *obj = JS_NewObject(cx, NULL, NULL, NULL);
-+-        if (!obj || !JS_DefineProperty(cx, obj, dataPropName, v, NULL, NULL, 0))
-+-            return fail;
-+-
-+-        // Call event handler.
-+-        jsval argv[1] = { OBJECT_TO_JSVAL(obj) };
-+-        jsval rval = JSVAL_VOID;
-+-        return Result(JS_CallFunctionName(cx, thisobj, methodName, 1, argv, &rval));
-+-    }
-+-};
-+-
-+-typedef ThreadSafeQueue<Event *> EventQueue;
-+-
-+-class MainQueue : public EventQueue, public WorkerParent
-+-{
-+-  private:
-+-    ThreadPool *threadPool;
-+-
-+-  public:
-+-    explicit MainQueue(ThreadPool *tp) : threadPool(tp) {}
-+-
-+-    ~MainQueue() {
-+-        JS_ASSERT(queue.empty());
-+-    }
-+-
-+-    bool init() { return initThreadSafeQueue() && initWorkerParent(); }
-+-
-+-    void destroy(JSContext *cx) {
-+-        while (!queue.empty())
-+-            queue.pop()->destroy(cx);
-+-        delete this;
-+-    }
-+-
-+-    virtual JSLock *getLock() { return lock; }
-+-    virtual ThreadPool *getThreadPool() { return threadPool; }
-+-
-+-  protected:
-+-    virtual bool shouldStop();
-+-
-+-  public:
-+-    virtual bool post(Event *event) { return EventQueue::post(event); }
-+-
-+-    virtual void trace(JSTracer *trc);
-+-
-+-    void traceChildren(JSTracer *trc) { EventQueue::trace(trc); }
-+-
-+-    JSBool mainThreadWork(JSContext *cx, bool continueOnError) {
-+-        JSAutoSuspendRequest suspend(cx);
-+-        AutoLock hold(lock);
-+-
-+-        Event *event;
-+-        while (take(&event)) {
-+-            JS_RELEASE_LOCK(lock);
-+-            Event::Result result;
-+-            {
-+-                JSAutoRequest req(cx);
-+-                result = event->process(cx);
-+-                if (result == Event::forwardToParent) {
-+-                    // FIXME - pointlessly truncates the string to 8 bits
-+-                    jsval data;
-+-                    JSAutoByteString bytes;
-+-                    if (event->deserializeData(cx, &data) &&
-+-                        JSVAL_IS_STRING(data) &&
-+-                        bytes.encode(cx, JSVAL_TO_STRING(data))) {
-+-                        JS_ReportError(cx, "%s", bytes.ptr());
-+-                    } else {
-+-                        JS_ReportOutOfMemory(cx);
-+-                    }
-+-                    result = Event::fail;
-+-                }
-+-                if (result == Event::fail && continueOnError) {
-+-                    if (JS_IsExceptionPending(cx) && !JS_ReportPendingException(cx))
-+-                        JS_ClearPendingException(cx);
-+-                    result = Event::ok;
-+-                }
-+-            }
-+-            JS_ACQUIRE_LOCK(lock);
-+-            drop(event);
-+-            event->destroy(cx);
-+-            if (result != Event::ok)
-+-                return false;
-+-        }
-+-        return true;
-+-    }
-+-};
-+-
-+-/*
-+- * A queue of workers.
-+- *
-+- * We keep a queue of workers with pending events, rather than a queue of
-+- * events, so that two threads won't try to run a Worker at the same time.
-+- */
-+-class WorkerQueue : public ThreadSafeQueue<Worker *>
-+-{
-+-  private:
-+-    MainQueue *main;
-+-
-+-  public:
-+-    explicit WorkerQueue(MainQueue *main) : main(main) {}
-+-
-+-    void work();
-+-};
-+-
-+-/* The top-level object that owns everything else. */
-+-class ThreadPool
-+-{
-+-  private:
-+-    enum { threadCount = 6 };
-+-
-+-    JSObject *obj;
-+-    WorkerHooks *hooks;
-+-    MainQueue *mq;
-+-    WorkerQueue *wq;
-+-    PRThread *threads[threadCount];
-+-    int32_t terminating;
-+-
-+-    static JSClass jsClass;
-+-
-+-    static void start(void* arg) {
-+-        ((WorkerQueue *) arg)->work();
-+-    }
-+-
-+-    explicit ThreadPool(WorkerHooks *hooks) : hooks(hooks), mq(NULL), wq(NULL), terminating(0) {
-+-        for (int i = 0; i < threadCount; i++)
-+-            threads[i] = NULL;
-+-    }
-+-
-+-  public:
-+-    ~ThreadPool() {
-+-        JS_ASSERT(!mq);
-+-        JS_ASSERT(!wq);
-+-        JS_ASSERT(!threads[0]);
-+-    }
-+-
-+-    static ThreadPool *create(JSContext *cx, WorkerHooks *hooks) {
-+-        ThreadPool *tp = new ThreadPool(hooks);
-+-        if (!tp) {
-+-            JS_ReportOutOfMemory(cx);
-+-            return NULL;
-+-        }
-+-
-+-        JSObject *obj = JS_NewObject(cx, &jsClass, NULL, NULL);
-+-        if (!obj || !JS_SetPrivate(cx, obj, tp)) {
-+-            delete tp;
-+-            return NULL;
-+-        }
-+-        tp->obj = obj;
-+-        return tp;
-+-    }
-+-
-+-    JSObject *asObject() { return obj; }
-+-    WorkerHooks *getHooks() { return hooks; }
-+-    WorkerQueue *getWorkerQueue() { return wq; }
-+-    MainQueue *getMainQueue() { return mq; }
-+-    bool isTerminating() { return terminating != 0; }
-+-
-+-    /*
-+-     * Main thread only. Requires request (to prevent GC, which could see the
-+-     * object in an inconsistent state).
-+-     */
-+-    bool start(JSContext *cx) {
-+-        JS_ASSERT(!mq && !wq);
-+-        mq = new MainQueue(this);
-+-        if (!mq || !mq->init()) {
-+-            mq->destroy(cx);
-+-            mq = NULL;
-+-            return false;
-+-        }
-+-        wq = new WorkerQueue(mq);
-+-        if (!wq || !wq->initThreadSafeQueue()) {
-+-            delete wq;
-+-            wq = NULL;
-+-            mq->destroy(cx);
-+-            mq = NULL;
-+-            return false;
-+-        }
-+-        JSAutoSuspendRequest suspend(cx);
-+-        bool ok = true;
-+-        for (int i = 0; i < threadCount; i++) {
-+-            threads[i] = PR_CreateThread(PR_USER_THREAD, start, wq, PR_PRIORITY_NORMAL,
-+-                                         PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0);
-+-            if (!threads[i]) {
-+-                shutdown(cx);
-+-                ok = false;
-+-                break;
-+-            }
-+-        }
-+-        return ok;
-+-    }
-+-
-+-    void terminateAll(JSRuntime *rt) {
-+-        // See comment about JS_ATOMIC_SET in the implementation of
-+-        // JS_TriggerOperationCallback.
-+-        JS_ATOMIC_SET(&terminating, 1);
-+-        JS_TriggerAllOperationCallbacks(rt);
-+-    }
-+-
-+-    /* This context is used only to free memory. */
-+-    void shutdown(JSContext *cx) {
-+-        wq->close();
-+-        for (int i = 0; i < threadCount; i++) {
-+-            if (threads[i]) {
-+-                PR_JoinThread(threads[i]);
-+-                threads[i] = NULL;
-+-            }
-+-        }
-+-
-+-        delete wq;
-+-        wq = NULL;
-+-
-+-        mq->disposeChildren();
-+-        mq->destroy(cx);
-+-        mq = NULL;
-+-        terminating = 0;
-+-    }
-+-
-+-  private:
-+-    static void jsTraceThreadPool(JSTracer *trc, JSObject *obj) {
-+-        ThreadPool *tp = unwrap(trc->context, obj);
-+-        if (tp->mq) {
-+-            tp->mq->traceChildren(trc);
-+-            tp->wq->trace(trc);
-+-        }
-+-    }
-+-
-+-
-+-    static void jsFinalize(JSContext *cx, JSObject *obj) {
-+-        if (ThreadPool *tp = unwrap(cx, obj))
-+-            delete tp;
-+-    }
-+-
-+-  public:
-+-    static ThreadPool *unwrap(JSContext *cx, JSObject *obj) {
-+-        JS_ASSERT(JS_GET_CLASS(cx, obj) == &jsClass);
-+-        return (ThreadPool *) JS_GetPrivate(cx, obj);
-+-    }
-+-};
-+-
-+-/*
-+- * A Worker is always in one of 4 states, except when it is being initialized
-+- * or destroyed, or its lock is held:
-+- *   - idle       (!terminated && current == NULL && events.empty())
-+- *   - enqueued   (!terminated && current == NULL && !events.empty())
-+- *   - busy       (!terminated && current != NULL)
-+- *   - terminated (terminated && current == NULL && events.empty())
-+- *
-+- * Separately, there is a terminateFlag that other threads can set
-+- * asynchronously to tell the Worker to terminate.
-+- */
-+-class Worker : public WorkerParent
-+-{
-+-  private:
-+-    ThreadPool *threadPool;
-+-    WorkerParent *parent;
-+-    JSObject *object;  // Worker object exposed to parent
-+-    JSContext *context;
-+-    JSLock *lock;
-+-    Queue<Event *, SystemAllocPolicy> events;  // owning pointers to pending events
-+-    Event *current;
-+-    bool terminated;
-+-    int32_t terminateFlag;
-+-
-+-    static JSClass jsWorkerClass;
-+-
-+-    Worker()
-+-        : threadPool(NULL), parent(NULL), object(NULL),
-+-          context(NULL), lock(NULL), current(NULL), terminated(false), terminateFlag(0) {}
-+-
-+-    bool init(JSContext *parentcx, WorkerParent *parent, JSObject *obj) {
-+-        JS_ASSERT(!threadPool && !this->parent && !object && !lock);
-+-
-+-        if (!initWorkerParent() || !parent->addChild(this))
-+-            return false;
-+-        threadPool = parent->getThreadPool();
-+-        this->parent = parent;
-+-        this->object = obj;
-+-        lock = JS_NEW_LOCK();
-+-        return lock &&
-+-               createContext(parentcx, parent) &&
-+-               JS_SetPrivate(parentcx, obj, this);
-+-    }
-+-
-+-    bool createContext(JSContext *parentcx, WorkerParent *parent) {
-+-        JSRuntime *rt = JS_GetRuntime(parentcx);
-+-        context = JS_NewContext(rt, 8192);
-+-        if (!context)
-+-            return false;
-+-
-+-        // The Worker has a strong reference to the global; see jsTraceWorker.
-+-        // JSOPTION_UNROOTED_GLOBAL ensures that when the worker becomes
-+-        // unreachable, it and its global object can be collected. Otherwise
-+-        // the cx->globalObject root would keep them both alive forever.
-+-        JS_SetOptions(context, JS_GetOptions(parentcx) | JSOPTION_UNROOTED_GLOBAL |
-+-                                                         JSOPTION_DONT_REPORT_UNCAUGHT);
-+-        JS_SetVersion(context, JS_GetVersion(parentcx));
-+-        JS_SetContextPrivate(context, this);
-+-        JS_SetOperationCallback(context, jsOperationCallback);
-+-        JS_BeginRequest(context);
-+-
-+-        JSObject *global = threadPool->getHooks()->newGlobalObject(context);
-+-        JSObject *post, *proto, *ctor;
-+-        if (!global)
-+-            goto bad;
-+-        JS_SetGlobalObject(context, global);
-+-
-+-        // Because the Worker is completely isolated from the rest of the
-+-        // runtime, and because any pending events on a Worker keep the Worker
-+-        // alive, this postMessage function cannot be called after the Worker
-+-        // is collected.  Therefore it's safe to stash a pointer (a weak
-+-        // reference) to the C++ Worker object in the reserved slot.
-+-        post = JS_GetFunctionObject(JS_DefineFunction(context, global, "postMessage",
-+-                                                      (JSNative) jsPostMessageToParent, 1, 0));
-+-        if (!post || !JS_SetReservedSlot(context, post, 0, PRIVATE_TO_JSVAL(this)))
-+-            goto bad;
-+-
-+-        proto = JS_InitClass(context, global, NULL, &jsWorkerClass, jsConstruct, 1,
-+-                             NULL, jsMethods, NULL, NULL);
-+-        if (!proto)
-+-            goto bad;
-+-
-+-        ctor = JS_GetConstructor(context, proto);
-+-        if (!ctor || !JS_SetReservedSlot(context, ctor, 0, PRIVATE_TO_JSVAL(this)))
-+-            goto bad;
-+-
-+-        JS_EndRequest(context);
-+-        JS_ClearContextThread(context);
-+-        return true;
-+-
-+-    bad:
-+-        JS_EndRequest(context);
-+-        JS_DestroyContext(context);
-+-        context = NULL;
-+-        return false;
-+-    }
-+-
-+-    static void jsTraceWorker(JSTracer *trc, JSObject *obj) {
-+-        JS_ASSERT(JS_GET_CLASS(trc->context, obj) == &jsWorkerClass);
-+-        if (Worker *w = (Worker *) JS_GetPrivate(trc->context, obj)) {
-+-            w->parent->trace(trc);
-+-            w->events.trace(trc);
-+-            if (w->current)
-+-                w->current->trace(trc);
-+-            JS_CALL_OBJECT_TRACER(trc, JS_GetGlobalObject(w->context), "Worker global");
-+-        }
-+-    }
-+-
-+-    static void jsFinalize(JSContext *cx, JSObject *obj) {
-+-        JS_ASSERT(JS_GET_CLASS(cx, obj) == &jsWorkerClass);
-+-        if (Worker *w = (Worker *) JS_GetPrivate(cx, obj))
-+-            delete w;
-+-    }
-+-
-+-    static JSBool jsOperationCallback(JSContext *cx) {
-+-        Worker *w = (Worker *) JS_GetContextPrivate(cx);
-+-        JSAutoSuspendRequest suspend(cx);  // avoid nesting w->lock in a request
-+-        return !w->checkTermination();
-+-    }
-+-
-+-    static JSBool jsResolveGlobal(JSContext *cx, JSObject *obj, jsid id, uintN flags,
-+-                                  JSObject **objp)
-+-    {
-+-        JSBool resolved;
-+-
-+-        if (!JS_ResolveStandardClass(cx, obj, id, &resolved))
-+-            return false;
-+-        if (resolved)
-+-            *objp = obj;
-+-
-+-        return true;
-+-    }
-+-
-+-    static JSBool jsPostMessageToParent(JSContext *cx, uintN argc, jsval *vp);
-+-    static JSBool jsPostMessageToChild(JSContext *cx, uintN argc, jsval *vp);
-+-    static JSBool jsTerminate(JSContext *cx, uintN argc, jsval *vp);
-+-
-+-    bool checkTermination() {
-+-        AutoLock hold(lock);
-+-        return lockedCheckTermination();
-+-    }
-+-
-+-    bool lockedCheckTermination() {
-+-        if (terminateFlag || threadPool->isTerminating()) {
-+-            terminateSelf();
-+-            terminateFlag = 0;
-+-        }
-+-        return terminated;
-+-    }
-+-
-+-    // Caller must hold the lock.
-+-    void terminateSelf() {
-+-        terminated = true;
-+-        while (!events.empty())
-+-            events.pop()->destroy(context);
-+-
-+-        // Tell the children to shut down too. An arbitrarily silly amount of
-+-        // processing could happen before the whole tree is terminated; but
-+-        // this way we don't have to worry about blowing the C stack.
-+-        for (ChildSet::Enum e(children); !e.empty(); e.popFront())
-+-            e.front()->setTerminateFlag();  // note: nesting locks here
-+-    }
-+-
-+-  public:
-+-    ~Worker() {
-+-        if (parent)
-+-            parent->removeChild(this);
-+-        dispose();
-+-    }
-+-
-+-    void dispose() {
-+-        JS_ASSERT(!current);
-+-        while (!events.empty())
-+-            events.pop()->destroy(context);
-+-        if (lock) {
-+-            JS_DESTROY_LOCK(lock);
-+-            lock = NULL;
-+-        }
-+-        if (context) {
-+-            JS_SetContextThread(context);
-+-            JS_DestroyContextNoGC(context);
-+-            context = NULL;
-+-        }
-+-        object = NULL;
-+-
-+-        // Do not call parent->removeChild(). This is called either from
-+-        // ~Worker, which calls it for us; or from parent->disposeChildren or
-+-        // Worker::create, which require that it not be called.
-+-        parent = NULL;
-+-        disposeChildren();
-+-    }
-+-
-+-    static Worker *create(JSContext *parentcx, WorkerParent *parent,
-+-                          JSString *scriptName, JSObject *obj);
-+-
-+-    JSObject *asObject() { return object; }
-+-
-+-    JSObject *getGlobal() { return JS_GetGlobalObject(context); }
-+-
-+-    WorkerParent *getParent() { return parent; }
-+-
-+-    virtual JSLock *getLock() { return lock; }
-+-
-+-    virtual ThreadPool *getThreadPool() { return threadPool; }
-+-
-+-    bool post(Event *event) {
-+-        AutoLock hold(lock);
-+-        if (terminated)
-+-            return false;
-+-        if (!current && events.empty() && !threadPool->getWorkerQueue()->post(this))
-+-            return false;
-+-        return events.push(event);
-+-    }
-+-
-+-    void setTerminateFlag() {
-+-        AutoLock hold(lock);
-+-        terminateFlag = true;
-+-        if (current)
-+-            JS_TriggerOperationCallback(context);
-+-    }
-+-
-+-    void processOneEvent();
-+-
-+-    /* Trace method to be called from C++. */
-+-    void trace(JSTracer *trc) {
-+-        // Just mark the JSObject. If we haven't already been marked,
-+-        // jsTraceWorker will be called, at which point we'll trace referents.
-+-        JS_CALL_OBJECT_TRACER(trc, object, "queued Worker");
-+-    }
-+-
-+-    static bool getWorkerParentFromConstructor(JSContext *cx, JSObject *ctor, WorkerParent **p) {
-+-        jsval v;
-+-        if (!JS_GetReservedSlot(cx, ctor, 0, &v))
-+-            return false;
-+-        if (JSVAL_IS_VOID(v)) {
-+-            // This means ctor is the root Worker constructor (created in
-+-            // Worker::initWorkers as opposed to Worker::createContext, which sets up
-+-            // Worker sandboxes) and nothing is initialized yet.
-+-            if (!JS_GetReservedSlot(cx, ctor, 1, &v))
-+-                return false;
-+-            ThreadPool *threadPool = (ThreadPool *) JSVAL_TO_PRIVATE(v);
-+-            if (!threadPool->start(cx))
-+-                return false;
-+-            WorkerParent *parent = threadPool->getMainQueue();
-+-            if (!JS_SetReservedSlot(cx, ctor, 0, PRIVATE_TO_JSVAL(parent))) {
-+-                threadPool->shutdown(cx);
-+-                return false;
-+-            }
-+-            *p = parent;
-+-            return true;
-+-        }
-+-        *p = (WorkerParent *) JSVAL_TO_PRIVATE(v);
-+-        return true;
-+-    }
-+-
-+-    static JSBool jsConstruct(JSContext *cx, uintN argc, jsval *vp) {
-+-        WorkerParent *parent;
-+-        if (!getWorkerParentFromConstructor(cx, JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)), &parent))
-+-            return false;
-+-
-+-
-+-        JSString *scriptName = JS_ValueToString(cx, argc ? JS_ARGV(cx, vp)[0] : JSVAL_VOID);
-+-        if (!scriptName)
-+-            return false;
-+-
-+-        JSObject *obj = JS_NewObject(cx, &jsWorkerClass, NULL, NULL);
-+-        if (!obj || !create(cx, parent, scriptName, obj))
-+-            return false;
-+-        JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(obj));
-+-        return true;
-+-    }
-+-
-+-    static JSFunctionSpec jsMethods[3];
-+-    static JSFunctionSpec jsStaticMethod[2];
-+-
-+-    static ThreadPool *initWorkers(JSContext *cx, WorkerHooks *hooks, JSObject *global,
-+-                                   JSObject **objp) {
-+-        // Create the ThreadPool object and its JSObject wrapper.
-+-        ThreadPool *threadPool = ThreadPool::create(cx, hooks);
-+-        if (!threadPool)
-+-            return NULL;
-+-
-+-        // Root the ThreadPool JSObject early.
-+-        *objp = threadPool->asObject();
-+-
-+-        // Create the Worker constructor.
-+-        JSObject *proto = JS_InitClass(cx, global, NULL, &jsWorkerClass,
-+-                                       jsConstruct, 1,
-+-                                       NULL, jsMethods, NULL, NULL);
-+-        if (!proto)
-+-            return NULL;
-+-
-+-        // Stash a pointer to the ThreadPool in constructor reserved slot 1.
-+-        // It will be used later when lazily creating the MainQueue.
-+-        JSObject *ctor = JS_GetConstructor(cx, proto);
-+-        if (!JS_SetReservedSlot(cx, ctor, 1, PRIVATE_TO_JSVAL(threadPool)))
-+-            return NULL;
-+-
-+-        return threadPool;
-+-    }
-+-};
-+-
-+-class InitEvent : public Event
-+-{
-+-  public:
-+-    static InitEvent *create(JSContext *cx, Worker *worker, JSString *scriptName) {
-+-        return createEvent<InitEvent>(cx, worker, worker, STRING_TO_JSVAL(scriptName));
-+-    }
-+-
-+-    Result process(JSContext *cx) {
-+-        jsval s;
-+-        if (!deserializeData(cx, &s))
-+-            return fail;
-+-        JS_ASSERT(JSVAL_IS_STRING(s));
-+-        JSAutoByteString filename(cx, JSVAL_TO_STRING(s));
-+-        if (!filename)
-+-            return fail;
-+-
-+-        JSObject *scriptObj = JS_CompileFile(cx, child->getGlobal(), filename.ptr());
-+-        if (!scriptObj)
-+-            return fail;
-+-
-+-        AutoValueRooter rval(cx);
-+-        JSBool ok = JS_ExecuteScript(cx, child->getGlobal(), scriptObj, Jsvalify(rval.addr()));
-+-        return Result(ok);
-+-    }
-+-};
-+-
-+-class DownMessageEvent : public Event
-+-{
-+-  public:
-+-    static DownMessageEvent *create(JSContext *cx, Worker *child, jsval data) {
-+-        return createEvent<DownMessageEvent>(cx, child, child, data);
-+-    }
-+-
-+-    Result process(JSContext *cx) {
-+-        return dispatch(cx, child->getGlobal(), "data", "onmessage", ok);
-+-    }
-+-};
-+-
-+-class UpMessageEvent : public Event
-+-{
-+-  public:
-+-    static UpMessageEvent *create(JSContext *cx, Worker *child, jsval data) {
-+-        return createEvent<UpMessageEvent>(cx, child->getParent(), child, data);
-+-    }
-+-
-+-    Result process(JSContext *cx) {
-+-        return dispatch(cx, child->asObject(), "data", "onmessage", ok);
-+-    }
-+-};
-+-
-+-class ErrorEvent : public Event
-+-{
-+-  public:
-+-    static ErrorEvent *create(JSContext *cx, Worker *child) {
-+-        JSString *data = NULL;
-+-        jsval exc;
-+-        if (JS_GetPendingException(cx, &exc)) {
-+-            AutoValueRooter tvr(cx, Valueify(exc));
-+-            JS_ClearPendingException(cx);
-+-
-+-            // Determine what error message to put in the error event.
-+-            // If exc.message is a string, use that; otherwise use String(exc).
-+-            // (This is a little different from what web workers do.)
-+-            if (JSVAL_IS_OBJECT(exc)) {
-+-                jsval msg;
-+-                if (!JS_GetProperty(cx, JSVAL_TO_OBJECT(exc), "message", &msg))

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201812262036.wBQKawYj055784>