blob: 1b40ae6ed6721d5b2c67e118e7c154eec1b62c72 [file] [log] [blame]
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef vm_ThreadPool_h
#define vm_ThreadPool_h
#include <stddef.h>
#include "mozilla/StandardInteger.h"
#include "js/Vector.h"
#include "jsalloc.h"
#ifdef JS_THREADSAFE
#if defined(STARBOARD)
#include "pr_starboard.h"
#else // defined(STARBOARD)
# include "prtypes.h"
# include "prlock.h"
# include "prcvar.h"
#endif // defined(STARBOARD)
#endif
struct JSContext;
struct JSRuntime;
struct JSCompartment;
class JSScript;
namespace js {
class ThreadPoolWorker;
typedef void (*TaskFun)(void *userdata, uint32_t workerId, uintptr_t stackLimit);
class TaskExecutor
{
public:
virtual void executeFromWorker(uint32_t workerId, uintptr_t stackLimit) = 0;
};
// ThreadPool used for parallel JavaScript execution as well as
// parallel compilation. Unless you are building a new kind of
// parallel service, it is very likely that you do not wish to
// interact with the threadpool directly. In particular, if you wish
// to execute JavaScript in parallel, you probably want to look at
// |js::ForkJoin| in |forkjoin.cpp|.
//
// The ThreadPool always maintains a fixed pool of worker threads.
// You can query the number of worker threads via the method
// |numWorkers()|. Note that this number may be zero (generally if
// threads are disabled, or when manually specified for benchmarking
// purposes).
//
// You can either submit jobs in one of two ways. The first is
// |submitOne()|, which submits a job to be executed by one worker
// thread (this will fail if there are no worker threads). The job
// will be enqueued and executed by some worker (the current scheduler
// uses round-robin load balancing; something more sophisticated,
// e.g. a central queue or work stealing, might be better).
//
// The second way to submit a job is using |submitAll()|---in this
// case, the job will be executed by all worker threads. This does
// not fail if there are no worker threads, it simply does nothing.
// Of course, each thread may have any number of previously submitted
// things that they are already working on, and so they will finish
// those before they get to this job. Therefore it is possible to
// have some worker threads pick up (and even finish) their piece of
// the job before others have even started.
class ThreadPool
{
private:
friend class ThreadPoolWorker;
// Initialized at startup only:
JSRuntime *const runtime_;
js::Vector<ThreadPoolWorker*, 8, SystemAllocPolicy> workers_;
// Number of workers we will start, when we actually start them
size_t numWorkers_;
// Next worker for |submitOne()|. Atomically modified.
uint32_t nextId_;
bool lazyStartWorkers(JSContext *cx);
void terminateWorkers();
void terminateWorkersAndReportOOM(JSContext *cx);
public:
ThreadPool(JSRuntime *rt);
~ThreadPool();
bool init();
// Return number of worker threads in the pool.
size_t numWorkers() { return numWorkers_; }
// See comment on class:
bool submitOne(JSContext *cx, TaskExecutor *executor);
bool submitAll(JSContext *cx, TaskExecutor *executor);
// Wait until all worker threads have finished their current set
// of jobs and then return. You must not submit new jobs after
// invoking |terminate()|.
bool terminate();
};
} // namespace js
#endif /* vm_ThreadPool_h */