svn commit: r488434 - in head/games/oolite: . files
Steve Wills
swills at FreeBSD.org
Wed Dec 26 20:36:59 UTC 2018
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 at 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 at 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 ***
More information about the svn-ports-head
mailing list