付智勇

no message

正在显示 55 个修改的文件 包含 4280 行增加3 行删除

要显示太多修改。

为保证性能只显示 55 of 55+ 个文件。

@@ -28,9 +28,9 @@ var tokenUtil = require('./util/tokenUtil'); @@ -28,9 +28,9 @@ var tokenUtil = require('./util/tokenUtil');
28 const _ = require('lodash'); 28 const _ = require('lodash');
29 var status = require('./util/resTemplate') 29 var status = require('./util/resTemplate')
30 30
  31 +
31 // error handler 32 // error handler
32 onerror(app) 33 onerror(app)
33 -  
34 app.use(koaBody({ multipart: true })); 34 app.use(koaBody({ multipart: true }));
35 35
36 // middlewares 36 // middlewares
@@ -50,7 +50,10 @@ app.use(views(__dirname + '/views', { @@ -50,7 +50,10 @@ app.use(views(__dirname + '/views', {
50 app.use(async (ctx, next) => { 50 app.use(async (ctx, next) => {
51 try{ 51 try{
52 const start = new Date(); 52 const start = new Date();
53 - if(filterUrl.indexOf(ctx.request.url) != -1){ 53 + const url = ctx.request.url.split('?');
  54 + console.log(url);
  55 + if(filterUrl.indexOf(url[0]) != -1){
  56 +
54 await next(); 57 await next();
55 }else if(!ctx.header.token){ 58 }else if(!ctx.header.token){
56 status.catchError(ctx,400,'请登录'); 59 status.catchError(ctx,400,'请登录');
1 -All packages installed at Tue Aug 22 2017 18:52:38 GMT+0800 (CST)  
  1 +All packages installed at Wed Sep 06 2017 18:02:21 GMT+0800 (CST)
  1 +# download-file
  2 +
  3 +## Install
  4 +
  5 +```shell
  6 +npm install download-file --save
  7 +```
  8 +
  9 +## Usage
  10 +
  11 +```js
  12 +var download = require('download-file')
  13 +
  14 +var url = "http://i.imgur.com/G9bDaPH.jpg"
  15 +
  16 +var options = {
  17 + directory: "./images/cats/",
  18 + filename: "cat.gif"
  19 +}
  20 +
  21 +download(url, options, function(err){
  22 + if (err) throw err
  23 + console.log("meow")
  24 +})
  25 +```
  26 +
  27 +## API
  28 +
  29 +### download(url, [options], callback(err))
  30 +
  31 +- __url__ string of the file URL to download
  32 +
  33 +- __options__ object with options
  34 +
  35 + - __directory__ string with path to directory where to save files (default: current working directory)
  36 + - __filename__ string for the name of the file to be saved as (default: filename in the url)
  37 + - __timeout__ integer of how long in ms to wait while downloading (default: 20000)
  38 +
  39 +- __callback__ function to run after
  1 +var fs = require('fs')
  2 +var url = require('url')
  3 +var http = require('http')
  4 +var https = require('https')
  5 +var mkdirp = require('mkdirp')
  6 +
  7 +module.exports = function download(file, options, callback) {
  8 + if (!file) throw("Need a file url to download")
  9 +
  10 + if (!callback && typeof options === 'function') {
  11 + callback = options
  12 + }
  13 +
  14 + options = typeof options === 'object' ? options : {}
  15 + options.timeout = options.timeout || 20000
  16 + options.directory = options.directory ? options.directory : '.'
  17 +
  18 + var uri = file.split('/')
  19 + options.filename = options.filename || uri[uri.length - 1]
  20 +
  21 + var path = options.directory + "/" + options.filename
  22 +
  23 + if (url.parse(file).protocol === null) {
  24 + file = 'http://' + file
  25 + req = http
  26 + } else if (url.parse(file).protocol === 'https:') {
  27 + req = https
  28 + } else {
  29 + req = http
  30 + }
  31 +
  32 + var request = req.get(file, function(response) {
  33 +
  34 + if (response.statusCode === 200) {
  35 +
  36 + mkdirp(options.directory, function(err) {
  37 + if (err) throw err
  38 + var file = fs.createWriteStream(path)
  39 + response.pipe(file)
  40 + })
  41 +
  42 + } else {
  43 +
  44 + if (callback) callback(response.statusCode)
  45 +
  46 + }
  47 +
  48 + response.on("end", function(){
  49 + if (callback) callback(false, path)
  50 + })
  51 +
  52 + request.setTimeout(options.timeout, function () {
  53 + request.abort()
  54 + callback("Timeout")
  55 + })
  56 +
  57 + }).on('error', function(e) {
  58 +
  59 + if (callback) callback(e)
  60 +
  61 + })
  62 +
  63 +}
  1 +{
  2 + "name": "download-file",
  3 + "version": "0.1.5",
  4 + "description": "Generic file download utility",
  5 + "main": "index.js",
  6 + "scripts": {
  7 + "test": "node test.js"
  8 + },
  9 + "author": "Montana Flynn",
  10 + "license": "ISC",
  11 + "dependencies": {
  12 + "mkdirp": "^0.5.0"
  13 + },
  14 + "devDependencies": {},
  15 + "keywords": [
  16 + "download",
  17 + "file",
  18 + "url",
  19 + "get",
  20 + "http",
  21 + "https"
  22 + ],
  23 + "_from": "download-file@0.1.5",
  24 + "_resolved": "http://registry.npm.taobao.org/download-file/download/download-file-0.1.5.tgz"
  25 +}
  1 +var dl = require('./index.js')
  2 +
  3 +var url = "i.imgur.com/G9bDaPH.jpg"
  4 +
  5 +var opts = {
  6 + directory: "./images/cats/",
  7 + filename: "cat.gif"
  8 +}
  9 +
  10 +dl(url, opts, function(err){
  11 + if (err) hiss(err)
  12 + meow("no protocol")
  13 +})
  14 +
  15 +var url = "http://i.imgur.com/G9bDaPH.jpg"
  16 +
  17 +var opts = {
  18 + directory: "./images/cats/",
  19 + filename: "cat.gif"
  20 +}
  21 +
  22 +dl(url, opts, function(err){
  23 + if (err) hiss(err)
  24 + meow("http protocol")
  25 +})
  26 +
  27 +var url = "http://i.imgur.com/G9bDaPH.jpg"
  28 +
  29 +var opts = {
  30 + directory: "./images/cats/",
  31 + filename: "cat.gif"
  32 +}
  33 +
  34 +dl(url, opts, function(err){
  35 + if (err) hiss(err)
  36 + meow("https protocol")
  37 +})
  38 +
  39 +function meow(msg) {
  40 + console.log("\033[32m", "meow: " + msg, "\033[91m")
  41 +}
  42 +
  43 +function hiss(err) {
  44 + console.log("\033[31m", "hiss", "\033[91m")
  45 + throw err
  46 +}
  1 +Wed Sep 06 2017 17:57:15 GMT+0800 (CST)
  1 +sudo: false
  2 +
  3 +language: node_js
  4 +
  5 +node_js:
  6 + - "4"
  7 + - "6"
  8 +
  9 +cache:
  10 + directories:
  11 + - node_modules
  12 +
  13 +install:
  14 + - npm install
  15 +
  16 +script:
  17 + - npm run test
  18 +
  19 +# Necessary to compile native modules for io.js v3 or Node.js v4
  20 +env:
  21 + - CXX=g++-4.8
  22 +
  23 +# Necessary to compile native modules for io.js v3 or Node.js v4
  24 +addons:
  25 + apt:
  26 + sources:
  27 + - ubuntu-toolchain-r-test
  28 + packages:
  29 + - g++-4.8
  30 +
  31 +notifications:
  32 + email: false
  1 +Copyright 2011 Marcel Laverdet
  2 +Permission is hereby granted, free of charge, to any person obtaining a copy
  3 +of this software and associated documentation files (the "Software"), to
  4 +deal in the Software without restriction, including without limitation the
  5 +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  6 +sell copies of the Software, and to permit persons to whom the Software is
  7 +furnished to do so, subject to the following conditions:
  8 +
  9 +The above copyright notice and this permission notice shall be included in
  10 +all copies or substantial portions of the Software.
  11 +
  12 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  13 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  14 +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  15 +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  16 +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  17 +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  18 +IN THE SOFTWARE.
  1 +fibers(1) -- Fiber support for v8 and Node
  2 +==========================================
  3 +
  4 +INSTALLING
  5 +----------
  6 +
  7 +### via npm
  8 +* `npm install fibers`
  9 +* You're done! (see "supported platforms" below if you run into errors)
  10 +
  11 +### from source
  12 +* `git clone git://github.com/laverdet/node-fibers.git`
  13 +* `cd node-fibers`
  14 +* `npm install`
  15 +
  16 +Note: node-fibers uses [node-gyp](https://github.com/TooTallNate/node-gyp) for
  17 +building. To manually invoke the build process, you can use `node-gyp rebuild`.
  18 +This will put the compiled extension in `build/Release/fibers.node`. However,
  19 +when you do `require('fibers')`, it will expect the module to be in, for
  20 +example, `bin/linux-x64-v8-3.11/fibers.node`. You can manually put the module
  21 +here every time you build, or you can use the included build script. Either
  22 +`npm install` or `node build -f` will do this for you. If you are going to be
  23 +hacking on node-fibers, it may be worthwhile to first do `node-gyp configure`
  24 +and then for subsequent rebuilds you can just do `node-gyp build` which will
  25 +be faster than a full `npm install` or `node-gyp rebuild`.
  26 +
  27 +### meteor users please read this
  28 +If you're trying to get meteor running and you ended up at this page you're
  29 +probably doing something wrong. Please uninstall all versions of NodeJS and
  30 +Meteor, then start over. See
  31 +[meteor#5124](https://github.com/meteor/meteor/issues/5124) for more
  32 +information.
  33 +
  34 +### supported platforms
  35 +If you are running NodeJS version 4.x, 5.x, or 6.x on Linux, OS X, or Windows
  36 +(7 or later) then you should be able to install fibers from npm just fine. If
  37 +you are running an older (or newer) version of node or some other operating
  38 +system you will have to compile fibers on your system.
  39 +
  40 +(special thanks to [Jeroen Janssen](https://github.com/japj) for his work on
  41 +fibers in Windows)
  42 +
  43 +If you do end up needing to compile fibers first make sure you have node-gyp
  44 +installed as a global dependency (`npm install -g node-gyp`), and that you have
  45 +setup your build enviroment by following the instructions at
  46 +[node-gyp](https://github.com/TooTallNate/node-gyp). Ubuntu-flavored Linux users
  47 +may need to run `sudo apt-get install g++` as well.
  48 +
  49 +
  50 +EXAMPLES
  51 +--------
  52 +
  53 +The examples below describe basic use of `Fiber`, but note that it is **not
  54 +recommended** to use `Fiber` without an abstraction in between your code and
  55 +fibers. See "FUTURES" below for additional information.
  56 +
  57 +### Sleep
  58 +This is a quick example of how you can write sleep() with fibers. Note that
  59 +while the sleep() call is blocking inside the fiber, node is able to handle
  60 +other events.
  61 +
  62 + $ cat sleep.js
  63 +
  64 +```javascript
  65 +var Fiber = require('fibers');
  66 +
  67 +function sleep(ms) {
  68 + var fiber = Fiber.current;
  69 + setTimeout(function() {
  70 + fiber.run();
  71 + }, ms);
  72 + Fiber.yield();
  73 +}
  74 +
  75 +Fiber(function() {
  76 + console.log('wait... ' + new Date);
  77 + sleep(1000);
  78 + console.log('ok... ' + new Date);
  79 +}).run();
  80 +console.log('back in main');
  81 +```
  82 +
  83 + $ node sleep.js
  84 + wait... Fri Jan 21 2011 22:42:04 GMT+0900 (JST)
  85 + back in main
  86 + ok... Fri Jan 21 2011 22:42:05 GMT+0900 (JST)
  87 +
  88 +
  89 +### Incremental Generator
  90 +Yielding execution will resume back in the fiber right where you left off. You
  91 +can also pass values back and forth through yield() and run(). Again, the node
  92 +event loop is never blocked while this script is running.
  93 +
  94 + $ cat generator.js
  95 +
  96 +```javascript
  97 +var Fiber = require('fibers');
  98 +
  99 +var inc = Fiber(function(start) {
  100 + var total = start;
  101 + while (true) {
  102 + total += Fiber.yield(total);
  103 + }
  104 +});
  105 +
  106 +for (var ii = inc.run(1); ii <= 10; ii = inc.run(1)) {
  107 + console.log(ii);
  108 +}
  109 +```
  110 +
  111 + $ node generator.js
  112 + 1
  113 + 2
  114 + 3
  115 + 4
  116 + 5
  117 + 6
  118 + 7
  119 + 8
  120 + 9
  121 + 10
  122 +
  123 +
  124 +### Fibonacci Generator
  125 +Expanding on the incremental generator above, we can create a generator which
  126 +returns a new Fibonacci number with each invocation. You can compare this with
  127 +the [ECMAScript Harmony
  128 +Generator](http://wiki.ecmascript.org/doku.php?id=harmony:generators) Fibonacci
  129 +example.
  130 +
  131 + $ cat fibonacci.js
  132 +
  133 +```javascript
  134 +var Fiber = require('fibers');
  135 +
  136 +// Generator function. Returns a function which returns incrementing
  137 +// Fibonacci numbers with each call.
  138 +function Fibonacci() {
  139 + // Create a new fiber which yields sequential Fibonacci numbers
  140 + var fiber = Fiber(function() {
  141 + Fiber.yield(0); // F(0) -> 0
  142 + var prev = 0, curr = 1;
  143 + while (true) {
  144 + Fiber.yield(curr);
  145 + var tmp = prev + curr;
  146 + prev = curr;
  147 + curr = tmp;
  148 + }
  149 + });
  150 + // Return a bound handle to `run` on this fiber
  151 + return fiber.run.bind(fiber);
  152 +}
  153 +
  154 +// Initialize a new Fibonacci sequence and iterate up to 1597
  155 +var seq = Fibonacci();
  156 +for (var ii = seq(); ii <= 1597; ii = seq()) {
  157 + console.log(ii);
  158 +}
  159 +```
  160 +
  161 + $ node fibonacci.js
  162 + 0
  163 + 1
  164 + 1
  165 + 2
  166 + 3
  167 + 5
  168 + 8
  169 + 13
  170 + 21
  171 + 34
  172 + 55
  173 + 89
  174 + 144
  175 + 233
  176 + 377
  177 + 610
  178 + 987
  179 + 1597
  180 +
  181 +
  182 +### Basic Exceptions
  183 +Fibers are exception-safe; exceptions will continue travelling through fiber
  184 +boundaries:
  185 +
  186 + $ cat error.js
  187 +
  188 +```javascript
  189 +var Fiber = require('fibers');
  190 +
  191 +var fn = Fiber(function() {
  192 + console.log('async work here...');
  193 + Fiber.yield();
  194 + console.log('still working...');
  195 + Fiber.yield();
  196 + console.log('just a little bit more...');
  197 + Fiber.yield();
  198 + throw new Error('oh crap!');
  199 +});
  200 +
  201 +try {
  202 + while (true) {
  203 + fn.run();
  204 + }
  205 +} catch(e) {
  206 + console.log('safely caught that error!');
  207 + console.log(e.stack);
  208 +}
  209 +console.log('done!');
  210 +```
  211 +
  212 + $ node error.js
  213 + async work here...
  214 + still working...
  215 + just a little bit more...
  216 + safely caught that error!
  217 + Error: oh crap!
  218 + at error.js:11:9
  219 + done!
  220 +
  221 +
  222 +FUTURES
  223 +-------
  224 +
  225 +Using the `Fiber` class without an abstraction in between your code and the raw
  226 +API is **not recommended**. `Fiber` is meant to implement the smallest amount of
  227 +functionality in order make possible many different programming patterns. This
  228 +makes the `Fiber` class relatively lousy to work with directly, but extremely
  229 +powerful when coupled with a decent abstraction. There is no right answer for
  230 +which abstraction is right for you and your project. Included with `node-fibers`
  231 +is an implementation of "futures" which is fiber-aware. Usage of this library
  232 +is documented below. There are several other externally-maintained options
  233 +which can be found on the [wiki](https://github.com/laverdet/node-fibers/wiki).
  234 +You **should** feel encouraged to be creative with fibers and build a solution
  235 +which works well with your project. For instance, `Future` is not a good
  236 +abstraction to use if you want to build a generator function (see Fibonacci
  237 +example above).
  238 +
  239 +Using `Future` to wrap existing node functions. At no point is the node event
  240 +loop blocked:
  241 +
  242 + $ cat ls.js
  243 +
  244 +```javascript
  245 +var Future = require('fibers/future');
  246 +var fs = Future.wrap(require('fs'));
  247 +
  248 +Future.task(function() {
  249 + // Get a list of files in the directory
  250 + var fileNames = fs.readdirFuture('.').wait();
  251 + console.log('Found '+ fileNames.length+ ' files');
  252 +
  253 + // Stat each file
  254 + var stats = [];
  255 + for (var ii = 0; ii < fileNames.length; ++ii) {
  256 + stats.push(fs.statFuture(fileNames[ii]));
  257 + }
  258 + stats.map(function(f) {
  259 + f.wait()
  260 + });
  261 +
  262 + // Print file size
  263 + for (var ii = 0; ii < fileNames.length; ++ii) {
  264 + console.log(fileNames[ii]+ ': '+ stats[ii].get().size);
  265 + }
  266 +}).detach();
  267 +```
  268 +
  269 + $ node ls.js
  270 + Found 11 files
  271 + bin: 4096
  272 + fibers.js: 1708
  273 + .gitignore: 37
  274 + README.md: 8664
  275 + future.js: 5833
  276 + .git: 4096
  277 + LICENSE: 1054
  278 + src: 4096
  279 + ls.js: 860
  280 + Makefile: 436
  281 + package.json: 684
  282 +
  283 +
  284 +The future API is designed to make it easy to move between classic
  285 +callback-style code and fiber-aware waiting code:
  286 +
  287 + $ cat sleep.js
  288 +
  289 +```javascript
  290 +var Future = require('fibers/future'), wait = Future.wait;
  291 +
  292 +// This function returns a future which resolves after a timeout. This
  293 +// demonstrates manually resolving futures.
  294 +function sleep(ms) {
  295 + var future = new Future;
  296 + setTimeout(function() {
  297 + future.return();
  298 + }, ms);
  299 + return future;
  300 +}
  301 +
  302 +// You can create functions which automatically run in their own fiber and
  303 +// return futures that resolve when the fiber returns (this probably sounds
  304 +// confusing.. just play with it to understand).
  305 +var calcTimerDelta = function(ms) {
  306 + var start = new Date;
  307 + sleep(ms).wait();
  308 + return new Date - start;
  309 +}.future(); // <-- important!
  310 +
  311 +// And futures also include node-friendly callbacks if you don't want to use
  312 +// wait()
  313 +calcTimerDelta(2000).resolve(function(err, val) {
  314 + console.log('Set timer for 2000ms, waited '+ val+ 'ms');
  315 +});
  316 +```
  317 +
  318 + $ node sleep.js
  319 + Set timer for 2000ms, waited 2009ms
  320 +
  321 +
  322 +API DOCUMENTATION
  323 +-----------------
  324 +Fiber's definition looks something like this:
  325 +
  326 +```javascript
  327 +/**
  328 + * Instantiate a new Fiber. You may invoke this either as a function or as
  329 + * a constructor; the behavior is the same.
  330 + *
  331 + * When run() is called on this fiber for the first time, `fn` will be
  332 + * invoked as the first frame on a new stack. Execution will continue on
  333 + * this new stack until `fn` returns, or Fiber.yield() is called.
  334 + *
  335 + * After the function returns the fiber is reset to original state and
  336 + * may be restarted with another call to run().
  337 + */
  338 +function Fiber(fn) {
  339 + [native code]
  340 +}
  341 +
  342 +/**
  343 + * `Fiber.current` will contain the currently-running Fiber. It will be
  344 + * `undefined` if there is no fiber (i.e. the main stack of execution).
  345 + *
  346 + * See "Garbage Collection" for more information on responsible use of
  347 + * `Fiber.current`.
  348 + */
  349 +Fiber.current = undefined;
  350 +
  351 +/**
  352 + * `Fiber.yield()` will halt execution of the current fiber and return control
  353 + * back to original caller of run(). If an argument is supplied to yield(),
  354 + * run() will return that value.
  355 + *
  356 + * When run() is called again, yield() will return.
  357 + *
  358 + * Note that this function is a global to allow for correct garbage
  359 + * collection. This results in no loss of functionality because it is only
  360 + * valid to yield from the currently running fiber anyway.
  361 + *
  362 + * Note also that `yield` is a reserved word in Javascript. This is normally
  363 + * not an issue, however some code linters may complain. Rest assured that it
  364 + * will run fine now and in future versions of Javascript.
  365 + */
  366 +Fiber.yield = function(param) {
  367 + [native code]
  368 +}
  369 +
  370 +/**
  371 + * run() will start execution of this Fiber, or if it is currently yielding,
  372 + * it will resume execution. If an argument is supplied, this argument will
  373 + * be passed to the fiber, either as the first parameter to the main
  374 + * function [if the fiber has not been started] or as the return value of
  375 + * yield() [if the fiber is currently yielding].
  376 + *
  377 + * This function will return either the parameter passed to yield(), or the
  378 + * returned value from the fiber's main function.
  379 + */
  380 +Fiber.prototype.run = function(param) {
  381 + [native code]
  382 +}
  383 +
  384 +/**
  385 + * reset() will terminate a running Fiber and restore it to its original
  386 + * state, as if it had returned execution.
  387 + *
  388 + * This is accomplished by causing yield() to throw an exception, and any
  389 + * futher calls to yield() will also throw an exception. This continues
  390 + * until the fiber has completely unwound and returns.
  391 + *
  392 + * If the fiber returns a value it will be returned by reset().
  393 + *
  394 + * If the fiber is not running, reset() will have no effect.
  395 + */
  396 +Fiber.prototype.reset = function() {
  397 + [native code]
  398 +}
  399 +
  400 +/**
  401 + * throwInto() will cause a currently yielding fiber's yield() call to
  402 + * throw instead of return gracefully. This can be useful for notifying a
  403 + * fiber that you are no longer interested in its task, and that it should
  404 + * give up.
  405 + *
  406 + * Note that if the fiber does not handle the exception it will continue to
  407 + * bubble up and throwInto() will throw the exception right back at you.
  408 + */
  409 +Fiber.prototype.throwInto = function(exception) {
  410 + [native code]
  411 +}
  412 +```
  413 +
  414 +
  415 +Future's definition looks something like this:
  416 +
  417 +```javascript
  418 +/**
  419 + * Returns a future-function which, when run, starts running the target
  420 + * function and returns a future for the result.
  421 + *
  422 + * Example usage:
  423 + * var funcy = function(arg) {
  424 + * return arg+1;
  425 + * }.future();
  426 + *
  427 + * funcy(1).wait(); // returns 2
  428 + */
  429 +Function.prototype.future = function() { ... }
  430 +
  431 +/**
  432 + * Future object, instantiated with the new operator.
  433 + */
  434 +function Future() {}
  435 +
  436 +/**
  437 + * Wrap a node-style async function to return a future in place of using a callback.
  438 + *
  439 + * fn - the function or object to wrap
  440 + * array - indicates that this callback will return more than 1 argument after `err`. For example,
  441 + * `child_process.exec()` returns [err, stdout, stderr]
  442 + * suffix - appends a string to every method that was overridden, if you passed an object
  443 + *
  444 + * Example usage: Future.wrap(asyncFunction)(arg1).wait()
  445 + */
  446 +Future.wrap = function(fn, multi, suffix) { ... }
  447 +
  448 +/**
  449 + * Invoke a function that will be run in its own fiber context and return a future to its return
  450 + * value.
  451 + *
  452 + * Example:
  453 + * Future.task(function() {
  454 + * // You can safely `wait` on stuff here
  455 + * }).detach();
  456 + */
  457 +Future.task = function(fn) { ... }
  458 +
  459 +/**
  460 + * Wait on a series of futures and then return. If the futures throw an exception this function
  461 + * /won't/ throw it back. You can get the value of the future by calling get() on it directly. If
  462 + * you want to wait on a single future you're better off calling future.wait() on the instance.
  463 + *
  464 + * Example usage: Future.wait(aFuture, anotherFuture)
  465 + */
  466 +Future.wait = function(/* ... */) { ... }
  467 +
  468 +/**
  469 + * Return the value of this future. If the future hasn't resolved yet this will throw an error.
  470 + */
  471 +Future.prototype.get = function() { ... }
  472 +
  473 +/**
  474 + * Mark this future as returned. All pending callbacks will be invoked immediately.
  475 + *
  476 + * value - the value to return when get() or wait() is called.
  477 + *
  478 + * Example usage: aFuture.return(value)
  479 + */
  480 +Future.prototype.return = function(value) { ... }
  481 +
  482 +/**
  483 + * Throw from this future as returned. All pending callbacks will be invoked immediately.
  484 + * Note that execution will continue normally after running this method,
  485 + * so make sure you exit appropriately after running throw()
  486 + *
  487 + * error - the error to throw when get() or wait() is called.
  488 + *
  489 + * Example usage: aFuture.throw(new Error("Something borked"))
  490 + */
  491 +Future.prototype.throw = function(error) { ... }
  492 +
  493 +/**
  494 + * "detach" this future. Basically this is useful if you want to run a task in a future, you
  495 + * aren't interested in its return value, but if it throws you don't want the exception to be
  496 + * lost. If this fiber throws, an exception will be thrown to the event loop and node will
  497 + * probably fall down.
  498 + */
  499 +Future.prototype.detach = function() { ... }
  500 +
  501 +/**
  502 + * Returns whether or not this future has resolved yet.
  503 + */
  504 +Future.prototype.isResolved = function() { ... }
  505 +
  506 +/**
  507 + * Returns a node-style function which will mark this future as resolved when called.
  508 + *
  509 + * Example usage:
  510 + * var errback = aFuture.resolver();
  511 + * asyncFunction(arg1, arg2, etc, errback)
  512 + * var result = aFuture.wait();
  513 + */
  514 +Future.prototype.resolver = function() { ... }
  515 +
  516 +/**
  517 + * Waits for this future to resolve and then invokes a callback.
  518 + *
  519 + * If only one argument is passed it is a standard function(err, val){} errback.
  520 + *
  521 + * If two arguments are passed, the first argument is a future which will be thrown to in the case
  522 + * of error, and the second is a function(val){} callback.
  523 + */
  524 +Future.prototype.resolve = function(/* errback or future, callback */) { ... }
  525 +
  526 +/**
  527 + * Propogate results to another future.
  528 + *
  529 + * Example usage: future1.proxy(future2) // future2 gets automatically resolved with however future1 resolves
  530 + */
  531 +Future.prototype.proxy = function(future) { ... }
  532 +
  533 +/**
  534 + * Differs from its functional counterpart in that it actually resolves the future. Thus if the
  535 + * future threw, future.wait() will throw.
  536 + */
  537 +Future.prototype.wait = function() { ... }
  538 +
  539 +/**
  540 + * Support for converting a Future to and from ES6 Promises.
  541 + */
  542 +Future.fromPromise = function(promise) { ... }
  543 +Future.prototype.promise = function() { ... }
  544 +```
  545 +
  546 +GARBAGE COLLECTION
  547 +------------------
  548 +
  549 +If you intend to build generators, iterators, or "lazy lists", you should be
  550 +aware that all fibers must eventually unwind. This is implemented by causing
  551 +yield() to throw unconditionally when the library is trying to unwind your
  552 +fiber-- either because reset() was called, or all handles to the fiber were lost
  553 +and v8 wants to delete it.
  554 +
  555 +Something like this will, at some point, cause an infinite loop in your
  556 +application:
  557 +
  558 +```javascript
  559 +var fiber = Fiber(function() {
  560 + while (true) {
  561 + try {
  562 + Fiber.yield();
  563 + } catch(e) {}
  564 + }
  565 +});
  566 +fiber.run();
  567 +```
  568 +
  569 +If you either call reset() on this fiber, or the v8 garbage collector decides it
  570 +is no longer in use, the fiber library will attempt to unwind the fiber by
  571 +causing all calls to yield() to throw. However, if you catch these exceptions
  572 +and continue anyway, an infinite loop will occur.
  573 +
  574 +There are other garbage collection issues that occur with misuse of fiber
  575 +handles. If you grab a handle to a fiber from within itself, you should make
  576 +sure that the fiber eventually unwinds. This application will leak memory:
  577 +
  578 +```javascript
  579 +var fiber = Fiber(function() {
  580 + var that = Fiber.current;
  581 + Fiber.yield();
  582 +}
  583 +fiber.run();
  584 +fiber = undefined;
  585 +```
  586 +
  587 +There is no way to get back into the fiber that was started, however it's
  588 +impossible for v8's garbage collector to detect this. With a handle to the fiber
  589 +still outstanding, v8 will never garbage collect it and the stack will remain in
  590 +memory until the application exits.
  591 +
  592 +Thus, you should take care when grabbing references to `Fiber.current`.
  1 +#!/usr/bin/env node
  2 +"use strict";
  3 +var fs = require('fs');
  4 +global.Fiber = require('../fibers');
  5 +global.Future = require('../future');
  6 +
  7 +// Start the repl
  8 +var vm = require('vm');
  9 +var domain = require('domain');
  10 +var repl = require('repl').start('node> ', null, fiberEval, true, true);
  11 +function fiberEval(code, context, file, cb) {
  12 + if (/^\([ \r\n\t+]\)$/.test(code)) {
  13 + return cb(false, undefined);
  14 + }
  15 + // Parses?
  16 + try {
  17 + new Function(code);
  18 + } catch (err) {
  19 + return cb(err, false);
  20 + }
  21 +
  22 + // Run in fiber
  23 + Future.task(function() {
  24 + // Save history
  25 + var last;
  26 + repl.rli.history = repl.rli.history.slice(0, 50).filter(function(item) {
  27 + try {
  28 + return item !== last;
  29 + } finally {
  30 + last = item;
  31 + }
  32 + });
  33 + fs.writeFile(process.env.HOME+ '/.node-history', JSON.stringify(repl.rli.history), function(){});
  34 +
  35 + // Run user code
  36 + var d = domain.create();
  37 + d.run(function() {
  38 + cb(null, vm.runInThisContext(code, file));
  39 + });
  40 + d.on('error', function(err) {
  41 + console.error('\nUnhandled error: '+ err.stack);
  42 + });
  43 + }).resolve(cb);
  44 +}
  45 +
  46 +// Load history
  47 +try {
  48 + repl.rli.history = JSON.parse(fs.readFileSync(process.env.HOME+ '/.node-history', 'utf-8'));
  49 +} catch (err) {}
  1 +{
  2 + 'target_defaults': {
  3 + 'default_configuration': 'Release',
  4 + 'configurations': {
  5 + 'Release': {
  6 + 'cflags': [ '-O3' ],
  7 + 'xcode_settings': {
  8 + 'GCC_OPTIMIZATION_LEVEL': '3',
  9 + 'GCC_GENERATE_DEBUGGING_SYMBOLS': 'NO',
  10 + },
  11 + 'msvs_settings': {
  12 + 'VCCLCompilerTool': {
  13 + 'Optimization': 3,
  14 + 'FavorSizeOrSpeed': 1,
  15 + },
  16 + },
  17 + }
  18 + },
  19 + },
  20 + 'targets': [
  21 + {
  22 + 'target_name': 'fibers',
  23 + 'sources': [
  24 + 'src/fibers.cc',
  25 + 'src/coroutine.cc',
  26 + 'src/libcoro/coro.c',
  27 + # Rebuild on header changes
  28 + 'src/coroutine.h',
  29 + 'src/libcoro/coro.h',
  30 + ],
  31 + 'cflags!': ['-ansi'],
  32 + 'conditions': [
  33 + ['OS == "win"',
  34 + {'defines': ['CORO_FIBER', 'WINDOWS']},
  35 + # else
  36 + {
  37 + 'defines': ['USE_CORO', 'CORO_GUARDPAGES=1'],
  38 + 'ldflags': ['-pthread'],
  39 + }
  40 + ],
  41 + ['OS == "linux"',
  42 + {
  43 + 'variables': {
  44 + 'USE_MUSL': '<!(ldd --version 2>&1 | head -n1 | grep "musl" | wc -l)',
  45 + },
  46 + 'conditions': [
  47 + ['<(USE_MUSL) == 1',
  48 + {'defines': ['CORO_ASM', 'USE_V8_SYMBOLS']},
  49 + {'defines': ['CORO_UCONTEXT']}
  50 + ],
  51 + ],
  52 + },
  53 + ],
  54 + ['OS == "solaris" or OS == "sunos" or OS == "freebsd" or OS == "aix"', {'defines': ['CORO_UCONTEXT']}],
  55 + ['OS == "mac"', {'defines': ['CORO_SJLJ']}],
  56 + ['OS == "openbsd"', {'defines': ['CORO_ASM']}],
  57 + ['target_arch == "arm" or target_arch == "arm64"',
  58 + {
  59 + # There's been problems getting real fibers working on arm
  60 + 'defines': ['CORO_PTHREAD'],
  61 + 'defines!': ['CORO_UCONTEXT', 'CORO_SJLJ', 'CORO_ASM'],
  62 + },
  63 + ],
  64 + ],
  65 + },
  66 + ],
  67 +}
  1 +#!/usr/bin/env node
  2 +var cp = require('child_process'),
  3 + fs = require('fs'),
  4 + path = require('path');
  5 +
  6 +// Parse args
  7 +var force = false, debug = false;
  8 +var
  9 + arch = process.arch,
  10 + platform = process.platform;
  11 +var args = process.argv.slice(2).filter(function(arg) {
  12 + if (arg === '-f') {
  13 + force = true;
  14 + return false;
  15 + } else if (arg.substring(0, 13) === '--target_arch') {
  16 + arch = arg.substring(14);
  17 + } else if (arg === '--debug') {
  18 + debug = true;
  19 + }
  20 + return true;
  21 +});
  22 +if (!debug) {
  23 + args.push('--release');
  24 +}
  25 +if (!{ia32: true, x64: true, arm: true, arm64: true, ppc: true, ppc64: true, s390: true, s390x: true}.hasOwnProperty(arch)) {
  26 + console.error('Unsupported (?) architecture: `'+ arch+ '`');
  27 + process.exit(1);
  28 +}
  29 +
  30 +// Test for pre-built library
  31 +var modPath = platform+ '-'+ arch+ '-'+ process.versions.modules;
  32 +if (!force) {
  33 + try {
  34 + fs.statSync(path.join(__dirname, 'bin', modPath, 'fibers.node'));
  35 + console.log('`'+ modPath+ '` exists; testing');
  36 + cp.execFile(process.execPath, ['quick-test'], function(err, stdout, stderr) {
  37 + if (err || stdout !== 'pass' || stderr) {
  38 + console.log('Problem with the binary; manual build incoming');
  39 + build();
  40 + } else {
  41 + console.log('Binary is fine; exiting');
  42 + }
  43 + });
  44 + } catch (ex) {
  45 + // Stat failed
  46 + build();
  47 + }
  48 +} else {
  49 + build();
  50 +}
  51 +
  52 +// Build it
  53 +function build() {
  54 + if (process.versions.electron) {
  55 + args.push('--target='+ process.versions.electron, '--dist-url=https://atom.io/download/atom-shell');
  56 + }
  57 + cp.spawn(
  58 + process.platform === 'win32' ? 'node-gyp.cmd' : 'node-gyp',
  59 + ['rebuild'].concat(args),
  60 + {stdio: [process.stdin, process.stdout, process.stderr]})
  61 + .on('exit', function(err) {
  62 + if (err) {
  63 + console.error(
  64 + 'node-gyp exited with code: '+ err+ '\n'+
  65 + 'Please make sure you are using a supported platform and node version. If you\n'+
  66 + 'would like to compile fibers on this machine please make sure you have setup your\n'+
  67 + 'build environment--\n'+
  68 + 'Windows + OS X instructions here: https://github.com/nodejs/node-gyp\n'+
  69 + 'Ubuntu users please run: `sudo apt-get install g++ build-essential`\n'+
  70 + 'Alpine users please run: `sudo apk add python make g++`'
  71 + );
  72 + return process.exit(err);
  73 + }
  74 + afterBuild();
  75 + })
  76 + .on('error', function(err) {
  77 + console.error(
  78 + 'node-gyp not found! Please ensure node-gyp is in your PATH--\n'+
  79 + 'Try running: `sudo npm install -g node-gyp`'
  80 + );
  81 + console.log(err.message);
  82 + process.exit(1);
  83 + });
  84 +}
  85 +
  86 +// Move it to expected location
  87 +function afterBuild() {
  88 + var targetPath = path.join(__dirname, 'build', debug ? 'Debug' : 'Release', 'fibers.node');
  89 + var installPath = path.join(__dirname, 'bin', modPath, 'fibers.node');
  90 +
  91 + try {
  92 + fs.mkdirSync(path.join(__dirname, 'bin', modPath));
  93 + } catch (ex) {}
  94 +
  95 + try {
  96 + fs.statSync(targetPath);
  97 + } catch (ex) {
  98 + console.error('Build succeeded but target not found');
  99 + process.exit(1);
  100 + }
  101 + fs.renameSync(targetPath, installPath);
  102 + console.log('Installed in `'+ installPath+ '`');
  103 + if (process.versions.electron) {
  104 + process.nextTick(function() {
  105 + require('electron').app.quit();
  106 + });
  107 + }
  108 +}
  1 +# We borrow heavily from the kernel build setup, though we are simpler since
  2 +# we don't have Kconfig tweaking settings on us.
  3 +
  4 +# The implicit make rules have it looking for RCS files, among other things.
  5 +# We instead explicitly write all the rules we care about.
  6 +# It's even quicker (saves ~200ms) to pass -r on the command line.
  7 +MAKEFLAGS=-r
  8 +
  9 +# The source directory tree.
  10 +srcdir := ..
  11 +abs_srcdir := $(abspath $(srcdir))
  12 +
  13 +# The name of the builddir.
  14 +builddir_name ?= .
  15 +
  16 +# The V=1 flag on command line makes us verbosely print command lines.
  17 +ifdef V
  18 + quiet=
  19 +else
  20 + quiet=quiet_
  21 +endif
  22 +
  23 +# Specify BUILDTYPE=Release on the command line for a release build.
  24 +BUILDTYPE ?= Release
  25 +
  26 +# Directory all our build output goes into.
  27 +# Note that this must be two directories beneath src/ for unit tests to pass,
  28 +# as they reach into the src/ directory for data with relative paths.
  29 +builddir ?= $(builddir_name)/$(BUILDTYPE)
  30 +abs_builddir := $(abspath $(builddir))
  31 +depsdir := $(builddir)/.deps
  32 +
  33 +# Object output directory.
  34 +obj := $(builddir)/obj
  35 +abs_obj := $(abspath $(obj))
  36 +
  37 +# We build up a list of every single one of the targets so we can slurp in the
  38 +# generated dependency rule Makefiles in one pass.
  39 +all_deps :=
  40 +
  41 +
  42 +
  43 +CC.target ?= $(CC)
  44 +CFLAGS.target ?= $(CPPFLAGS) $(CFLAGS)
  45 +CXX.target ?= $(CXX)
  46 +CXXFLAGS.target ?= $(CPPFLAGS) $(CXXFLAGS)
  47 +LINK.target ?= $(LINK)
  48 +LDFLAGS.target ?= $(LDFLAGS)
  49 +AR.target ?= $(AR)
  50 +
  51 +# C++ apps need to be linked with g++.
  52 +LINK ?= $(CXX.target)
  53 +
  54 +# TODO(evan): move all cross-compilation logic to gyp-time so we don't need
  55 +# to replicate this environment fallback in make as well.
  56 +CC.host ?= gcc
  57 +CFLAGS.host ?= $(CPPFLAGS_host) $(CFLAGS_host)
  58 +CXX.host ?= g++
  59 +CXXFLAGS.host ?= $(CPPFLAGS_host) $(CXXFLAGS_host)
  60 +LINK.host ?= $(CXX.host)
  61 +LDFLAGS.host ?=
  62 +AR.host ?= ar
  63 +
  64 +# Define a dir function that can handle spaces.
  65 +# http://www.gnu.org/software/make/manual/make.html#Syntax-of-Functions
  66 +# "leading spaces cannot appear in the text of the first argument as written.
  67 +# These characters can be put into the argument value by variable substitution."
  68 +empty :=
  69 +space := $(empty) $(empty)
  70 +
  71 +# http://stackoverflow.com/questions/1189781/using-make-dir-or-notdir-on-a-path-with-spaces
  72 +replace_spaces = $(subst $(space),?,$1)
  73 +unreplace_spaces = $(subst ?,$(space),$1)
  74 +dirx = $(call unreplace_spaces,$(dir $(call replace_spaces,$1)))
  75 +
  76 +# Flags to make gcc output dependency info. Note that you need to be
  77 +# careful here to use the flags that ccache and distcc can understand.
  78 +# We write to a dep file on the side first and then rename at the end
  79 +# so we can't end up with a broken dep file.
  80 +depfile = $(depsdir)/$(call replace_spaces,$@).d
  81 +DEPFLAGS = -MMD -MF $(depfile).raw
  82 +
  83 +# We have to fixup the deps output in a few ways.
  84 +# (1) the file output should mention the proper .o file.
  85 +# ccache or distcc lose the path to the target, so we convert a rule of
  86 +# the form:
  87 +# foobar.o: DEP1 DEP2
  88 +# into
  89 +# path/to/foobar.o: DEP1 DEP2
  90 +# (2) we want missing files not to cause us to fail to build.
  91 +# We want to rewrite
  92 +# foobar.o: DEP1 DEP2 \
  93 +# DEP3
  94 +# to
  95 +# DEP1:
  96 +# DEP2:
  97 +# DEP3:
  98 +# so if the files are missing, they're just considered phony rules.
  99 +# We have to do some pretty insane escaping to get those backslashes
  100 +# and dollar signs past make, the shell, and sed at the same time.
  101 +# Doesn't work with spaces, but that's fine: .d files have spaces in
  102 +# their names replaced with other characters.
  103 +define fixup_dep
  104 +# The depfile may not exist if the input file didn't have any #includes.
  105 +touch $(depfile).raw
  106 +# Fixup path as in (1).
  107 +sed -e "s|^$(notdir $@)|$@|" $(depfile).raw >> $(depfile)
  108 +# Add extra rules as in (2).
  109 +# We remove slashes and replace spaces with new lines;
  110 +# remove blank lines;
  111 +# delete the first line and append a colon to the remaining lines.
  112 +sed -e 's|\\||' -e 'y| |\n|' $(depfile).raw |\
  113 + grep -v '^$$' |\
  114 + sed -e 1d -e 's|$$|:|' \
  115 + >> $(depfile)
  116 +rm $(depfile).raw
  117 +endef
  118 +
  119 +# Command definitions:
  120 +# - cmd_foo is the actual command to run;
  121 +# - quiet_cmd_foo is the brief-output summary of the command.
  122 +
  123 +quiet_cmd_cc = CC($(TOOLSET)) $@
  124 +cmd_cc = $(CC.$(TOOLSET)) $(GYP_CFLAGS) $(DEPFLAGS) $(CFLAGS.$(TOOLSET)) -c -o $@ $<
  125 +
  126 +quiet_cmd_cxx = CXX($(TOOLSET)) $@
  127 +cmd_cxx = $(CXX.$(TOOLSET)) $(GYP_CXXFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $<
  128 +
  129 +quiet_cmd_objc = CXX($(TOOLSET)) $@
  130 +cmd_objc = $(CC.$(TOOLSET)) $(GYP_OBJCFLAGS) $(DEPFLAGS) -c -o $@ $<
  131 +
  132 +quiet_cmd_objcxx = CXX($(TOOLSET)) $@
  133 +cmd_objcxx = $(CXX.$(TOOLSET)) $(GYP_OBJCXXFLAGS) $(DEPFLAGS) -c -o $@ $<
  134 +
  135 +# Commands for precompiled header files.
  136 +quiet_cmd_pch_c = CXX($(TOOLSET)) $@
  137 +cmd_pch_c = $(CC.$(TOOLSET)) $(GYP_PCH_CFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $<
  138 +quiet_cmd_pch_cc = CXX($(TOOLSET)) $@
  139 +cmd_pch_cc = $(CC.$(TOOLSET)) $(GYP_PCH_CXXFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $<
  140 +quiet_cmd_pch_m = CXX($(TOOLSET)) $@
  141 +cmd_pch_m = $(CC.$(TOOLSET)) $(GYP_PCH_OBJCFLAGS) $(DEPFLAGS) -c -o $@ $<
  142 +quiet_cmd_pch_mm = CXX($(TOOLSET)) $@
  143 +cmd_pch_mm = $(CC.$(TOOLSET)) $(GYP_PCH_OBJCXXFLAGS) $(DEPFLAGS) -c -o $@ $<
  144 +
  145 +# gyp-mac-tool is written next to the root Makefile by gyp.
  146 +# Use $(4) for the command, since $(2) and $(3) are used as flag by do_cmd
  147 +# already.
  148 +quiet_cmd_mac_tool = MACTOOL $(4) $<
  149 +cmd_mac_tool = ./gyp-mac-tool $(4) $< "$@"
  150 +
  151 +quiet_cmd_mac_package_framework = PACKAGE FRAMEWORK $@
  152 +cmd_mac_package_framework = ./gyp-mac-tool package-framework "$@" $(4)
  153 +
  154 +quiet_cmd_infoplist = INFOPLIST $@
  155 +cmd_infoplist = $(CC.$(TOOLSET)) -E -P -Wno-trigraphs -x c $(INFOPLIST_DEFINES) "$<" -o "$@"
  156 +
  157 +quiet_cmd_touch = TOUCH $@
  158 +cmd_touch = touch $@
  159 +
  160 +quiet_cmd_copy = COPY $@
  161 +# send stderr to /dev/null to ignore messages when linking directories.
  162 +cmd_copy = rm -rf "$@" && cp -af "$<" "$@"
  163 +
  164 +quiet_cmd_alink = LIBTOOL-STATIC $@
  165 +cmd_alink = rm -f $@ && ./gyp-mac-tool filter-libtool libtool $(GYP_LIBTOOLFLAGS) -static -o $@ $(filter %.o,$^)
  166 +
  167 +quiet_cmd_link = LINK($(TOOLSET)) $@
  168 +cmd_link = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o "$@" $(LD_INPUTS) $(LIBS)
  169 +
  170 +quiet_cmd_solink = SOLINK($(TOOLSET)) $@
  171 +cmd_solink = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o "$@" $(LD_INPUTS) $(LIBS)
  172 +
  173 +quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@
  174 +cmd_solink_module = $(LINK.$(TOOLSET)) -bundle $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(filter-out FORCE_DO_CMD, $^) $(LIBS)
  175 +
  176 +
  177 +# Define an escape_quotes function to escape single quotes.
  178 +# This allows us to handle quotes properly as long as we always use
  179 +# use single quotes and escape_quotes.
  180 +escape_quotes = $(subst ','\'',$(1))
  181 +# This comment is here just to include a ' to unconfuse syntax highlighting.
  182 +# Define an escape_vars function to escape '$' variable syntax.
  183 +# This allows us to read/write command lines with shell variables (e.g.
  184 +# $LD_LIBRARY_PATH), without triggering make substitution.
  185 +escape_vars = $(subst $$,$$$$,$(1))
  186 +# Helper that expands to a shell command to echo a string exactly as it is in
  187 +# make. This uses printf instead of echo because printf's behaviour with respect
  188 +# to escape sequences is more portable than echo's across different shells
  189 +# (e.g., dash, bash).
  190 +exact_echo = printf '%s\n' '$(call escape_quotes,$(1))'
  191 +
  192 +# Helper to compare the command we're about to run against the command
  193 +# we logged the last time we ran the command. Produces an empty
  194 +# string (false) when the commands match.
  195 +# Tricky point: Make has no string-equality test function.
  196 +# The kernel uses the following, but it seems like it would have false
  197 +# positives, where one string reordered its arguments.
  198 +# arg_check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \
  199 +# $(filter-out $(cmd_$@), $(cmd_$(1))))
  200 +# We instead substitute each for the empty string into the other, and
  201 +# say they're equal if both substitutions produce the empty string.
  202 +# .d files contain ? instead of spaces, take that into account.
  203 +command_changed = $(or $(subst $(cmd_$(1)),,$(cmd_$(call replace_spaces,$@))),\
  204 + $(subst $(cmd_$(call replace_spaces,$@)),,$(cmd_$(1))))
  205 +
  206 +# Helper that is non-empty when a prerequisite changes.
  207 +# Normally make does this implicitly, but we force rules to always run
  208 +# so we can check their command lines.
  209 +# $? -- new prerequisites
  210 +# $| -- order-only dependencies
  211 +prereq_changed = $(filter-out FORCE_DO_CMD,$(filter-out $|,$?))
  212 +
  213 +# Helper that executes all postbuilds until one fails.
  214 +define do_postbuilds
  215 + @E=0;\
  216 + for p in $(POSTBUILDS); do\
  217 + eval $$p;\
  218 + E=$$?;\
  219 + if [ $$E -ne 0 ]; then\
  220 + break;\
  221 + fi;\
  222 + done;\
  223 + if [ $$E -ne 0 ]; then\
  224 + rm -rf "$@";\
  225 + exit $$E;\
  226 + fi
  227 +endef
  228 +
  229 +# do_cmd: run a command via the above cmd_foo names, if necessary.
  230 +# Should always run for a given target to handle command-line changes.
  231 +# Second argument, if non-zero, makes it do asm/C/C++ dependency munging.
  232 +# Third argument, if non-zero, makes it do POSTBUILDS processing.
  233 +# Note: We intentionally do NOT call dirx for depfile, since it contains ? for
  234 +# spaces already and dirx strips the ? characters.
  235 +define do_cmd
  236 +$(if $(or $(command_changed),$(prereq_changed)),
  237 + @$(call exact_echo, $($(quiet)cmd_$(1)))
  238 + @mkdir -p "$(call dirx,$@)" "$(dir $(depfile))"
  239 + $(if $(findstring flock,$(word 2,$(cmd_$1))),
  240 + @$(cmd_$(1))
  241 + @echo " $(quiet_cmd_$(1)): Finished",
  242 + @$(cmd_$(1))
  243 + )
  244 + @$(call exact_echo,$(call escape_vars,cmd_$(call replace_spaces,$@) := $(cmd_$(1)))) > $(depfile)
  245 + @$(if $(2),$(fixup_dep))
  246 + $(if $(and $(3), $(POSTBUILDS)),
  247 + $(call do_postbuilds)
  248 + )
  249 +)
  250 +endef
  251 +
  252 +# Declare the "all" target first so it is the default,
  253 +# even though we don't have the deps yet.
  254 +.PHONY: all
  255 +all:
  256 +
  257 +# make looks for ways to re-generate included makefiles, but in our case, we
  258 +# don't have a direct way. Explicitly telling make that it has nothing to do
  259 +# for them makes it go faster.
  260 +%.d: ;
  261 +
  262 +# Use FORCE_DO_CMD to force a target to run. Should be coupled with
  263 +# do_cmd.
  264 +.PHONY: FORCE_DO_CMD
  265 +FORCE_DO_CMD:
  266 +
  267 +TOOLSET := target
  268 +# Suffix rules, putting all outputs into $(obj).
  269 +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.c FORCE_DO_CMD
  270 + @$(call do_cmd,cc,1)
  271 +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cc FORCE_DO_CMD
  272 + @$(call do_cmd,cxx,1)
  273 +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cpp FORCE_DO_CMD
  274 + @$(call do_cmd,cxx,1)
  275 +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cxx FORCE_DO_CMD
  276 + @$(call do_cmd,cxx,1)
  277 +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.m FORCE_DO_CMD
  278 + @$(call do_cmd,objc,1)
  279 +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.mm FORCE_DO_CMD
  280 + @$(call do_cmd,objcxx,1)
  281 +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.S FORCE_DO_CMD
  282 + @$(call do_cmd,cc,1)
  283 +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.s FORCE_DO_CMD
  284 + @$(call do_cmd,cc,1)
  285 +
  286 +# Try building from generated source, too.
  287 +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD
  288 + @$(call do_cmd,cc,1)
  289 +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cc FORCE_DO_CMD
  290 + @$(call do_cmd,cxx,1)
  291 +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cpp FORCE_DO_CMD
  292 + @$(call do_cmd,cxx,1)
  293 +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cxx FORCE_DO_CMD
  294 + @$(call do_cmd,cxx,1)
  295 +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.m FORCE_DO_CMD
  296 + @$(call do_cmd,objc,1)
  297 +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.mm FORCE_DO_CMD
  298 + @$(call do_cmd,objcxx,1)
  299 +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.S FORCE_DO_CMD
  300 + @$(call do_cmd,cc,1)
  301 +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.s FORCE_DO_CMD
  302 + @$(call do_cmd,cc,1)
  303 +
  304 +$(obj).$(TOOLSET)/%.o: $(obj)/%.c FORCE_DO_CMD
  305 + @$(call do_cmd,cc,1)
  306 +$(obj).$(TOOLSET)/%.o: $(obj)/%.cc FORCE_DO_CMD
  307 + @$(call do_cmd,cxx,1)
  308 +$(obj).$(TOOLSET)/%.o: $(obj)/%.cpp FORCE_DO_CMD
  309 + @$(call do_cmd,cxx,1)
  310 +$(obj).$(TOOLSET)/%.o: $(obj)/%.cxx FORCE_DO_CMD
  311 + @$(call do_cmd,cxx,1)
  312 +$(obj).$(TOOLSET)/%.o: $(obj)/%.m FORCE_DO_CMD
  313 + @$(call do_cmd,objc,1)
  314 +$(obj).$(TOOLSET)/%.o: $(obj)/%.mm FORCE_DO_CMD
  315 + @$(call do_cmd,objcxx,1)
  316 +$(obj).$(TOOLSET)/%.o: $(obj)/%.S FORCE_DO_CMD
  317 + @$(call do_cmd,cc,1)
  318 +$(obj).$(TOOLSET)/%.o: $(obj)/%.s FORCE_DO_CMD
  319 + @$(call do_cmd,cc,1)
  320 +
  321 +
  322 +ifeq ($(strip $(foreach prefix,$(NO_LOAD),\
  323 + $(findstring $(join ^,$(prefix)),\
  324 + $(join ^,fibers.target.mk)))),)
  325 + include fibers.target.mk
  326 +endif
  327 +
  328 +quiet_cmd_regen_makefile = ACTION Regenerating $@
  329 +cmd_regen_makefile = cd $(srcdir); /usr/local/lib/node_modules/cnpm/node_modules/npminstall/node_modules/node-gyp/gyp/gyp_main.py -fmake --ignore-environment "--toplevel-dir=." -I/Users/fzy/project/koa2_Sequelize_project/node_modules/_fibers@1.0.15@fibers/build/config.gypi -I/usr/local/lib/node_modules/cnpm/node_modules/npminstall/node_modules/node-gyp/addon.gypi -I/Users/fzy/.node-gyp/8.2.1/include/node/common.gypi "--depth=." "-Goutput_dir=." "--generator-output=build" "-Dlibrary=shared_library" "-Dvisibility=default" "-Dnode_root_dir=/Users/fzy/.node-gyp/8.2.1" "-Dnode_gyp_dir=/usr/local/lib/node_modules/cnpm/node_modules/npminstall/node_modules/node-gyp" "-Dnode_lib_file=node.lib" "-Dmodule_root_dir=/Users/fzy/project/koa2_Sequelize_project/node_modules/_fibers@1.0.15@fibers" "-Dnode_engine=v8" binding.gyp
  330 +Makefile: $(srcdir)/../../../../.node-gyp/8.2.1/include/node/common.gypi $(srcdir)/../../../../../../usr/local/lib/node_modules/cnpm/node_modules/npminstall/node_modules/node-gyp/addon.gypi $(srcdir)/build/config.gypi $(srcdir)/binding.gyp
  331 + $(call do_cmd,regen_makefile)
  332 +
  333 +# "all" is a concatenation of the "all" targets from all the included
  334 +# sub-makefiles. This is just here to clarify.
  335 +all:
  336 +
  337 +# Add in dependency-tracking rules. $(all_deps) is the list of every single
  338 +# target in our tree. Only consider the ones with .d (dependency) info:
  339 +d_files := $(wildcard $(foreach f,$(all_deps),$(depsdir)/$(f).d))
  340 +ifneq ($(d_files),)
  341 + include $(d_files)
  342 +endif
  1 +cmd_Release/fibers.node := c++ -bundle -undefined dynamic_lookup -Wl,-no_pie -Wl,-search_paths_first -mmacosx-version-min=10.7 -arch x86_64 -L./Release -stdlib=libc++ -o Release/fibers.node Release/obj.target/fibers/src/fibers.o Release/obj.target/fibers/src/coroutine.o Release/obj.target/fibers/src/libcoro/coro.o
  1 +cmd_Release/obj.target/fibers/src/coroutine.o := c++ '-DNODE_GYP_MODULE_NAME=fibers' '-DUSING_UV_SHARED=1' '-DUSING_V8_SHARED=1' '-DV8_DEPRECATION_WARNINGS=1' '-D_DARWIN_USE_64_BIT_INODE=1' '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-DUSE_CORO' '-DCORO_GUARDPAGES=1' '-DCORO_SJLJ' '-DBUILDING_NODE_EXTENSION' -I/Users/fzy/.node-gyp/8.2.1/include/node -I/Users/fzy/.node-gyp/8.2.1/src -I/Users/fzy/.node-gyp/8.2.1/deps/uv/include -I/Users/fzy/.node-gyp/8.2.1/deps/v8/include -O3 -mmacosx-version-min=10.7 -arch x86_64 -Wall -Wendif-labels -W -Wno-unused-parameter -std=gnu++0x -stdlib=libc++ -fno-rtti -fno-exceptions -fno-threadsafe-statics -fno-strict-aliasing -MMD -MF ./Release/.deps/Release/obj.target/fibers/src/coroutine.o.d.raw -c -o Release/obj.target/fibers/src/coroutine.o ../src/coroutine.cc
  2 +Release/obj.target/fibers/src/coroutine.o: ../src/coroutine.cc \
  3 + ../src/coroutine.h /Users/fzy/.node-gyp/8.2.1/include/node/node.h \
  4 + /Users/fzy/.node-gyp/8.2.1/include/node/v8.h \
  5 + /Users/fzy/.node-gyp/8.2.1/include/node/v8-version.h \
  6 + /Users/fzy/.node-gyp/8.2.1/include/node/v8config.h \
  7 + /Users/fzy/.node-gyp/8.2.1/include/node/node_version.h \
  8 + ../src/libcoro/coro.h ../src/v8-version.h
  9 +../src/coroutine.cc:
  10 +../src/coroutine.h:
  11 +/Users/fzy/.node-gyp/8.2.1/include/node/node.h:
  12 +/Users/fzy/.node-gyp/8.2.1/include/node/v8.h:
  13 +/Users/fzy/.node-gyp/8.2.1/include/node/v8-version.h:
  14 +/Users/fzy/.node-gyp/8.2.1/include/node/v8config.h:
  15 +/Users/fzy/.node-gyp/8.2.1/include/node/node_version.h:
  16 +../src/libcoro/coro.h:
  17 +../src/v8-version.h:
  1 +cmd_Release/obj.target/fibers/src/fibers.o := c++ '-DNODE_GYP_MODULE_NAME=fibers' '-DUSING_UV_SHARED=1' '-DUSING_V8_SHARED=1' '-DV8_DEPRECATION_WARNINGS=1' '-D_DARWIN_USE_64_BIT_INODE=1' '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-DUSE_CORO' '-DCORO_GUARDPAGES=1' '-DCORO_SJLJ' '-DBUILDING_NODE_EXTENSION' -I/Users/fzy/.node-gyp/8.2.1/include/node -I/Users/fzy/.node-gyp/8.2.1/src -I/Users/fzy/.node-gyp/8.2.1/deps/uv/include -I/Users/fzy/.node-gyp/8.2.1/deps/v8/include -O3 -mmacosx-version-min=10.7 -arch x86_64 -Wall -Wendif-labels -W -Wno-unused-parameter -std=gnu++0x -stdlib=libc++ -fno-rtti -fno-exceptions -fno-threadsafe-statics -fno-strict-aliasing -MMD -MF ./Release/.deps/Release/obj.target/fibers/src/fibers.o.d.raw -c -o Release/obj.target/fibers/src/fibers.o ../src/fibers.cc
  2 +Release/obj.target/fibers/src/fibers.o: ../src/fibers.cc \
  3 + ../src/coroutine.h /Users/fzy/.node-gyp/8.2.1/include/node/node.h \
  4 + /Users/fzy/.node-gyp/8.2.1/include/node/v8.h \
  5 + /Users/fzy/.node-gyp/8.2.1/include/node/v8-version.h \
  6 + /Users/fzy/.node-gyp/8.2.1/include/node/v8config.h \
  7 + /Users/fzy/.node-gyp/8.2.1/include/node/node_version.h \
  8 + ../src/libcoro/coro.h ../src/v8-version.h
  9 +../src/fibers.cc:
  10 +../src/coroutine.h:
  11 +/Users/fzy/.node-gyp/8.2.1/include/node/node.h:
  12 +/Users/fzy/.node-gyp/8.2.1/include/node/v8.h:
  13 +/Users/fzy/.node-gyp/8.2.1/include/node/v8-version.h:
  14 +/Users/fzy/.node-gyp/8.2.1/include/node/v8config.h:
  15 +/Users/fzy/.node-gyp/8.2.1/include/node/node_version.h:
  16 +../src/libcoro/coro.h:
  17 +../src/v8-version.h:
  1 +cmd_Release/obj.target/fibers/src/libcoro/coro.o := cc '-DNODE_GYP_MODULE_NAME=fibers' '-DUSING_UV_SHARED=1' '-DUSING_V8_SHARED=1' '-DV8_DEPRECATION_WARNINGS=1' '-D_DARWIN_USE_64_BIT_INODE=1' '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-DUSE_CORO' '-DCORO_GUARDPAGES=1' '-DCORO_SJLJ' '-DBUILDING_NODE_EXTENSION' -I/Users/fzy/.node-gyp/8.2.1/include/node -I/Users/fzy/.node-gyp/8.2.1/src -I/Users/fzy/.node-gyp/8.2.1/deps/uv/include -I/Users/fzy/.node-gyp/8.2.1/deps/v8/include -O3 -mmacosx-version-min=10.7 -arch x86_64 -Wall -Wendif-labels -W -Wno-unused-parameter -fno-strict-aliasing -MMD -MF ./Release/.deps/Release/obj.target/fibers/src/libcoro/coro.o.d.raw -c -o Release/obj.target/fibers/src/libcoro/coro.o ../src/libcoro/coro.c
  2 +Release/obj.target/fibers/src/libcoro/coro.o: ../src/libcoro/coro.c \
  3 + ../src/libcoro/coro.h
  4 +../src/libcoro/coro.c:
  5 +../src/libcoro/coro.h:
  1 +# This file is generated by gyp; do not edit.
  2 +
  3 +export builddir_name ?= ./build/.
  4 +.PHONY: all
  5 +all:
  6 + $(MAKE) fibers
  1 +# Do not edit. File was generated by node-gyp's "configure" step
  2 +{
  3 + "target_defaults": {
  4 + "cflags": [],
  5 + "default_configuration": "Release",
  6 + "defines": [],
  7 + "include_dirs": [],
  8 + "libraries": []
  9 + },
  10 + "variables": {
  11 + "asan": 0,
  12 + "coverage": "false",
  13 + "debug_devtools": "node",
  14 + "force_dynamic_crt": 0,
  15 + "host_arch": "x64",
  16 + "icu_data_file": "icudt59l.dat",
  17 + "icu_data_in": "../../deps/icu-small/source/data/in/icudt59l.dat",
  18 + "icu_endianness": "l",
  19 + "icu_gyp_path": "tools/icu/icu-generic.gyp",
  20 + "icu_locales": "en,root",
  21 + "icu_path": "deps/icu-small",
  22 + "icu_small": "true",
  23 + "icu_ver_major": "59",
  24 + "llvm_version": 0,
  25 + "node_byteorder": "little",
  26 + "node_enable_d8": "false",
  27 + "node_enable_v8_vtunejit": "false",
  28 + "node_install_npm": "true",
  29 + "node_module_version": 57,
  30 + "node_no_browser_globals": "false",
  31 + "node_prefix": "/",
  32 + "node_release_urlbase": "https://nodejs.org/download/release/",
  33 + "node_shared": "false",
  34 + "node_shared_cares": "false",
  35 + "node_shared_http_parser": "false",
  36 + "node_shared_libuv": "false",
  37 + "node_shared_openssl": "false",
  38 + "node_shared_zlib": "false",
  39 + "node_tag": "",
  40 + "node_use_bundled_v8": "true",
  41 + "node_use_dtrace": "true",
  42 + "node_use_etw": "false",
  43 + "node_use_lttng": "false",
  44 + "node_use_openssl": "true",
  45 + "node_use_perfctr": "false",
  46 + "node_use_v8_platform": "true",
  47 + "node_without_node_options": "false",
  48 + "openssl_fips": "",
  49 + "openssl_no_asm": 0,
  50 + "shlib_suffix": "57.dylib",
  51 + "target_arch": "x64",
  52 + "uv_parent_path": "/deps/uv/",
  53 + "uv_use_dtrace": "true",
  54 + "v8_enable_gdbjit": 0,
  55 + "v8_enable_i18n_support": 1,
  56 + "v8_enable_inspector": 1,
  57 + "v8_no_strict_aliasing": 1,
  58 + "v8_optimized_debug": 0,
  59 + "v8_promise_internal_field_count": 1,
  60 + "v8_random_seed": 0,
  61 + "v8_trace_maps": 0,
  62 + "v8_use_snapshot": "false",
  63 + "want_separate_host_toolset": 0,
  64 + "want_separate_host_toolset_mkpeephole": 0,
  65 + "xcode_version": "7.0",
  66 + "nodedir": "/Users/fzy/.node-gyp/8.2.1",
  67 + "copy_dev_lib": "true",
  68 + "standalone_static_library": 1,
  69 + "registry": "https://registry.npm.taobao.org",
  70 + "userconfig": "/Users/fzy/.cnpmrc",
  71 + "r": "https://registry.npm.taobao.org",
  72 + "disturl": "https://npm.taobao.org/mirrors/node",
  73 + "cache": "/Users/fzy/.npminstall_tarball"
  74 + }
  75 +}
  1 +# This file is generated by gyp; do not edit.
  2 +
  3 +TOOLSET := target
  4 +TARGET := fibers
  5 +DEFS_Debug := \
  6 + '-DNODE_GYP_MODULE_NAME=fibers' \
  7 + '-DUSING_UV_SHARED=1' \
  8 + '-DUSING_V8_SHARED=1' \
  9 + '-DV8_DEPRECATION_WARNINGS=1' \
  10 + '-D_DARWIN_USE_64_BIT_INODE=1' \
  11 + '-D_LARGEFILE_SOURCE' \
  12 + '-D_FILE_OFFSET_BITS=64' \
  13 + '-DUSE_CORO' \
  14 + '-DCORO_GUARDPAGES=1' \
  15 + '-DCORO_SJLJ' \
  16 + '-DBUILDING_NODE_EXTENSION' \
  17 + '-DDEBUG' \
  18 + '-D_DEBUG' \
  19 + '-DV8_ENABLE_CHECKS'
  20 +
  21 +# Flags passed to all source files.
  22 +CFLAGS_Debug := \
  23 + -O0 \
  24 + -gdwarf-2 \
  25 + -mmacosx-version-min=10.7 \
  26 + -arch x86_64 \
  27 + -Wall \
  28 + -Wendif-labels \
  29 + -W \
  30 + -Wno-unused-parameter
  31 +
  32 +# Flags passed to only C files.
  33 +CFLAGS_C_Debug := \
  34 + -fno-strict-aliasing
  35 +
  36 +# Flags passed to only C++ files.
  37 +CFLAGS_CC_Debug := \
  38 + -std=gnu++0x \
  39 + -stdlib=libc++ \
  40 + -fno-rtti \
  41 + -fno-exceptions \
  42 + -fno-threadsafe-statics \
  43 + -fno-strict-aliasing
  44 +
  45 +# Flags passed to only ObjC files.
  46 +CFLAGS_OBJC_Debug :=
  47 +
  48 +# Flags passed to only ObjC++ files.
  49 +CFLAGS_OBJCC_Debug :=
  50 +
  51 +INCS_Debug := \
  52 + -I/Users/fzy/.node-gyp/8.2.1/include/node \
  53 + -I/Users/fzy/.node-gyp/8.2.1/src \
  54 + -I/Users/fzy/.node-gyp/8.2.1/deps/uv/include \
  55 + -I/Users/fzy/.node-gyp/8.2.1/deps/v8/include
  56 +
  57 +DEFS_Release := \
  58 + '-DNODE_GYP_MODULE_NAME=fibers' \
  59 + '-DUSING_UV_SHARED=1' \
  60 + '-DUSING_V8_SHARED=1' \
  61 + '-DV8_DEPRECATION_WARNINGS=1' \
  62 + '-D_DARWIN_USE_64_BIT_INODE=1' \
  63 + '-D_LARGEFILE_SOURCE' \
  64 + '-D_FILE_OFFSET_BITS=64' \
  65 + '-DUSE_CORO' \
  66 + '-DCORO_GUARDPAGES=1' \
  67 + '-DCORO_SJLJ' \
  68 + '-DBUILDING_NODE_EXTENSION'
  69 +
  70 +# Flags passed to all source files.
  71 +CFLAGS_Release := \
  72 + -O3 \
  73 + -mmacosx-version-min=10.7 \
  74 + -arch x86_64 \
  75 + -Wall \
  76 + -Wendif-labels \
  77 + -W \
  78 + -Wno-unused-parameter
  79 +
  80 +# Flags passed to only C files.
  81 +CFLAGS_C_Release := \
  82 + -fno-strict-aliasing
  83 +
  84 +# Flags passed to only C++ files.
  85 +CFLAGS_CC_Release := \
  86 + -std=gnu++0x \
  87 + -stdlib=libc++ \
  88 + -fno-rtti \
  89 + -fno-exceptions \
  90 + -fno-threadsafe-statics \
  91 + -fno-strict-aliasing
  92 +
  93 +# Flags passed to only ObjC files.
  94 +CFLAGS_OBJC_Release :=
  95 +
  96 +# Flags passed to only ObjC++ files.
  97 +CFLAGS_OBJCC_Release :=
  98 +
  99 +INCS_Release := \
  100 + -I/Users/fzy/.node-gyp/8.2.1/include/node \
  101 + -I/Users/fzy/.node-gyp/8.2.1/src \
  102 + -I/Users/fzy/.node-gyp/8.2.1/deps/uv/include \
  103 + -I/Users/fzy/.node-gyp/8.2.1/deps/v8/include
  104 +
  105 +OBJS := \
  106 + $(obj).target/$(TARGET)/src/fibers.o \
  107 + $(obj).target/$(TARGET)/src/coroutine.o \
  108 + $(obj).target/$(TARGET)/src/libcoro/coro.o
  109 +
  110 +# Add to the list of files we specially track dependencies for.
  111 +all_deps += $(OBJS)
  112 +
  113 +# CFLAGS et al overrides must be target-local.
  114 +# See "Target-specific Variable Values" in the GNU Make manual.
  115 +$(OBJS): TOOLSET := $(TOOLSET)
  116 +$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE))
  117 +$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE))
  118 +$(OBJS): GYP_OBJCFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE)) $(CFLAGS_OBJC_$(BUILDTYPE))
  119 +$(OBJS): GYP_OBJCXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE)) $(CFLAGS_OBJCC_$(BUILDTYPE))
  120 +
  121 +# Suffix rules, putting all outputs into $(obj).
  122 +
  123 +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.cc FORCE_DO_CMD
  124 + @$(call do_cmd,cxx,1)
  125 +
  126 +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.c FORCE_DO_CMD
  127 + @$(call do_cmd,cc,1)
  128 +
  129 +# Try building from generated source, too.
  130 +
  131 +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj).$(TOOLSET)/%.cc FORCE_DO_CMD
  132 + @$(call do_cmd,cxx,1)
  133 +
  134 +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD
  135 + @$(call do_cmd,cc,1)
  136 +
  137 +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.cc FORCE_DO_CMD
  138 + @$(call do_cmd,cxx,1)
  139 +
  140 +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.c FORCE_DO_CMD
  141 + @$(call do_cmd,cc,1)
  142 +
  143 +# End of this set of suffix rules
  144 +### Rules for final target.
  145 +LDFLAGS_Debug := \
  146 + -undefined dynamic_lookup \
  147 + -Wl,-no_pie \
  148 + -Wl,-search_paths_first \
  149 + -mmacosx-version-min=10.7 \
  150 + -arch x86_64 \
  151 + -L$(builddir) \
  152 + -stdlib=libc++
  153 +
  154 +LIBTOOLFLAGS_Debug := \
  155 + -undefined dynamic_lookup \
  156 + -Wl,-no_pie \
  157 + -Wl,-search_paths_first
  158 +
  159 +LDFLAGS_Release := \
  160 + -undefined dynamic_lookup \
  161 + -Wl,-no_pie \
  162 + -Wl,-search_paths_first \
  163 + -mmacosx-version-min=10.7 \
  164 + -arch x86_64 \
  165 + -L$(builddir) \
  166 + -stdlib=libc++
  167 +
  168 +LIBTOOLFLAGS_Release := \
  169 + -undefined dynamic_lookup \
  170 + -Wl,-no_pie \
  171 + -Wl,-search_paths_first
  172 +
  173 +LIBS :=
  174 +
  175 +$(builddir)/fibers.node: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE))
  176 +$(builddir)/fibers.node: LIBS := $(LIBS)
  177 +$(builddir)/fibers.node: GYP_LIBTOOLFLAGS := $(LIBTOOLFLAGS_$(BUILDTYPE))
  178 +$(builddir)/fibers.node: TOOLSET := $(TOOLSET)
  179 +$(builddir)/fibers.node: $(OBJS) FORCE_DO_CMD
  180 + $(call do_cmd,solink_module)
  181 +
  182 +all_deps += $(builddir)/fibers.node
  183 +# Add target alias
  184 +.PHONY: fibers
  185 +fibers: $(builddir)/fibers.node
  186 +
  187 +# Short alias for building this executable.
  188 +.PHONY: fibers.node
  189 +fibers.node: $(builddir)/fibers.node
  190 +
  191 +# Add executable to "all" target.
  192 +.PHONY: all
  193 +all: $(builddir)/fibers.node
  194 +
  1 +#!/usr/bin/env python
  2 +# Generated by gyp. Do not edit.
  3 +# Copyright (c) 2012 Google Inc. All rights reserved.
  4 +# Use of this source code is governed by a BSD-style license that can be
  5 +# found in the LICENSE file.
  6 +
  7 +"""Utility functions to perform Xcode-style build steps.
  8 +
  9 +These functions are executed via gyp-mac-tool when using the Makefile generator.
  10 +"""
  11 +
  12 +import fcntl
  13 +import fnmatch
  14 +import glob
  15 +import json
  16 +import os
  17 +import plistlib
  18 +import re
  19 +import shutil
  20 +import string
  21 +import subprocess
  22 +import sys
  23 +import tempfile
  24 +
  25 +
  26 +def main(args):
  27 + executor = MacTool()
  28 + exit_code = executor.Dispatch(args)
  29 + if exit_code is not None:
  30 + sys.exit(exit_code)
  31 +
  32 +
  33 +class MacTool(object):
  34 + """This class performs all the Mac tooling steps. The methods can either be
  35 + executed directly, or dispatched from an argument list."""
  36 +
  37 + def Dispatch(self, args):
  38 + """Dispatches a string command to a method."""
  39 + if len(args) < 1:
  40 + raise Exception("Not enough arguments")
  41 +
  42 + method = "Exec%s" % self._CommandifyName(args[0])
  43 + return getattr(self, method)(*args[1:])
  44 +
  45 + def _CommandifyName(self, name_string):
  46 + """Transforms a tool name like copy-info-plist to CopyInfoPlist"""
  47 + return name_string.title().replace('-', '')
  48 +
  49 + def ExecCopyBundleResource(self, source, dest, convert_to_binary):
  50 + """Copies a resource file to the bundle/Resources directory, performing any
  51 + necessary compilation on each resource."""
  52 + extension = os.path.splitext(source)[1].lower()
  53 + if os.path.isdir(source):
  54 + # Copy tree.
  55 + # TODO(thakis): This copies file attributes like mtime, while the
  56 + # single-file branch below doesn't. This should probably be changed to
  57 + # be consistent with the single-file branch.
  58 + if os.path.exists(dest):
  59 + shutil.rmtree(dest)
  60 + shutil.copytree(source, dest)
  61 + elif extension == '.xib':
  62 + return self._CopyXIBFile(source, dest)
  63 + elif extension == '.storyboard':
  64 + return self._CopyXIBFile(source, dest)
  65 + elif extension == '.strings':
  66 + self._CopyStringsFile(source, dest, convert_to_binary)
  67 + else:
  68 + shutil.copy(source, dest)
  69 +
  70 + def _CopyXIBFile(self, source, dest):
  71 + """Compiles a XIB file with ibtool into a binary plist in the bundle."""
  72 +
  73 + # ibtool sometimes crashes with relative paths. See crbug.com/314728.
  74 + base = os.path.dirname(os.path.realpath(__file__))
  75 + if os.path.relpath(source):
  76 + source = os.path.join(base, source)
  77 + if os.path.relpath(dest):
  78 + dest = os.path.join(base, dest)
  79 +
  80 + args = ['xcrun', 'ibtool', '--errors', '--warnings', '--notices',
  81 + '--output-format', 'human-readable-text', '--compile', dest, source]
  82 + ibtool_section_re = re.compile(r'/\*.*\*/')
  83 + ibtool_re = re.compile(r'.*note:.*is clipping its content')
  84 + ibtoolout = subprocess.Popen(args, stdout=subprocess.PIPE)
  85 + current_section_header = None
  86 + for line in ibtoolout.stdout:
  87 + if ibtool_section_re.match(line):
  88 + current_section_header = line
  89 + elif not ibtool_re.match(line):
  90 + if current_section_header:
  91 + sys.stdout.write(current_section_header)
  92 + current_section_header = None
  93 + sys.stdout.write(line)
  94 + return ibtoolout.returncode
  95 +
  96 + def _ConvertToBinary(self, dest):
  97 + subprocess.check_call([
  98 + 'xcrun', 'plutil', '-convert', 'binary1', '-o', dest, dest])
  99 +
  100 + def _CopyStringsFile(self, source, dest, convert_to_binary):
  101 + """Copies a .strings file using iconv to reconvert the input into UTF-16."""
  102 + input_code = self._DetectInputEncoding(source) or "UTF-8"
  103 +
  104 + # Xcode's CpyCopyStringsFile / builtin-copyStrings seems to call
  105 + # CFPropertyListCreateFromXMLData() behind the scenes; at least it prints
  106 + # CFPropertyListCreateFromXMLData(): Old-style plist parser: missing
  107 + # semicolon in dictionary.
  108 + # on invalid files. Do the same kind of validation.
  109 + import CoreFoundation
  110 + s = open(source, 'rb').read()
  111 + d = CoreFoundation.CFDataCreate(None, s, len(s))
  112 + _, error = CoreFoundation.CFPropertyListCreateFromXMLData(None, d, 0, None)
  113 + if error:
  114 + return
  115 +
  116 + fp = open(dest, 'wb')
  117 + fp.write(s.decode(input_code).encode('UTF-16'))
  118 + fp.close()
  119 +
  120 + if convert_to_binary == 'True':
  121 + self._ConvertToBinary(dest)
  122 +
  123 + def _DetectInputEncoding(self, file_name):
  124 + """Reads the first few bytes from file_name and tries to guess the text
  125 + encoding. Returns None as a guess if it can't detect it."""
  126 + fp = open(file_name, 'rb')
  127 + try:
  128 + header = fp.read(3)
  129 + except e:
  130 + fp.close()
  131 + return None
  132 + fp.close()
  133 + if header.startswith("\xFE\xFF"):
  134 + return "UTF-16"
  135 + elif header.startswith("\xFF\xFE"):
  136 + return "UTF-16"
  137 + elif header.startswith("\xEF\xBB\xBF"):
  138 + return "UTF-8"
  139 + else:
  140 + return None
  141 +
  142 + def ExecCopyInfoPlist(self, source, dest, convert_to_binary, *keys):
  143 + """Copies the |source| Info.plist to the destination directory |dest|."""
  144 + # Read the source Info.plist into memory.
  145 + fd = open(source, 'r')
  146 + lines = fd.read()
  147 + fd.close()
  148 +
  149 + # Insert synthesized key/value pairs (e.g. BuildMachineOSBuild).
  150 + plist = plistlib.readPlistFromString(lines)
  151 + if keys:
  152 + plist = dict(plist.items() + json.loads(keys[0]).items())
  153 + lines = plistlib.writePlistToString(plist)
  154 +
  155 + # Go through all the environment variables and replace them as variables in
  156 + # the file.
  157 + IDENT_RE = re.compile(r'[/\s]')
  158 + for key in os.environ:
  159 + if key.startswith('_'):
  160 + continue
  161 + evar = '${%s}' % key
  162 + evalue = os.environ[key]
  163 + lines = string.replace(lines, evar, evalue)
  164 +
  165 + # Xcode supports various suffices on environment variables, which are
  166 + # all undocumented. :rfc1034identifier is used in the standard project
  167 + # template these days, and :identifier was used earlier. They are used to
  168 + # convert non-url characters into things that look like valid urls --
  169 + # except that the replacement character for :identifier, '_' isn't valid
  170 + # in a URL either -- oops, hence :rfc1034identifier was born.
  171 + evar = '${%s:identifier}' % key
  172 + evalue = IDENT_RE.sub('_', os.environ[key])
  173 + lines = string.replace(lines, evar, evalue)
  174 +
  175 + evar = '${%s:rfc1034identifier}' % key
  176 + evalue = IDENT_RE.sub('-', os.environ[key])
  177 + lines = string.replace(lines, evar, evalue)
  178 +
  179 + # Remove any keys with values that haven't been replaced.
  180 + lines = lines.split('\n')
  181 + for i in range(len(lines)):
  182 + if lines[i].strip().startswith("<string>${"):
  183 + lines[i] = None
  184 + lines[i - 1] = None
  185 + lines = '\n'.join(filter(lambda x: x is not None, lines))
  186 +
  187 + # Write out the file with variables replaced.
  188 + fd = open(dest, 'w')
  189 + fd.write(lines)
  190 + fd.close()
  191 +
  192 + # Now write out PkgInfo file now that the Info.plist file has been
  193 + # "compiled".
  194 + self._WritePkgInfo(dest)
  195 +
  196 + if convert_to_binary == 'True':
  197 + self._ConvertToBinary(dest)
  198 +
  199 + def _WritePkgInfo(self, info_plist):
  200 + """This writes the PkgInfo file from the data stored in Info.plist."""
  201 + plist = plistlib.readPlist(info_plist)
  202 + if not plist:
  203 + return
  204 +
  205 + # Only create PkgInfo for executable types.
  206 + package_type = plist['CFBundlePackageType']
  207 + if package_type != 'APPL':
  208 + return
  209 +
  210 + # The format of PkgInfo is eight characters, representing the bundle type
  211 + # and bundle signature, each four characters. If that is missing, four
  212 + # '?' characters are used instead.
  213 + signature_code = plist.get('CFBundleSignature', '????')
  214 + if len(signature_code) != 4: # Wrong length resets everything, too.
  215 + signature_code = '?' * 4
  216 +
  217 + dest = os.path.join(os.path.dirname(info_plist), 'PkgInfo')
  218 + fp = open(dest, 'w')
  219 + fp.write('%s%s' % (package_type, signature_code))
  220 + fp.close()
  221 +
  222 + def ExecFlock(self, lockfile, *cmd_list):
  223 + """Emulates the most basic behavior of Linux's flock(1)."""
  224 + # Rely on exception handling to report errors.
  225 + fd = os.open(lockfile, os.O_RDONLY|os.O_NOCTTY|os.O_CREAT, 0o666)
  226 + fcntl.flock(fd, fcntl.LOCK_EX)
  227 + return subprocess.call(cmd_list)
  228 +
  229 + def ExecFilterLibtool(self, *cmd_list):
  230 + """Calls libtool and filters out '/path/to/libtool: file: foo.o has no
  231 + symbols'."""
  232 + libtool_re = re.compile(r'^.*libtool: file: .* has no symbols$')
  233 + libtool_re5 = re.compile(
  234 + r'^.*libtool: warning for library: ' +
  235 + r'.* the table of contents is empty ' +
  236 + r'\(no object file members in the library define global symbols\)$')
  237 + env = os.environ.copy()
  238 + # Ref:
  239 + # http://www.opensource.apple.com/source/cctools/cctools-809/misc/libtool.c
  240 + # The problem with this flag is that it resets the file mtime on the file to
  241 + # epoch=0, e.g. 1970-1-1 or 1969-12-31 depending on timezone.
  242 + env['ZERO_AR_DATE'] = '1'
  243 + libtoolout = subprocess.Popen(cmd_list, stderr=subprocess.PIPE, env=env)
  244 + _, err = libtoolout.communicate()
  245 + for line in err.splitlines():
  246 + if not libtool_re.match(line) and not libtool_re5.match(line):
  247 + print >>sys.stderr, line
  248 + # Unconditionally touch the output .a file on the command line if present
  249 + # and the command succeeded. A bit hacky.
  250 + if not libtoolout.returncode:
  251 + for i in range(len(cmd_list) - 1):
  252 + if cmd_list[i] == "-o" and cmd_list[i+1].endswith('.a'):
  253 + os.utime(cmd_list[i+1], None)
  254 + break
  255 + return libtoolout.returncode
  256 +
  257 + def ExecPackageFramework(self, framework, version):
  258 + """Takes a path to Something.framework and the Current version of that and
  259 + sets up all the symlinks."""
  260 + # Find the name of the binary based on the part before the ".framework".
  261 + binary = os.path.basename(framework).split('.')[0]
  262 +
  263 + CURRENT = 'Current'
  264 + RESOURCES = 'Resources'
  265 + VERSIONS = 'Versions'
  266 +
  267 + if not os.path.exists(os.path.join(framework, VERSIONS, version, binary)):
  268 + # Binary-less frameworks don't seem to contain symlinks (see e.g.
  269 + # chromium's out/Debug/org.chromium.Chromium.manifest/ bundle).
  270 + return
  271 +
  272 + # Move into the framework directory to set the symlinks correctly.
  273 + pwd = os.getcwd()
  274 + os.chdir(framework)
  275 +
  276 + # Set up the Current version.
  277 + self._Relink(version, os.path.join(VERSIONS, CURRENT))
  278 +
  279 + # Set up the root symlinks.
  280 + self._Relink(os.path.join(VERSIONS, CURRENT, binary), binary)
  281 + self._Relink(os.path.join(VERSIONS, CURRENT, RESOURCES), RESOURCES)
  282 +
  283 + # Back to where we were before!
  284 + os.chdir(pwd)
  285 +
  286 + def _Relink(self, dest, link):
  287 + """Creates a symlink to |dest| named |link|. If |link| already exists,
  288 + it is overwritten."""
  289 + if os.path.lexists(link):
  290 + os.remove(link)
  291 + os.symlink(dest, link)
  292 +
  293 + def ExecCompileXcassets(self, keys, *inputs):
  294 + """Compiles multiple .xcassets files into a single .car file.
  295 +
  296 + This invokes 'actool' to compile all the inputs .xcassets files. The
  297 + |keys| arguments is a json-encoded dictionary of extra arguments to
  298 + pass to 'actool' when the asset catalogs contains an application icon
  299 + or a launch image.
  300 +
  301 + Note that 'actool' does not create the Assets.car file if the asset
  302 + catalogs does not contains imageset.
  303 + """
  304 + command_line = [
  305 + 'xcrun', 'actool', '--output-format', 'human-readable-text',
  306 + '--compress-pngs', '--notices', '--warnings', '--errors',
  307 + ]
  308 + is_iphone_target = 'IPHONEOS_DEPLOYMENT_TARGET' in os.environ
  309 + if is_iphone_target:
  310 + platform = os.environ['CONFIGURATION'].split('-')[-1]
  311 + if platform not in ('iphoneos', 'iphonesimulator'):
  312 + platform = 'iphonesimulator'
  313 + command_line.extend([
  314 + '--platform', platform, '--target-device', 'iphone',
  315 + '--target-device', 'ipad', '--minimum-deployment-target',
  316 + os.environ['IPHONEOS_DEPLOYMENT_TARGET'], '--compile',
  317 + os.path.abspath(os.environ['CONTENTS_FOLDER_PATH']),
  318 + ])
  319 + else:
  320 + command_line.extend([
  321 + '--platform', 'macosx', '--target-device', 'mac',
  322 + '--minimum-deployment-target', os.environ['MACOSX_DEPLOYMENT_TARGET'],
  323 + '--compile',
  324 + os.path.abspath(os.environ['UNLOCALIZED_RESOURCES_FOLDER_PATH']),
  325 + ])
  326 + if keys:
  327 + keys = json.loads(keys)
  328 + for key, value in keys.iteritems():
  329 + arg_name = '--' + key
  330 + if isinstance(value, bool):
  331 + if value:
  332 + command_line.append(arg_name)
  333 + elif isinstance(value, list):
  334 + for v in value:
  335 + command_line.append(arg_name)
  336 + command_line.append(str(v))
  337 + else:
  338 + command_line.append(arg_name)
  339 + command_line.append(str(value))
  340 + # Note: actool crashes if inputs path are relative, so use os.path.abspath
  341 + # to get absolute path name for inputs.
  342 + command_line.extend(map(os.path.abspath, inputs))
  343 + subprocess.check_call(command_line)
  344 +
  345 + def ExecMergeInfoPlist(self, output, *inputs):
  346 + """Merge multiple .plist files into a single .plist file."""
  347 + merged_plist = {}
  348 + for path in inputs:
  349 + plist = self._LoadPlistMaybeBinary(path)
  350 + self._MergePlist(merged_plist, plist)
  351 + plistlib.writePlist(merged_plist, output)
  352 +
  353 + def ExecCodeSignBundle(self, key, resource_rules, entitlements, provisioning):
  354 + """Code sign a bundle.
  355 +
  356 + This function tries to code sign an iOS bundle, following the same
  357 + algorithm as Xcode:
  358 + 1. copy ResourceRules.plist from the user or the SDK into the bundle,
  359 + 2. pick the provisioning profile that best match the bundle identifier,
  360 + and copy it into the bundle as embedded.mobileprovision,
  361 + 3. copy Entitlements.plist from user or SDK next to the bundle,
  362 + 4. code sign the bundle.
  363 + """
  364 + resource_rules_path = self._InstallResourceRules(resource_rules)
  365 + substitutions, overrides = self._InstallProvisioningProfile(
  366 + provisioning, self._GetCFBundleIdentifier())
  367 + entitlements_path = self._InstallEntitlements(
  368 + entitlements, substitutions, overrides)
  369 + subprocess.check_call([
  370 + 'codesign', '--force', '--sign', key, '--resource-rules',
  371 + resource_rules_path, '--entitlements', entitlements_path,
  372 + os.path.join(
  373 + os.environ['TARGET_BUILD_DIR'],
  374 + os.environ['FULL_PRODUCT_NAME'])])
  375 +
  376 + def _InstallResourceRules(self, resource_rules):
  377 + """Installs ResourceRules.plist from user or SDK into the bundle.
  378 +
  379 + Args:
  380 + resource_rules: string, optional, path to the ResourceRules.plist file
  381 + to use, default to "${SDKROOT}/ResourceRules.plist"
  382 +
  383 + Returns:
  384 + Path to the copy of ResourceRules.plist into the bundle.
  385 + """
  386 + source_path = resource_rules
  387 + target_path = os.path.join(
  388 + os.environ['BUILT_PRODUCTS_DIR'],
  389 + os.environ['CONTENTS_FOLDER_PATH'],
  390 + 'ResourceRules.plist')
  391 + if not source_path:
  392 + source_path = os.path.join(
  393 + os.environ['SDKROOT'], 'ResourceRules.plist')
  394 + shutil.copy2(source_path, target_path)
  395 + return target_path
  396 +
  397 + def _InstallProvisioningProfile(self, profile, bundle_identifier):
  398 + """Installs embedded.mobileprovision into the bundle.
  399 +
  400 + Args:
  401 + profile: string, optional, short name of the .mobileprovision file
  402 + to use, if empty or the file is missing, the best file installed
  403 + will be used
  404 + bundle_identifier: string, value of CFBundleIdentifier from Info.plist
  405 +
  406 + Returns:
  407 + A tuple containing two dictionary: variables substitutions and values
  408 + to overrides when generating the entitlements file.
  409 + """
  410 + source_path, provisioning_data, team_id = self._FindProvisioningProfile(
  411 + profile, bundle_identifier)
  412 + target_path = os.path.join(
  413 + os.environ['BUILT_PRODUCTS_DIR'],
  414 + os.environ['CONTENTS_FOLDER_PATH'],
  415 + 'embedded.mobileprovision')
  416 + shutil.copy2(source_path, target_path)
  417 + substitutions = self._GetSubstitutions(bundle_identifier, team_id + '.')
  418 + return substitutions, provisioning_data['Entitlements']
  419 +
  420 + def _FindProvisioningProfile(self, profile, bundle_identifier):
  421 + """Finds the .mobileprovision file to use for signing the bundle.
  422 +
  423 + Checks all the installed provisioning profiles (or if the user specified
  424 + the PROVISIONING_PROFILE variable, only consult it) and select the most
  425 + specific that correspond to the bundle identifier.
  426 +
  427 + Args:
  428 + profile: string, optional, short name of the .mobileprovision file
  429 + to use, if empty or the file is missing, the best file installed
  430 + will be used
  431 + bundle_identifier: string, value of CFBundleIdentifier from Info.plist
  432 +
  433 + Returns:
  434 + A tuple of the path to the selected provisioning profile, the data of
  435 + the embedded plist in the provisioning profile and the team identifier
  436 + to use for code signing.
  437 +
  438 + Raises:
  439 + SystemExit: if no .mobileprovision can be used to sign the bundle.
  440 + """
  441 + profiles_dir = os.path.join(
  442 + os.environ['HOME'], 'Library', 'MobileDevice', 'Provisioning Profiles')
  443 + if not os.path.isdir(profiles_dir):
  444 + print >>sys.stderr, (
  445 + 'cannot find mobile provisioning for %s' % bundle_identifier)
  446 + sys.exit(1)
  447 + provisioning_profiles = None
  448 + if profile:
  449 + profile_path = os.path.join(profiles_dir, profile + '.mobileprovision')
  450 + if os.path.exists(profile_path):
  451 + provisioning_profiles = [profile_path]
  452 + if not provisioning_profiles:
  453 + provisioning_profiles = glob.glob(
  454 + os.path.join(profiles_dir, '*.mobileprovision'))
  455 + valid_provisioning_profiles = {}
  456 + for profile_path in provisioning_profiles:
  457 + profile_data = self._LoadProvisioningProfile(profile_path)
  458 + app_id_pattern = profile_data.get(
  459 + 'Entitlements', {}).get('application-identifier', '')
  460 + for team_identifier in profile_data.get('TeamIdentifier', []):
  461 + app_id = '%s.%s' % (team_identifier, bundle_identifier)
  462 + if fnmatch.fnmatch(app_id, app_id_pattern):
  463 + valid_provisioning_profiles[app_id_pattern] = (
  464 + profile_path, profile_data, team_identifier)
  465 + if not valid_provisioning_profiles:
  466 + print >>sys.stderr, (
  467 + 'cannot find mobile provisioning for %s' % bundle_identifier)
  468 + sys.exit(1)
  469 + # If the user has multiple provisioning profiles installed that can be
  470 + # used for ${bundle_identifier}, pick the most specific one (ie. the
  471 + # provisioning profile whose pattern is the longest).
  472 + selected_key = max(valid_provisioning_profiles, key=lambda v: len(v))
  473 + return valid_provisioning_profiles[selected_key]
  474 +
  475 + def _LoadProvisioningProfile(self, profile_path):
  476 + """Extracts the plist embedded in a provisioning profile.
  477 +
  478 + Args:
  479 + profile_path: string, path to the .mobileprovision file
  480 +
  481 + Returns:
  482 + Content of the plist embedded in the provisioning profile as a dictionary.
  483 + """
  484 + with tempfile.NamedTemporaryFile() as temp:
  485 + subprocess.check_call([
  486 + 'security', 'cms', '-D', '-i', profile_path, '-o', temp.name])
  487 + return self._LoadPlistMaybeBinary(temp.name)
  488 +
  489 + def _MergePlist(self, merged_plist, plist):
  490 + """Merge |plist| into |merged_plist|."""
  491 + for key, value in plist.iteritems():
  492 + if isinstance(value, dict):
  493 + merged_value = merged_plist.get(key, {})
  494 + if isinstance(merged_value, dict):
  495 + self._MergePlist(merged_value, value)
  496 + merged_plist[key] = merged_value
  497 + else:
  498 + merged_plist[key] = value
  499 + else:
  500 + merged_plist[key] = value
  501 +
  502 + def _LoadPlistMaybeBinary(self, plist_path):
  503 + """Loads into a memory a plist possibly encoded in binary format.
  504 +
  505 + This is a wrapper around plistlib.readPlist that tries to convert the
  506 + plist to the XML format if it can't be parsed (assuming that it is in
  507 + the binary format).
  508 +
  509 + Args:
  510 + plist_path: string, path to a plist file, in XML or binary format
  511 +
  512 + Returns:
  513 + Content of the plist as a dictionary.
  514 + """
  515 + try:
  516 + # First, try to read the file using plistlib that only supports XML,
  517 + # and if an exception is raised, convert a temporary copy to XML and
  518 + # load that copy.
  519 + return plistlib.readPlist(plist_path)
  520 + except:
  521 + pass
  522 + with tempfile.NamedTemporaryFile() as temp:
  523 + shutil.copy2(plist_path, temp.name)
  524 + subprocess.check_call(['plutil', '-convert', 'xml1', temp.name])
  525 + return plistlib.readPlist(temp.name)
  526 +
  527 + def _GetSubstitutions(self, bundle_identifier, app_identifier_prefix):
  528 + """Constructs a dictionary of variable substitutions for Entitlements.plist.
  529 +
  530 + Args:
  531 + bundle_identifier: string, value of CFBundleIdentifier from Info.plist
  532 + app_identifier_prefix: string, value for AppIdentifierPrefix
  533 +
  534 + Returns:
  535 + Dictionary of substitutions to apply when generating Entitlements.plist.
  536 + """
  537 + return {
  538 + 'CFBundleIdentifier': bundle_identifier,
  539 + 'AppIdentifierPrefix': app_identifier_prefix,
  540 + }
  541 +
  542 + def _GetCFBundleIdentifier(self):
  543 + """Extracts CFBundleIdentifier value from Info.plist in the bundle.
  544 +
  545 + Returns:
  546 + Value of CFBundleIdentifier in the Info.plist located in the bundle.
  547 + """
  548 + info_plist_path = os.path.join(
  549 + os.environ['TARGET_BUILD_DIR'],
  550 + os.environ['INFOPLIST_PATH'])
  551 + info_plist_data = self._LoadPlistMaybeBinary(info_plist_path)
  552 + return info_plist_data['CFBundleIdentifier']
  553 +
  554 + def _InstallEntitlements(self, entitlements, substitutions, overrides):
  555 + """Generates and install the ${BundleName}.xcent entitlements file.
  556 +
  557 + Expands variables "$(variable)" pattern in the source entitlements file,
  558 + add extra entitlements defined in the .mobileprovision file and the copy
  559 + the generated plist to "${BundlePath}.xcent".
  560 +
  561 + Args:
  562 + entitlements: string, optional, path to the Entitlements.plist template
  563 + to use, defaults to "${SDKROOT}/Entitlements.plist"
  564 + substitutions: dictionary, variable substitutions
  565 + overrides: dictionary, values to add to the entitlements
  566 +
  567 + Returns:
  568 + Path to the generated entitlements file.
  569 + """
  570 + source_path = entitlements
  571 + target_path = os.path.join(
  572 + os.environ['BUILT_PRODUCTS_DIR'],
  573 + os.environ['PRODUCT_NAME'] + '.xcent')
  574 + if not source_path:
  575 + source_path = os.path.join(
  576 + os.environ['SDKROOT'],
  577 + 'Entitlements.plist')
  578 + shutil.copy2(source_path, target_path)
  579 + data = self._LoadPlistMaybeBinary(target_path)
  580 + data = self._ExpandVariables(data, substitutions)
  581 + if overrides:
  582 + for key in overrides:
  583 + if key not in data:
  584 + data[key] = overrides[key]
  585 + plistlib.writePlist(data, target_path)
  586 + return target_path
  587 +
  588 + def _ExpandVariables(self, data, substitutions):
  589 + """Expands variables "$(variable)" in data.
  590 +
  591 + Args:
  592 + data: object, can be either string, list or dictionary
  593 + substitutions: dictionary, variable substitutions to perform
  594 +
  595 + Returns:
  596 + Copy of data where each references to "$(variable)" has been replaced
  597 + by the corresponding value found in substitutions, or left intact if
  598 + the key was not found.
  599 + """
  600 + if isinstance(data, str):
  601 + for key, value in substitutions.iteritems():
  602 + data = data.replace('$(%s)' % key, value)
  603 + return data
  604 + if isinstance(data, list):
  605 + return [self._ExpandVariables(v, substitutions) for v in data]
  606 + if isinstance(data, dict):
  607 + return {k: self._ExpandVariables(data[k], substitutions) for k in data}
  608 + return data
  609 +
  610 +if __name__ == '__main__':
  611 + sys.exit(main(sys.argv[1:]))
  1 +if (process.fiberLib) {
  2 + return module.exports = process.fiberLib;
  3 +}
  4 +var fs = require('fs'), path = require('path');
  5 +
  6 +// Seed random numbers [gh-82]
  7 +Math.random();
  8 +
  9 +// Look for binary for this platform
  10 +var modPath = path.join(__dirname, 'bin', process.platform+ '-'+ process.arch+ '-'+ process.versions.modules, 'fibers');
  11 +try {
  12 + fs.statSync(modPath+ '.node');
  13 +} catch (ex) {
  14 + // No binary!
  15 + console.error(
  16 + '## There is an issue with `node-fibers` ##\n'+
  17 + '`'+ modPath+ '.node` is missing.\n\n'+
  18 + 'Try running this to fix the issue: '+ process.execPath+ ' '+ __dirname.replace(' ', '\\ ')+ '/build'
  19 + );
  20 + throw new Error('Missing binary. See message above.');
  21 +}
  22 +
  23 +// Pull in fibers implementation
  24 +process.fiberLib = module.exports = require(modPath).Fiber;
  1 +"use strict";
  2 +var Fiber = require('./fibers');
  3 +var util = require('util');
  4 +module.exports = Future;
  5 +Function.prototype.future = function(detach) {
  6 + var fn = this;
  7 + var ret = function() {
  8 + var future = new FiberFuture(fn, this, arguments);
  9 + if (detach) {
  10 + future.detach();
  11 + }
  12 + return future;
  13 + };
  14 + ret.toString = function() {
  15 + return '<<Future '+ fn+ '.future()>>';
  16 + };
  17 + return ret;
  18 +};
  19 +
  20 +function Future() {}
  21 +
  22 +/**
  23 + * Run a function(s) in a future context, and return a future to their return value. This is useful
  24 + * for instances where you want a closure to be able to `.wait()`. This also lets you wait for
  25 + * mulitple parallel opertions to run.
  26 + */
  27 +Future.task = function(fn) {
  28 + if (arguments.length === 1) {
  29 + return fn.future()();
  30 + } else {
  31 + var future = new Future, pending = arguments.length, error, values = new Array(arguments.length);
  32 + for (var ii = 0; ii < arguments.length; ++ii) {
  33 + arguments[ii].future()().resolve(function(ii, err, val) {
  34 + if (err) {
  35 + error = err;
  36 + }
  37 + values[ii] = val;
  38 + if (--pending === 0) {
  39 + if (error) {
  40 + future.throw(error);
  41 + } else {
  42 + future.return(values);
  43 + }
  44 + }
  45 + }.bind(null, ii));
  46 + }
  47 + return future;
  48 + }
  49 +};
  50 +
  51 +/**
  52 + * Wrap node-style async functions to instead return futures. This assumes that the last parameter
  53 + * of the function is a callback.
  54 + *
  55 + * If a single function is passed a future-returning function is created. If an object is passed a
  56 + * new object is returned with all functions wrapped.
  57 + *
  58 + * The value that is returned from the invocation of the underlying function is assigned to the
  59 + * property `_` on the future. This is useful for functions like `execFile` which take a callback,
  60 + * but also return meaningful information.
  61 + *
  62 + * `multi` indicates that this callback will return more than 1 argument after `err`. For example,
  63 + * `child_process.exec()`
  64 + *
  65 + * `suffix` will append a string to every method that was overridden, if you pass an object to
  66 + * `Future.wrap()`. Default is 'Future'.
  67 + *
  68 + * var readFileFuture = Future.wrap(require('fs').readFile);
  69 + * var fs = Future.wrap(require('fs'));
  70 + * fs.readFileFuture('example.txt').wait();
  71 + */
  72 +Future.wrap = function(fnOrObject, multi, suffix, stop) {
  73 + if (typeof fnOrObject === 'object') {
  74 + var wrapped = Object.create(fnOrObject);
  75 + for (var ii in fnOrObject) {
  76 + if (wrapped[ii] instanceof Function) {
  77 + wrapped[suffix === undefined ? ii+ 'Future' : ii+ suffix] = Future.wrap(wrapped[ii], multi, suffix, stop);
  78 + }
  79 + }
  80 + return wrapped;
  81 + } else if (typeof fnOrObject === 'function') {
  82 + var fn = function() {
  83 + var future = new Future;
  84 + var args = Array.prototype.slice.call(arguments);
  85 + if (multi) {
  86 + var cb = future.resolver();
  87 + args.push(function(err) {
  88 + cb(err, Array.prototype.slice.call(arguments, 1));
  89 + });
  90 + } else {
  91 + args.push(future.resolver());
  92 + }
  93 + future._ = fnOrObject.apply(this, args);
  94 + return future;
  95 + }
  96 + // Modules like `request` return a function that has more functions as properties. Handle this
  97 + // in some kind of reasonable way.
  98 + if (!stop) {
  99 + var proto = Object.create(fnOrObject);
  100 + for (var ii in fnOrObject) {
  101 + if (fnOrObject.hasOwnProperty(ii) && fnOrObject[ii] instanceof Function) {
  102 + proto[ii] = proto[ii];
  103 + }
  104 + }
  105 + fn.__proto__ = Future.wrap(proto, multi, suffix, true);
  106 + }
  107 + return fn;
  108 + }
  109 +};
  110 +
  111 +/**
  112 + * Wait on a series of futures and then return. If the futures throw an exception this function
  113 + * /won't/ throw it back. You can get the value of the future by calling get() on it directly. If
  114 + * you want to wait on a single future you're better off calling future.wait() on the instance.
  115 + */
  116 +Future.wait = function wait(/* ... */) {
  117 +
  118 + // Normalize arguments + pull out a FiberFuture for reuse if possible
  119 + var futures = [], singleFiberFuture;
  120 + for (var ii = 0; ii < arguments.length; ++ii) {
  121 + var arg = arguments[ii];
  122 + if (arg instanceof Future) {
  123 + // Ignore already resolved fibers
  124 + if (arg.isResolved()) {
  125 + continue;
  126 + }
  127 + // Look for fiber reuse
  128 + if (!singleFiberFuture && arg instanceof FiberFuture && !arg.started) {
  129 + singleFiberFuture = arg;
  130 + continue;
  131 + }
  132 + futures.push(arg);
  133 + } else if (arg instanceof Array) {
  134 + for (var jj = 0; jj < arg.length; ++jj) {
  135 + var aarg = arg[jj];
  136 + if (aarg instanceof Future) {
  137 + // Ignore already resolved fibers
  138 + if (aarg.isResolved()) {
  139 + continue;
  140 + }
  141 + // Look for fiber reuse
  142 + if (!singleFiberFuture && aarg instanceof FiberFuture && !aarg.started) {
  143 + singleFiberFuture = aarg;
  144 + continue;
  145 + }
  146 + futures.push(aarg);
  147 + } else {
  148 + throw new Error(aarg+ ' is not a future');
  149 + }
  150 + }
  151 + } else {
  152 + throw new Error(arg+ ' is not a future');
  153 + }
  154 + }
  155 +
  156 + // Resumes current fiber
  157 + var fiber = Fiber.current;
  158 + if (!fiber) {
  159 + throw new Error('Can\'t wait without a fiber');
  160 + }
  161 +
  162 + // Resolve all futures
  163 + var pending = futures.length + (singleFiberFuture ? 1 : 0);
  164 + function cb() {
  165 + if (!--pending) {
  166 + fiber.run();
  167 + }
  168 + }
  169 + for (var ii = 0; ii < futures.length; ++ii) {
  170 + futures[ii].resolve(cb);
  171 + }
  172 +
  173 + // Reusing a fiber?
  174 + if (singleFiberFuture) {
  175 + singleFiberFuture.started = true;
  176 + try {
  177 + singleFiberFuture.return(
  178 + singleFiberFuture.fn.apply(singleFiberFuture.context, singleFiberFuture.args));
  179 + } catch(e) {
  180 + singleFiberFuture.throw(e);
  181 + }
  182 + --pending;
  183 + }
  184 +
  185 + // Yield this fiber
  186 + if (pending) {
  187 + Fiber.yield();
  188 + }
  189 +};
  190 +
  191 +/**
  192 + * Return a Future that waits on an ES6 Promise.
  193 + */
  194 +Future.fromPromise = function(promise) {
  195 + var future = new Future;
  196 + promise.then(function(val) {
  197 + future.return(val);
  198 + }, function(err) {
  199 + future.throw(err);
  200 + });
  201 + return future;
  202 +};
  203 +
  204 +Future.prototype = {
  205 + /**
  206 + * Return the value of this future. If the future hasn't resolved yet this will throw an error.
  207 + */
  208 + get: function() {
  209 + if (!this.resolved) {
  210 + throw new Error('Future must resolve before value is ready');
  211 + } else if (this.error) {
  212 + // Link the stack traces up
  213 + var error = this.error;
  214 + var localStack = {};
  215 + Error.captureStackTrace(localStack, Future.prototype.get);
  216 + var futureStack = Object.getOwnPropertyDescriptor(error, 'futureStack');
  217 + if (!futureStack) {
  218 + futureStack = Object.getOwnPropertyDescriptor(error, 'stack');
  219 + if (futureStack) {
  220 + Object.defineProperty(error, 'futureStack', futureStack);
  221 + }
  222 + }
  223 + if (futureStack && futureStack.get) {
  224 + Object.defineProperty(error, 'stack', {
  225 + get: function() {
  226 + var stack = futureStack.get.apply(error);
  227 + if (stack) {
  228 + stack = stack.split('\n');
  229 + return [stack[0]]
  230 + .concat(localStack.stack.split('\n').slice(1))
  231 + .concat(' - - - - -')
  232 + .concat(stack.slice(1))
  233 + .join('\n');
  234 + } else {
  235 + return localStack.stack;
  236 + }
  237 + },
  238 + set: function(stack) {
  239 + Object.defineProperty(error, 'stack', {
  240 + value: stack,
  241 + configurable: true,
  242 + enumerable: false,
  243 + writable: true,
  244 + });
  245 + },
  246 + configurable: true,
  247 + enumerable: false,
  248 + });
  249 + }
  250 + throw error;
  251 + } else {
  252 + return this.value;
  253 + }
  254 + },
  255 +
  256 + /**
  257 + * Mark this future as returned. All pending callbacks will be invoked immediately.
  258 + */
  259 + "return": function(value) {
  260 + if (this.resolved) {
  261 + throw new Error('Future resolved more than once');
  262 + }
  263 + this.value = value;
  264 + this.resolved = true;
  265 +
  266 + var callbacks = this.callbacks;
  267 + if (callbacks) {
  268 + delete this.callbacks;
  269 + for (var ii = 0; ii < callbacks.length; ++ii) {
  270 + try {
  271 + var ref = callbacks[ii];
  272 + if (ref[1]) {
  273 + ref[1](value);
  274 + } else {
  275 + ref[0](undefined, value);
  276 + }
  277 + } catch(ex) {
  278 + // console.log('Resolve cb threw', String(ex.stack || ex.message || ex));
  279 + process.nextTick(function() {
  280 + throw(ex);
  281 + });
  282 + }
  283 + }
  284 + }
  285 + },
  286 +
  287 + /**
  288 + * Throw from this future as returned. All pending callbacks will be invoked immediately.
  289 + */
  290 + "throw": function(error) {
  291 + if (this.resolved) {
  292 + throw new Error('Future resolved more than once');
  293 + } else if (!error) {
  294 + throw new Error('Must throw non-empty error');
  295 + }
  296 + this.error = error;
  297 + this.resolved = true;
  298 +
  299 + var callbacks = this.callbacks;
  300 + if (callbacks) {
  301 + delete this.callbacks;
  302 + for (var ii = 0; ii < callbacks.length; ++ii) {
  303 + try {
  304 + var ref = callbacks[ii];
  305 + if (ref[1]) {
  306 + ref[0].throw(error);
  307 + } else {
  308 + ref[0](error);
  309 + }
  310 + } catch(ex) {
  311 + // console.log('Resolve cb threw', String(ex.stack || ex.message || ex));
  312 + process.nextTick(function() {
  313 + throw(ex);
  314 + });
  315 + }
  316 + }
  317 + }
  318 + },
  319 +
  320 + /**
  321 + * "detach" this future. Basically this is useful if you want to run a task in a future, you
  322 + * aren't interested in its return value, but if it throws you don't want the exception to be
  323 + * lost. If this fiber throws, an exception will be thrown to the event loop and node will
  324 + * probably fall down.
  325 + */
  326 + detach: function() {
  327 + this.resolve(function(err) {
  328 + if (err) {
  329 + throw err;
  330 + }
  331 + });
  332 + },
  333 +
  334 + /**
  335 + * Returns whether or not this future has resolved yet.
  336 + */
  337 + isResolved: function() {
  338 + return this.resolved === true;
  339 + },
  340 +
  341 + /**
  342 + * Returns a node-style function which will mark this future as resolved when called.
  343 + */
  344 + resolver: function() {
  345 + return function(err, val) {
  346 + if (err) {
  347 + this.throw(err);
  348 + } else {
  349 + this.return(val);
  350 + }
  351 + }.bind(this);
  352 + },
  353 +
  354 + /**
  355 + * Waits for this future to resolve and then invokes a callback.
  356 + *
  357 + * If two arguments are passed, the first argument is a future which will be thrown to in the case
  358 + * of error, and the second is a function(val){} callback.
  359 + *
  360 + * If only one argument is passed it is a standard function(err, val){} callback.
  361 + */
  362 + resolve: function(arg1, arg2) {
  363 + if (this.resolved) {
  364 + if (arg2) {
  365 + if (this.error) {
  366 + arg1.throw(this.error);
  367 + } else {
  368 + arg2(this.value);
  369 + }
  370 + } else {
  371 + arg1(this.error, this.value);
  372 + }
  373 + } else {
  374 + (this.callbacks = this.callbacks || []).push([arg1, arg2]);
  375 + }
  376 + return this;
  377 + },
  378 +
  379 + /**
  380 + * Resolve only in the case of success
  381 + */
  382 + resolveSuccess: function(cb) {
  383 + this.resolve(function(err, val) {
  384 + if (err) {
  385 + return;
  386 + }
  387 + cb(val);
  388 + });
  389 + return this;
  390 + },
  391 +
  392 + /**
  393 + * Propogate results to another future.
  394 + */
  395 + proxy: function(future) {
  396 + this.resolve(function(err, val) {
  397 + if (err) {
  398 + future.throw(err);
  399 + } else {
  400 + future.return(val);
  401 + }
  402 + });
  403 + },
  404 +
  405 + /**
  406 + * Propogate only errors to an another future or array of futures.
  407 + */
  408 + proxyErrors: function(futures) {
  409 + this.resolve(function(err) {
  410 + if (!err) {
  411 + return;
  412 + }
  413 + if (futures instanceof Array) {
  414 + for (var ii = 0; ii < futures.length; ++ii) {
  415 + futures[ii].throw(err);
  416 + }
  417 + } else {
  418 + futures.throw(err);
  419 + }
  420 + });
  421 + return this;
  422 + },
  423 +
  424 + /**
  425 + * Returns an ES6 Promise
  426 + */
  427 + promise: function() {
  428 + var that = this;
  429 + return new Promise(function(resolve, reject) {
  430 + that.resolve(function(err, val) {
  431 + if (err) {
  432 + reject(err);
  433 + } else {
  434 + resolve(val);
  435 + }
  436 + });
  437 + });
  438 + },
  439 +
  440 + /**
  441 + * Differs from its functional counterpart in that it actually resolves the future. Thus if the
  442 + * future threw, future.wait() will throw.
  443 + */
  444 + wait: function() {
  445 + if (this.isResolved()) {
  446 + return this.get();
  447 + }
  448 + Future.wait(this);
  449 + return this.get();
  450 + },
  451 +};
  452 +
  453 +/**
  454 + * A function call which loads inside a fiber automatically and returns a future.
  455 + */
  456 +function FiberFuture(fn, context, args) {
  457 + this.fn = fn;
  458 + this.context = context;
  459 + this.args = args;
  460 + this.started = false;
  461 + var that = this;
  462 + process.nextTick(function() {
  463 + if (!that.started) {
  464 + that.started = true;
  465 + Fiber(function() {
  466 + try {
  467 + that.return(fn.apply(context, args));
  468 + } catch(e) {
  469 + that.throw(e);
  470 + }
  471 + }).run();
  472 + }
  473 + });
  474 +}
  475 +util.inherits(FiberFuture, Future);
  1 +{
  2 + "name": "fibers",
  3 + "version": "1.0.15",
  4 + "description": "Cooperative multi-tasking for Javascript",
  5 + "keywords": [
  6 + "fiber",
  7 + "fibers",
  8 + "coroutine",
  9 + "thread",
  10 + "async",
  11 + "parallel",
  12 + "worker",
  13 + "future",
  14 + "promise"
  15 + ],
  16 + "homepage": "https://github.com/laverdet/node-fibers",
  17 + "author": "Marcel Laverdet <marcel@laverdet.com> (https://github.com/laverdet/)",
  18 + "main": "fibers",
  19 + "scripts": {
  20 + "install": "node build.js || nodejs build.js",
  21 + "test": "node test.js || nodejs test.js"
  22 + },
  23 + "repository": {
  24 + "type": "git",
  25 + "url": "git://github.com/laverdet/node-fibers.git"
  26 + },
  27 + "license": "MIT",
  28 + "engines": {
  29 + "node": ">=0.5.2"
  30 + },
  31 + "_from": "fibers@1.0.15",
  32 + "_resolved": "http://registry.npm.taobao.org/fibers/download/fibers-1.0.15.tgz"
  33 +}
  1 +"use strict"
  2 +var Fiber = require('./fibers');
  3 +var fiber = Fiber(function() {
  4 + process.stdout.write(Fiber.yield());
  5 +});
  6 +fiber.run();
  7 +fiber.run('pass');
  1 +#include "coroutine.h"
  2 +#include "v8-version.h"
  3 +#include <assert.h>
  4 +#ifndef WINDOWS
  5 +#include <pthread.h>
  6 +#else
  7 +#include <windows.h>
  8 +#include <intrin.h>
  9 +// Stub pthreads into Windows approximations
  10 +#define pthread_t HANDLE
  11 +#define pthread_create(thread, attr, fn, arg) !((*thread)=CreateThread(NULL, 0, &(fn), arg, 0, NULL))
  12 +#define pthread_join(thread, arg) WaitForSingleObject((thread), INFINITE)
  13 +#define pthread_key_t DWORD
  14 +#define pthread_key_create(key, dtor) (*key)=TlsAlloc()
  15 +#define pthread_setspecific(key, val) TlsSetValue((key), (val))
  16 +#define pthread_getspecific(key) TlsGetValue((key))
  17 +#endif
  18 +
  19 +#include <stdexcept>
  20 +#include <stack>
  21 +#include <vector>
  22 +using namespace std;
  23 +
  24 +const size_t v8_tls_keys = 3;
  25 +static std::vector<void*> fls_data_pool;
  26 +static pthread_key_t coro_thread_key = 0;
  27 +static pthread_key_t isolate_key = 0x7777;
  28 +static pthread_key_t thread_id_key = 0x7777;
  29 +static pthread_key_t thread_data_key = 0x7777;
  30 +
  31 +static size_t stack_size = 0;
  32 +static size_t coroutines_created_ = 0;
  33 +static vector<Coroutine*> fiber_pool;
  34 +static Coroutine* delete_me = NULL;
  35 +size_t Coroutine::pool_size = 120;
  36 +
  37 +static bool can_poke(void* addr) {
  38 +#ifdef WINDOWS
  39 + MEMORY_BASIC_INFORMATION mbi;
  40 + if (!VirtualQueryEx(GetCurrentProcess(), addr, &mbi, sizeof(mbi))) {
  41 + return false;
  42 + }
  43 + if (!(mbi.State & MEM_COMMIT)) {
  44 + return false;
  45 + }
  46 + return true;
  47 +#else
  48 + // TODO: Check pointer on other OS's? Windows is the only case I've seen so far that has
  49 + // spooky gaps in the TLS key space
  50 + return true;
  51 +#endif
  52 +}
  53 +
  54 +#ifdef USE_V8_SYMBOLS
  55 +// Some distributions of node, most notably Ubuntu, strip the v8 internal symbols and so we don't
  56 +// have access to this stuff. In most cases we will use the more complicated `find_thread_id_key`
  57 +// below, since it tends to work on more platforms.
  58 +namespace v8 {
  59 + namespace base {
  60 + class Thread {
  61 + public: typedef int32_t LocalStorageKey;
  62 + };
  63 + }
  64 +
  65 + namespace internal {
  66 + class Isolate {
  67 + public:
  68 + static base::Thread::LocalStorageKey isolate_key_;
  69 + static base::Thread::LocalStorageKey per_isolate_thread_data_key_;
  70 + static base::Thread::LocalStorageKey thread_id_key_;
  71 + };
  72 + }
  73 +}
  74 +#endif
  75 +
  76 +#ifndef WINDOWS
  77 +static void* find_thread_id_key(void* arg)
  78 +#else
  79 +static DWORD __stdcall find_thread_id_key(LPVOID arg)
  80 +#endif
  81 +{
  82 + v8::Isolate* isolate = static_cast<v8::Isolate*>(arg);
  83 + assert(isolate != NULL);
  84 + v8::Locker locker(isolate);
  85 + isolate->Enter();
  86 +
  87 + // First pass-- find isolate thread key
  88 + for (pthread_key_t ii = coro_thread_key; ii > 0; --ii) {
  89 + void* tls = pthread_getspecific(ii - 1);
  90 + if (tls == isolate) {
  91 + isolate_key = ii - 1;
  92 + break;
  93 + }
  94 + }
  95 + assert(isolate_key != 0x7777);
  96 +
  97 + // Second pass-- find data key
  98 + int thread_id = 0;
  99 + for (pthread_key_t ii = isolate_key + 2; ii < coro_thread_key; ++ii) {
  100 + void* tls = pthread_getspecific(ii);
  101 + if (can_poke(tls) && *(void**)tls == isolate) {
  102 + // First member of per-thread data is the isolate
  103 + thread_data_key = ii;
  104 + // Second member is the thread id
  105 + thread_id = *(int*)((void**)tls + 1);
  106 + break;
  107 + }
  108 + }
  109 + assert(thread_data_key != 0x7777);
  110 +
  111 + // Third pass-- find thread id key
  112 + for (pthread_key_t ii = isolate_key + 1; ii < thread_data_key; ++ii) {
  113 + int tls = static_cast<int>(reinterpret_cast<intptr_t>(pthread_getspecific(ii)));
  114 + if (tls == thread_id) {
  115 + thread_id_key = ii;
  116 + break;
  117 + }
  118 + }
  119 + assert(thread_id_key != 0x7777);
  120 +
  121 + isolate->Exit();
  122 + return NULL;
  123 +}
  124 +
  125 +/**
  126 + * Coroutine class definition
  127 + */
  128 +void Coroutine::init(v8::Isolate* isolate) {
  129 + v8::Unlocker unlocker(isolate);
  130 + pthread_key_create(&coro_thread_key, NULL);
  131 + pthread_setspecific(coro_thread_key, &current());
  132 +#ifdef USE_V8_SYMBOLS
  133 + isolate_key = v8::internal::Isolate::isolate_key_;
  134 + thread_data_key = v8::internal::Isolate::per_isolate_thread_data_key_;
  135 + thread_id_key = v8::internal::Isolate::thread_id_key_;
  136 +#else
  137 + pthread_t thread;
  138 + pthread_create(&thread, NULL, find_thread_id_key, isolate);
  139 + pthread_join(thread, NULL);
  140 +#endif
  141 +}
  142 +
  143 +Coroutine& Coroutine::current() {
  144 + Coroutine* current = static_cast<Coroutine*>(pthread_getspecific(coro_thread_key));
  145 + if (!current) {
  146 + current = new Coroutine;
  147 + pthread_setspecific(coro_thread_key, current);
  148 + }
  149 + return *current;
  150 +}
  151 +
  152 +void Coroutine::set_stack_size(unsigned int size) {
  153 + assert(!stack_size);
  154 + stack_size = size;
  155 +}
  156 +
  157 +size_t Coroutine::coroutines_created() {
  158 + return coroutines_created_;
  159 +}
  160 +
  161 +void Coroutine::trampoline(void* that) {
  162 +#ifdef CORO_PTHREAD
  163 + pthread_setspecific(coro_thread_key, that);
  164 +#endif
  165 +#ifdef CORO_FIBER
  166 + // I can't figure out how to get the precise base of the stack in Windows. Since CreateFiber
  167 + // creates the stack automatically we don't have access to the base. We can however grab the
  168 + // current esp position, and use that as an approximation. Padding is added for safety since the
  169 + // base is slightly different.
  170 + static_cast<Coroutine*>(that)->stack_base = (size_t*)_AddressOfReturnAddress() - stack_size + 16;
  171 +#endif
  172 + if (!fls_data_pool.empty()) {
  173 + pthread_setspecific(thread_data_key, fls_data_pool.back());
  174 + pthread_setspecific(thread_id_key, fls_data_pool.at(fls_data_pool.size() - 2));
  175 + pthread_setspecific(isolate_key, fls_data_pool.at(fls_data_pool.size() - 3));
  176 + fls_data_pool.resize(fls_data_pool.size() - 3);
  177 + }
  178 + while (true) {
  179 + static_cast<Coroutine*>(that)->entry(const_cast<void*>(static_cast<Coroutine*>(that)->arg));
  180 + }
  181 +}
  182 +
  183 +Coroutine::Coroutine() :
  184 + fls_data(v8_tls_keys),
  185 + entry(NULL),
  186 + arg(NULL) {
  187 + stack.sptr = NULL;
  188 + coro_create(&context, NULL, NULL, NULL, 0);
  189 +}
  190 +
  191 +Coroutine::Coroutine(entry_t& entry, void* arg) :
  192 + fls_data(v8_tls_keys),
  193 + entry(entry),
  194 + arg(arg) {
  195 +}
  196 +
  197 +Coroutine::~Coroutine() {
  198 + if (stack.sptr) {
  199 + coro_stack_free(&stack);
  200 + }
  201 +#ifdef CORO_FIBER
  202 + if (context.fiber)
  203 +#endif
  204 + (void)coro_destroy(&context);
  205 +}
  206 +
  207 +Coroutine* Coroutine::create_fiber(entry_t* entry, void* arg) {
  208 + if (!fiber_pool.empty()) {
  209 + Coroutine* fiber = fiber_pool.back();
  210 + fiber_pool.pop_back();
  211 + fiber->reset(entry, arg);
  212 + return fiber;
  213 + }
  214 + Coroutine* coro = new Coroutine(*entry, arg);
  215 + if (!coro_stack_alloc(&coro->stack, stack_size)) {
  216 + delete coro;
  217 + return NULL;
  218 + }
  219 + coro_create(&coro->context, trampoline, coro, coro->stack.sptr, coro->stack.ssze);
  220 +#ifdef CORO_FIBER
  221 + // Stupid hack. libcoro's project structure combined with Windows's CreateFiber functions makes
  222 + // it difficult to catch this error. Sometimes Windows will return `ERROR_NOT_ENOUGH_MEMORY` or
  223 + // `ERROR_COMMITMENT_LIMIT` if it can't make any more fibers. However, `coro_stack_alloc` returns
  224 + // success unconditionally on Windows so we have to detect the error here, after the call to
  225 + // `coro_create`.
  226 + if (!coro->context.fiber) {
  227 + delete coro;
  228 + return NULL;
  229 + }
  230 +#endif
  231 + ++coroutines_created_;
  232 + return coro;
  233 +}
  234 +
  235 +void Coroutine::reset(entry_t* entry, void* arg) {
  236 + assert(entry != NULL);
  237 + this->entry = entry;
  238 + this->arg = arg;
  239 +}
  240 +
  241 +void Coroutine::transfer(Coroutine& next) {
  242 + assert(this != &next);
  243 +#ifndef CORO_PTHREAD
  244 + fls_data[0] = pthread_getspecific(isolate_key);
  245 + fls_data[1] = pthread_getspecific(thread_id_key);
  246 + fls_data[2] = pthread_getspecific(thread_data_key);
  247 +
  248 + pthread_setspecific(isolate_key, next.fls_data[0]);
  249 + pthread_setspecific(thread_id_key, next.fls_data[1]);
  250 + pthread_setspecific(thread_data_key, next.fls_data[2]);
  251 +
  252 + pthread_setspecific(coro_thread_key, &next);
  253 +#endif
  254 + coro_transfer(&context, &next.context);
  255 +#ifndef CORO_PTHREAD
  256 + pthread_setspecific(coro_thread_key, this);
  257 +#endif
  258 +}
  259 +
  260 +void Coroutine::run() {
  261 + Coroutine& current = Coroutine::current();
  262 + assert(!delete_me);
  263 + assert(&current != this);
  264 + current.transfer(*this);
  265 +
  266 + if (delete_me) {
  267 + // This means finish() was called on the coroutine and the pool was full so this coroutine needs
  268 + // to be deleted. We can't delete from inside finish(), because that would deallocate the
  269 + // current stack. However we CAN delete here, we just have to be very careful.
  270 + assert(delete_me == this);
  271 + assert(&current != this);
  272 + delete_me = NULL;
  273 + delete this;
  274 + }
  275 +}
  276 +
  277 +void Coroutine::finish(Coroutine& next, v8::Isolate* isolate) {
  278 + {
  279 + assert(&next != this);
  280 + assert(&current() == this);
  281 + if (fiber_pool.size() < pool_size) {
  282 + fiber_pool.push_back(this);
  283 + } else {
  284 +#if V8_MAJOR_VERSION > 4 || (V8_MAJOR_VERSION == 4 && V8_MINOR_VERSION >= 10)
  285 + // Clean up isolate data
  286 + isolate->DiscardThreadSpecificMetadata();
  287 +#else
  288 + // If not supported, then we can mitigate v8's leakage by saving these thread locals.
  289 + fls_data_pool.reserve(fls_data_pool.size() + 3);
  290 + fls_data_pool.push_back(pthread_getspecific(isolate_key));
  291 + fls_data_pool.push_back(pthread_getspecific(thread_id_key));
  292 + fls_data_pool.push_back(pthread_getspecific(thread_data_key));
  293 +#endif
  294 + // Can't delete right now because we're currently on this stack!
  295 + assert(delete_me == NULL);
  296 + delete_me = this;
  297 + }
  298 + }
  299 + this->transfer(next);
  300 +}
  301 +
  302 +void* Coroutine::bottom() const {
  303 +#ifdef CORO_FIBER
  304 + return stack_base;
  305 +#else
  306 + return stack.sptr;
  307 +#endif
  308 +}
  309 +
  310 +size_t Coroutine::size() const {
  311 + return sizeof(Coroutine) + stack_size * sizeof(void*);
  312 +}
  1 +#include <node.h>
  2 +#include <stdlib.h>
  3 +#include <vector>
  4 +#include "libcoro/coro.h"
  5 +
  6 +class Coroutine {
  7 + public:
  8 + typedef void(entry_t)(void*);
  9 +
  10 + private:
  11 +#ifdef CORO_FIBER
  12 + void* stack_base;
  13 +#endif
  14 + coro_context context;
  15 + coro_stack stack;
  16 + std::vector<void*> fls_data;
  17 + entry_t* entry;
  18 + void* arg;
  19 +
  20 + ~Coroutine();
  21 +
  22 + /**
  23 + * Constructor for currently running "fiber". This is really just original thread, but we
  24 + * need a way to get back into the main thread after yielding to a fiber. Basically this
  25 + * shouldn't be called from anywhere.
  26 + */
  27 + Coroutine();
  28 +
  29 + /**
  30 + * This constructor will actually create a new fiber context. Execution does not begin
  31 + * until you call run() for the first time.
  32 + */
  33 + Coroutine(entry_t& entry, void* arg);
  34 +
  35 + /**
  36 + * Resets the context of this coroutine from the start. Used to recyle old coroutines.
  37 + */
  38 + void reset(entry_t* entry, void* arg);
  39 +
  40 + static void trampoline(void* that);
  41 + void transfer(Coroutine& next);
  42 +
  43 + public:
  44 + static size_t pool_size;
  45 +
  46 + /**
  47 + * Returns the currently-running fiber.
  48 + */
  49 + static Coroutine& current();
  50 +
  51 + /**
  52 + * Create a new fiber.
  53 + */
  54 + static Coroutine* create_fiber(entry_t* entry, void* arg = NULL);
  55 +
  56 + /**
  57 + * Initialize the library.
  58 + */
  59 + static void init(v8::Isolate* isolate);
  60 +
  61 + /**
  62 + * Set the size of coroutines created by this library. Since coroutines are pooled the stack
  63 + * size is global instead of per-coroutine. Stack is measured in sizeof(void*), so
  64 + * set_stack_size(128) -> 512 bytes or 1kb
  65 + */
  66 + static void set_stack_size(unsigned int size);
  67 +
  68 + /**
  69 + * Get the number of coroutines that have been created.
  70 + */
  71 + static size_t coroutines_created();
  72 +
  73 + /**
  74 + * Start or resume execution in this fiber. Note there is no explicit yield() function,
  75 + * you must manually run another fiber.
  76 + */
  77 + void run();
  78 +
  79 + /**
  80 + * Finish this coroutine.. This will halt execution of this coroutine and resume execution
  81 + * of `next`. If you do not call this function, and instead just return from `entry` the
  82 + * application will exit. This function may or may not actually return.
  83 + */
  84 + void finish(Coroutine& next, v8::Isolate* isolate);
  85 +
  86 + /**
  87 + * Returns address of the lowest usable byte in this Coroutine's stack.
  88 + */
  89 + void* bottom() const;
  90 +
  91 + /**
  92 + * Returns the size this Coroutine takes up in the heap.
  93 + */
  94 + size_t size() const;
  95 +};
  1 +#include "coroutine.h"
  2 +#include "v8-version.h"
  3 +#include <assert.h>
  4 +#include <node.h>
  5 +#include <node_version.h>
  6 +
  7 +#include <vector>
  8 +#include <iostream>
  9 +
  10 +#define THROW(x, m) return uni::Return(uni::ThrowException(Isolate::GetCurrent(), x(uni::NewLatin1String(Isolate::GetCurrent(), m))), args)
  11 +
  12 +// Run GC more often when debugging
  13 +#ifdef DEBUG
  14 +#define GC_ADJUST 100
  15 +#else
  16 +#define GC_ADJUST 1
  17 +#endif
  18 +
  19 +using namespace std;
  20 +using namespace v8;
  21 +
  22 +// Handle legacy V8 API
  23 +namespace uni {
  24 +#if V8_MAJOR_VERSION > 5 || (V8_MAJOR_VERSION == 5 && V8_MINOR_VERSION >= 2)
  25 + // Actually 5.2.244
  26 + template <void (*F)(void*), class P>
  27 + void WeakCallbackShim(const WeakCallbackInfo<P>& data) {
  28 + F(data.GetParameter());
  29 + }
  30 +
  31 + template <void (*F)(void*), class T, typename P>
  32 + void MakeWeak(Isolate* isolate, Persistent<T>& handle, P* val) {
  33 + handle.SetWeak(val, WeakCallbackShim<F, P>, WeakCallbackType::kFinalizer);
  34 + }
  35 +#elif V8_MAJOR_VERSION > 3 || (V8_MAJOR_VERSION == 3 && V8_MINOR_VERSION >= 26)
  36 + template <void (*F)(void*), class T, typename P>
  37 + void WeakCallbackShim(const v8::WeakCallbackData<T, P>& data) {
  38 + F(data.GetParameter());
  39 + }
  40 +
  41 + template <void (*F)(void*), class T, typename P>
  42 + void MakeWeak(Isolate* isolate, Persistent<T>& handle, P* val) {
  43 + handle.SetWeak(val, WeakCallbackShim<F>);
  44 + }
  45 +#else
  46 + template <void (*F)(void*)>
  47 + void WeakCallbackShim(Persistent<Value> value, void* data) {
  48 + F(data);
  49 + }
  50 + template <void (*F)(void*), class T, typename P>
  51 + void MakeWeak(Isolate* isolate, Persistent<T>& handle, P* val) {
  52 + handle.MakeWeak(val, WeakCallbackShim<F>);
  53 + }
  54 +#endif
  55 +
  56 +
  57 +#if V8_MAJOR_VERSION > 3 || (V8_MAJOR_VERSION == 3 && V8_MINOR_VERSION >= 26)
  58 + // Node v0.11.13+
  59 + typedef PropertyCallbackInfo<Value> GetterCallbackInfo;
  60 + typedef PropertyCallbackInfo<void> SetterCallbackInfo;
  61 + typedef void FunctionType;
  62 + typedef FunctionCallbackInfo<v8::Value> Arguments;
  63 +
  64 + class HandleScope {
  65 + v8::HandleScope scope;
  66 + public: HandleScope(Isolate* isolate) : scope(isolate) {}
  67 + };
  68 +
  69 + template <class T>
  70 + void Reset(Isolate* isolate, Persistent<T>& persistent, Handle<T> handle) {
  71 + persistent.Reset(isolate, handle);
  72 + }
  73 + template <class T>
  74 + void Dispose(Isolate* isolate, Persistent<T>& handle) {
  75 + handle.Reset();
  76 + }
  77 + template <class T>
  78 + void ClearWeak(Isolate* isolate, Persistent<T>& handle) {
  79 + handle.ClearWeak(isolate);
  80 + }
  81 +
  82 + template <class T>
  83 + void SetInternalPointer(Handle<T> handle, int index, void* val) {
  84 + handle->SetAlignedPointerInInternalField(index, val);
  85 + }
  86 + template <class T>
  87 + void* GetInternalPointer(Handle<T> handle, int index) {
  88 + return handle->GetAlignedPointerFromInternalField(index);
  89 + }
  90 +
  91 + template <class T>
  92 + Handle<T> Deref(Isolate* isolate, Persistent<T>& handle) {
  93 + return Local<T>::New(isolate, handle);
  94 + }
  95 +
  96 + template <class T>
  97 + void Return(Handle<T> handle, const Arguments& args) {
  98 + args.GetReturnValue().Set(handle);
  99 + }
  100 + template <class T>
  101 + void Return(Handle<T> handle, GetterCallbackInfo info) {
  102 + info.GetReturnValue().Set(handle);
  103 + }
  104 + template <class T>
  105 + void Return(Persistent<T>& handle, GetterCallbackInfo info) {
  106 + info.GetReturnValue().Set(handle);
  107 + }
  108 +
  109 + Handle<Value> ThrowException(Isolate* isolate, Handle<Value> exception) {
  110 + return isolate->ThrowException(exception);
  111 + }
  112 +
  113 + Handle<Context> GetCurrentContext(Isolate* isolate) {
  114 + return isolate->GetCurrentContext();
  115 + }
  116 +
  117 + Handle<Primitive> Undefined(Isolate* isolate) {
  118 + return v8::Undefined(isolate);
  119 + }
  120 +
  121 + Handle<String> NewLatin1String(Isolate* isolate, const char* string) {
  122 + return String::NewFromOneByte(isolate, (const uint8_t*)string);
  123 + }
  124 +
  125 + Handle<String> NewLatin1Symbol(Isolate* isolate, const char* string) {
  126 + return String::NewFromOneByte(isolate, (const uint8_t*)string);
  127 + }
  128 +
  129 + Handle<Boolean> NewBoolean(Isolate* isolate, bool value) {
  130 + return Boolean::New(isolate, value);
  131 + }
  132 +
  133 + Handle<Number> NewNumber(Isolate* isolate, double value) {
  134 + return Number::New(isolate, value);
  135 + }
  136 +
  137 + Handle<FunctionTemplate> NewFunctionTemplate(
  138 + Isolate* isolate,
  139 + FunctionCallback callback,
  140 + Handle<Value> data = Handle<Value>(),
  141 + Handle<Signature> signature = Handle<Signature>(),
  142 + int length = 0
  143 + ) {
  144 + return FunctionTemplate::New(isolate, callback, data, signature, length);
  145 + }
  146 +
  147 + Handle<Signature> NewSignature(
  148 + Isolate* isolate,
  149 + Handle<FunctionTemplate> receiver = Handle<FunctionTemplate>()
  150 + ) {
  151 + return Signature::New(isolate, receiver);
  152 + }
  153 +
  154 + class ReverseIsolateScope {
  155 + Isolate* isolate;
  156 + public:
  157 + explicit inline ReverseIsolateScope(Isolate* isolate) : isolate(isolate) {
  158 + isolate->Exit();
  159 + }
  160 + inline ~ReverseIsolateScope() {
  161 + isolate->Enter();
  162 + }
  163 + };
  164 +
  165 + void AdjustAmountOfExternalAllocatedMemory(Isolate* isolate, int64_t change_in_bytes) {
  166 + isolate->AdjustAmountOfExternalAllocatedMemory(change_in_bytes);
  167 + }
  168 +#else
  169 + // Node v0.10.x and lower
  170 + typedef AccessorInfo GetterCallbackInfo;
  171 + typedef AccessorInfo SetterCallbackInfo;
  172 + typedef Handle<Value> FunctionType;
  173 + typedef Arguments Arguments;
  174 +
  175 + class HandleScope {
  176 + v8::HandleScope scope;
  177 + public: HandleScope(Isolate* isolate) {}
  178 + };
  179 +
  180 + template <class T>
  181 + void Reset(Isolate* isolate, Persistent<T>& persistent, Handle<T> handle) {
  182 + persistent = Persistent<T>::New(handle);
  183 + }
  184 + template <class T>
  185 + void Dispose(Isolate* isolate, Persistent<T>& handle) {
  186 + handle.Dispose();
  187 + }
  188 +
  189 + template <class T>
  190 + void ClearWeak(Isolate* isolate, Persistent<T>& handle) {
  191 + handle.ClearWeak();
  192 + }
  193 +
  194 + template <class T>
  195 + void SetInternalPointer(Handle<T> handle, int index, void* val) {
  196 + handle->SetPointerInInternalField(index, val);
  197 + }
  198 + template <class T>
  199 + void* GetInternalPointer(Handle<T> handle, int index) {
  200 + return handle->GetPointerFromInternalField(index);
  201 + }
  202 +
  203 + template <class T>
  204 + Handle<T> Deref(Isolate* isolate, Persistent<T>& handle) {
  205 + return Local<T>::New(handle);
  206 + }
  207 +
  208 + Handle<Value> Return(Handle<Value> handle, GetterCallbackInfo info) {
  209 + return handle;
  210 + }
  211 +
  212 + Handle<Value> Return(Handle<Value> handle, const Arguments& args) {
  213 + return handle;
  214 + }
  215 +
  216 + Handle<Value> ThrowException(Isolate* isolate, Handle<Value> exception) {
  217 + return ThrowException(exception);
  218 + }
  219 +
  220 + Handle<Context> GetCurrentContext(Isolate* isolate) {
  221 + return Context::GetCurrent();
  222 + }
  223 +
  224 + Handle<Primitive> Undefined(Isolate* isolate) {
  225 + return v8::Undefined();
  226 + }
  227 +
  228 + Handle<String> NewLatin1String(Isolate* isolate, const char* string) {
  229 + return String::New(string);
  230 + }
  231 +
  232 + Handle<String> NewLatin1Symbol(Isolate* isolate, const char* string) {
  233 + return String::NewSymbol(string);
  234 + }
  235 +
  236 + Handle<Boolean> NewBoolean(Isolate* isolate, bool value) {
  237 + return Boolean::New(value);
  238 + }
  239 +
  240 + Handle<Number> NewNumber(Isolate* isolate, double value) {
  241 + return Number::New(value);
  242 + }
  243 +
  244 + Handle<FunctionTemplate> NewFunctionTemplate(
  245 + Isolate* isolate,
  246 + InvocationCallback callback,
  247 + Handle<Value> data = Handle<Value>(),
  248 + Handle<Signature> signature = Handle<Signature>(),
  249 + int length = 0
  250 + ) {
  251 + return FunctionTemplate::New(callback, data, signature);
  252 + }
  253 +
  254 + Handle<Signature> NewSignature(
  255 + Isolate* isolate,
  256 + Handle<FunctionTemplate> receiver = Handle<FunctionTemplate>(),
  257 + int argc = 0,
  258 + Handle<FunctionTemplate> argv[] = 0
  259 + ) {
  260 + return Signature::New(receiver, argc, argv);
  261 + }
  262 +
  263 + class ReverseIsolateScope {
  264 + public: explicit inline ReverseIsolateScope(Isolate* isolate) {}
  265 + };
  266 +
  267 + void AdjustAmountOfExternalAllocatedMemory(Isolate* isolate, int64_t change_in_bytes) {
  268 + V8::AdjustAmountOfExternalAllocatedMemory(change_in_bytes);
  269 + }
  270 +#endif
  271 +
  272 +#if V8_MAJOR_VERSION > 3 || (V8_MAJOR_VERSION == 3 && V8_MINOR_VERSION >= 29)
  273 + // This was actually added in 3.29.67
  274 + void SetStackGuard(Isolate* isolate, void* guard) {
  275 + isolate->SetStackLimit(reinterpret_cast<uintptr_t>(guard));
  276 + }
  277 +#elif V8_MAJOR_VERSION > 3 || (V8_MAJOR_VERSION == 3 && V8_MINOR_VERSION >= 26)
  278 + void SetStackGuard(Isolate* isolate, void* guard) {
  279 + ResourceConstraints constraints;
  280 + constraints.set_stack_limit(reinterpret_cast<uint32_t*>(guard));
  281 + v8::SetResourceConstraints(isolate, &constraints);
  282 + }
  283 +#else
  284 + // Extra padding for old versions of v8. Shit's fucked.
  285 + void SetStackGuard(Isolate* isolate, void* guard) {
  286 + ResourceConstraints constraints;
  287 + constraints.set_stack_limit(
  288 + reinterpret_cast<uint32_t*>(guard) + 18 * 1024
  289 + );
  290 + v8::SetResourceConstraints(&constraints);
  291 + }
  292 +#endif
  293 +}
  294 +
  295 +class Fiber {
  296 +
  297 + private:
  298 + static Locker* global_locker; // Node does not use locks or threads, so we need a global lock
  299 + static Persistent<FunctionTemplate> tmpl;
  300 + static Persistent<Function> fiber_object;
  301 + static Fiber* current;
  302 + static vector<Fiber*> orphaned_fibers;
  303 + static Persistent<Value> fatal_stack;
  304 +
  305 + Isolate* isolate;
  306 + Persistent<Object> handle;
  307 + Persistent<Function> cb;
  308 + Persistent<Context> v8_context;
  309 + Persistent<Value> zombie_exception;
  310 + Persistent<Value> yielded;
  311 + bool yielded_exception;
  312 + Coroutine* entry_fiber;
  313 + Coroutine* this_fiber;
  314 + bool started;
  315 + bool yielding;
  316 + bool zombie;
  317 + bool resetting;
  318 +
  319 + static Fiber& Unwrap(Handle<Object> handle) {
  320 + assert(!handle.IsEmpty());
  321 + assert(handle->InternalFieldCount() == 1);
  322 + return *static_cast<Fiber*>(uni::GetInternalPointer(handle, 0));
  323 + }
  324 +
  325 + Fiber(Handle<Object> handle, Handle<Function> cb, Handle<Context> v8_context) :
  326 + isolate(Isolate::GetCurrent()),
  327 + started(false),
  328 + yielding(false),
  329 + zombie(false),
  330 + resetting(false) {
  331 + uni::Reset(isolate, this->handle, handle);
  332 + uni::Reset(isolate, this->cb, cb);
  333 + uni::Reset(isolate, this->v8_context, v8_context);
  334 +
  335 + MakeWeak();
  336 + uni::SetInternalPointer(handle, 0, this);
  337 + }
  338 +
  339 + virtual ~Fiber() {
  340 + assert(!this->started);
  341 + uni::Dispose(isolate, handle);
  342 + uni::Dispose(isolate, cb);
  343 + uni::Dispose(isolate, v8_context);
  344 + }
  345 +
  346 + /**
  347 + * Call MakeWeak if it's ok for v8 to garbage collect this Fiber.
  348 + * i.e. After fiber completes, while yielded, or before started
  349 + */
  350 + void MakeWeak() {
  351 + uni::MakeWeak<WeakCallback>(isolate, handle, (void*)this);
  352 + }
  353 +
  354 + /**
  355 + * And call ClearWeak if it's not ok for v8 to garbage collect this Fiber.
  356 + * i.e. While running.
  357 + */
  358 + void ClearWeak() {
  359 + handle.ClearWeak();
  360 + }
  361 +
  362 + /**
  363 + * Called when there are no more references to this object in Javascript. If this happens and
  364 + * the fiber is currently suspended we'll unwind the fiber's stack by throwing exceptions in
  365 + * order to clear all references.
  366 + */
  367 + static void WeakCallback(void* data) {
  368 + Fiber& that = *static_cast<Fiber*>(data);
  369 + assert(that.handle.IsNearDeath());
  370 + assert(current != &that);
  371 +
  372 + // We'll unwind running fibers later... doing it from the garbage collector is bad news.
  373 + if (that.started) {
  374 + assert(that.yielding);
  375 + orphaned_fibers.push_back(&that);
  376 + that.ClearWeak();
  377 + return;
  378 + }
  379 +
  380 + delete &that;
  381 + }
  382 +
  383 + /**
  384 + * When the v8 garbage collector notifies us about dying fibers instead of unwindng their
  385 + * stack as soon as possible we put them aside to unwind later. Unwinding from the garbage
  386 + * collector leads to exponential time garbage collections if there are many orphaned Fibers,
  387 + * there's also the possibility of running out of stack space. It's generally bad news.
  388 + *
  389 + * So instead we have this function to clean up all the fibers after the garbage collection
  390 + * has finished.
  391 + */
  392 + static void DestroyOrphans() {
  393 + if (orphaned_fibers.empty()) {
  394 + return;
  395 + }
  396 + vector<Fiber*> orphans(orphaned_fibers);
  397 + orphaned_fibers.clear();
  398 +
  399 + for (vector<Fiber*>::iterator ii = orphans.begin(); ii != orphans.end(); ++ii) {
  400 + Fiber& that = **ii;
  401 + that.UnwindStack();
  402 +
  403 + if (that.yielded_exception) {
  404 + // If you throw an exception from a fiber that's being garbage collected there's no way
  405 + // to bubble that exception up to the application.
  406 + String::Utf8Value stack(uni::Deref(that.isolate, fatal_stack));
  407 + cerr <<
  408 + "An exception was thrown from a Fiber which was being garbage collected. This error "
  409 + "can not be gracefully recovered from. The only acceptable behavior is to terminate "
  410 + "this application. The exception appears below:\n\n"
  411 + <<*stack <<"\n";
  412 + exit(1);
  413 + } else {
  414 + uni::Dispose(that.isolate, fatal_stack);
  415 + }
  416 +
  417 + uni::Dispose(that.isolate, that.yielded);
  418 + that.MakeWeak();
  419 + }
  420 + }
  421 +
  422 + /**
  423 + * Instantiate a new Fiber object. When a fiber is created it only grabs a handle to the
  424 + * callback; it doesn't create any new contexts until run() is called.
  425 + */
  426 + static uni::FunctionType New(const uni::Arguments& args) {
  427 + if (args.Length() != 1) {
  428 + THROW(Exception::TypeError, "Fiber expects 1 argument");
  429 + } else if (!args[0]->IsFunction()) {
  430 + THROW(Exception::TypeError, "Fiber expects a function");
  431 + } else if (!args.IsConstructCall()) {
  432 + Handle<Value> argv[1] = { args[0] };
  433 + return uni::Return(uni::Deref(Isolate::GetCurrent(), tmpl)->GetFunction()->NewInstance(1, argv), args);
  434 + }
  435 +
  436 + Handle<Function> fn = Handle<Function>::Cast(args[0]);
  437 + new Fiber(args.This(), fn, uni::GetCurrentContext(Isolate::GetCurrent()));
  438 + return uni::Return(args.This(), args);
  439 + }
  440 +
  441 + /**
  442 + * Begin or resume the current fiber. If the fiber is not currently running a new context will
  443 + * be created and the callback will start. Otherwise we switch back into the exist context.
  444 + */
  445 + static uni::FunctionType Run(const uni::Arguments& args) {
  446 + Fiber& that = Unwrap(args.Holder());
  447 +
  448 + // There seems to be no better place to put this check..
  449 + DestroyOrphans();
  450 +
  451 + if (that.started && !that.yielding) {
  452 + THROW(Exception::Error, "This Fiber is already running");
  453 + } else if (args.Length() > 1) {
  454 + THROW(Exception::TypeError, "run() excepts 1 or no arguments");
  455 + }
  456 +
  457 + if (!that.started) {
  458 + // Create a new context with entry point `Fiber::RunFiber()`.
  459 + void** data = new void*[2];
  460 + data[0] = (void*)&args;
  461 + data[1] = &that;
  462 + that.this_fiber = Coroutine::create_fiber((void (*)(void*))RunFiber, data);
  463 + if (!that.this_fiber) {
  464 + delete[] data;
  465 + THROW(Exception::RangeError, "Out of memory");
  466 + }
  467 + that.started = true;
  468 + uni::AdjustAmountOfExternalAllocatedMemory(that.isolate, that.this_fiber->size() * GC_ADJUST);
  469 + } else {
  470 + // If the fiber is currently running put the first parameter to `run()` on `yielded`, then
  471 + // the pending call to `yield()` will return that value. `yielded` in this case is just a
  472 + // misnomer, we're just reusing the same handle.
  473 + that.yielded_exception = false;
  474 + if (args.Length()) {
  475 + uni::Reset(that.isolate, that.yielded, args[0]);
  476 + } else {
  477 + uni::Reset<Value>(that.isolate, that.yielded, uni::Undefined(that.isolate));
  478 + }
  479 + }
  480 + that.SwapContext();
  481 + return uni::Return(that.ReturnYielded(), args);
  482 + }
  483 +
  484 + /**
  485 + * Throw an exception into a currently yielding fiber.
  486 + */
  487 + static uni::FunctionType ThrowInto(const uni::Arguments& args) {
  488 + Fiber& that = Unwrap(args.Holder());
  489 +
  490 + if (!that.yielding) {
  491 + THROW(Exception::Error, "This Fiber is not yielding");
  492 + } else if (args.Length() == 0) {
  493 + uni::Reset<Value>(that.isolate, that.yielded, uni::Undefined(that.isolate));
  494 + } else if (args.Length() == 1) {
  495 + uni::Reset(that.isolate, that.yielded, args[0]);
  496 + } else {
  497 + THROW(Exception::TypeError, "throwInto() expects 1 or no arguments");
  498 + }
  499 + that.yielded_exception = true;
  500 + that.SwapContext();
  501 + return uni::Return(that.ReturnYielded(), args);
  502 + }
  503 +
  504 + /**
  505 + * Unwinds a currently running fiber. If the fiber is not running then this function has no
  506 + * effect.
  507 + */
  508 + static uni::FunctionType Reset(const uni::Arguments& args) {
  509 + Fiber& that = Unwrap(args.Holder());
  510 +
  511 + if (!that.started) {
  512 + return uni::Return(uni::Undefined(that.isolate), args);
  513 + } else if (!that.yielding) {
  514 + THROW(Exception::Error, "This Fiber is not yielding");
  515 + } else if (args.Length()) {
  516 + THROW(Exception::TypeError, "reset() expects no arguments");
  517 + }
  518 +
  519 + that.resetting = true;
  520 + that.UnwindStack();
  521 + that.resetting = false;
  522 + that.MakeWeak();
  523 +
  524 + Handle<Value> val = uni::Deref(that.isolate, that.yielded);
  525 + uni::Dispose(that.isolate, that.yielded);
  526 + if (that.yielded_exception) {
  527 + return uni::Return(uni::ThrowException(that.isolate, val), args);
  528 + } else {
  529 + return uni::Return(val, args);
  530 + }
  531 + }
  532 +
  533 + /**
  534 + * Turns the fiber into a zombie and unwinds its whole stack.
  535 + *
  536 + * After calling this function you must either destroy this fiber or call MakeWeak() or it will
  537 + * be leaked.
  538 + */
  539 + void UnwindStack() {
  540 + assert(!zombie);
  541 + assert(started);
  542 + assert(yielding);
  543 + zombie = true;
  544 +
  545 + // Setup an exception which will be thrown and rethrown from Fiber::Yield()
  546 + Handle<Value> zombie_exception = Exception::Error(uni::NewLatin1String(isolate, "This Fiber is a zombie"));
  547 + uni::Reset(isolate, this->zombie_exception, zombie_exception);
  548 + uni::Reset(isolate, yielded, zombie_exception);
  549 + yielded_exception = true;
  550 +
  551 + // Swap context back to Fiber::Yield() which will throw an exception to unwind the stack.
  552 + // Futher calls to yield from this fiber will rethrow the same exception.
  553 + SwapContext();
  554 + assert(!started);
  555 + zombie = false;
  556 +
  557 + // Make sure this is the exception we threw
  558 + if (yielded_exception && yielded == zombie_exception) {
  559 + yielded_exception = false;
  560 + uni::Dispose(isolate, yielded);
  561 + uni::Reset<Value>(isolate, yielded, uni::Undefined(isolate));
  562 + }
  563 + uni::Dispose(isolate, this->zombie_exception);
  564 + }
  565 +
  566 + /**
  567 + * Common logic between Run(), ThrowInto(), and UnwindStack(). This is essentially just a
  568 + * wrapper around this->fiber->() which also handles all the bookkeeping needed.
  569 + */
  570 + void SwapContext() {
  571 +
  572 + entry_fiber = &Coroutine::current();
  573 + Fiber* last_fiber = current;
  574 + current = this;
  575 +
  576 + // This will jump into either `RunFiber()` or `Yield()`, depending on if the fiber was
  577 + // already running.
  578 + {
  579 + Unlocker unlocker(isolate);
  580 + uni::ReverseIsolateScope isolate_scope(isolate);
  581 + this_fiber->run();
  582 + }
  583 +
  584 + // At this point the fiber either returned or called `yield()`.
  585 + current = last_fiber;
  586 + }
  587 +
  588 + /**
  589 + * Grabs and resets this fiber's yielded value.
  590 + */
  591 + Handle<Value> ReturnYielded() {
  592 + Handle<Value> val = uni::Deref(isolate, yielded);
  593 + uni::Dispose(isolate, yielded);
  594 + if (yielded_exception) {
  595 + return uni::ThrowException(isolate, val);
  596 + } else {
  597 + return val;
  598 + }
  599 + }
  600 +
  601 + /**
  602 + * This is the entry point for a new fiber, from `run()`.
  603 + */
  604 + static void RunFiber(void** data) {
  605 + const uni::Arguments* args = (const uni::Arguments*)data[0];
  606 + Fiber& that = *(Fiber*)data[1];
  607 + delete[] data;
  608 +
  609 + // New C scope so that the stack-allocated objects will be destroyed before calling
  610 + // Coroutine::finish, because that function may not return, in which case the destructors in
  611 + // this function won't be called.
  612 + {
  613 + Locker locker(that.isolate);
  614 + Isolate::Scope isolate_scope(that.isolate);
  615 + uni::HandleScope scope(that.isolate);
  616 +
  617 + // Set the stack guard for this "thread"; allow 6k of padding past the JS limit for
  618 + // native v8 code to run
  619 + uni::SetStackGuard(that.isolate, reinterpret_cast<char*>(that.this_fiber->bottom()) + 1024 * 6);
  620 +
  621 + TryCatch try_catch;
  622 + that.ClearWeak();
  623 + Handle<Context> v8_context = uni::Deref(that.isolate, that.v8_context);
  624 + v8_context->Enter();
  625 +
  626 + // Workaround for v8 issue #1180
  627 + // http://code.google.com/p/v8/issues/detail?id=1180
  628 + Script::Compile(uni::NewLatin1String(that.isolate, "void 0;"));
  629 +
  630 + Handle<Value> yielded;
  631 + if (args->Length()) {
  632 + Handle<Value> argv[1] = { (*args)[0] };
  633 + yielded = uni::Deref(that.isolate, that.cb)->Call(v8_context->Global(), 1, argv);
  634 + } else {
  635 + yielded = uni::Deref(that.isolate, that.cb)->Call(v8_context->Global(), 0, NULL);
  636 + }
  637 +
  638 + if (try_catch.HasCaught()) {
  639 + uni::Reset(that.isolate, that.yielded, try_catch.Exception());
  640 + that.yielded_exception = true;
  641 + if (that.zombie && !that.resetting && !uni::Deref(that.isolate, that.yielded)->StrictEquals(uni::Deref(that.isolate, that.zombie_exception))) {
  642 + // Throwing an exception from a garbage sweep
  643 + uni::Reset(that.isolate, fatal_stack, try_catch.StackTrace());
  644 + }
  645 + } else {
  646 + uni::Reset(that.isolate, that.yielded, yielded);
  647 + that.yielded_exception = false;
  648 + }
  649 +
  650 + // Do not invoke the garbage collector if there's no context on the stack. It will seg fault
  651 + // otherwise.
  652 + uni::AdjustAmountOfExternalAllocatedMemory(that.isolate, -(int)(that.this_fiber->size() * GC_ADJUST));
  653 +
  654 + // Don't make weak until after notifying the garbage collector. Otherwise it may try and
  655 + // free this very fiber!
  656 + if (!that.zombie) {
  657 + that.MakeWeak();
  658 + }
  659 +
  660 + // Now safe to leave the context, this stack is done with JS.
  661 + v8_context->Exit();
  662 + }
  663 +
  664 + // The function returned (instead of yielding).
  665 + that.started = false;
  666 + that.this_fiber->finish(*that.entry_fiber, that.isolate);
  667 + }
  668 +
  669 + /**
  670 + * Yield control back to the function that called `run()`. The first parameter to this function
  671 + * is returned from `run()`. The context is saved, to be later resumed from `run()`.
  672 + * note: sigh, there is a #define Yield() in WinBase.h on Windows
  673 + */
  674 + static uni::FunctionType Yield_(const uni::Arguments& args) {
  675 + if (current == NULL) {
  676 + THROW(Exception::Error, "yield() called with no fiber running");
  677 + }
  678 +
  679 + Fiber& that = *current;
  680 +
  681 + if (that.zombie) {
  682 + return uni::Return(uni::ThrowException(that.isolate, uni::Deref(that.isolate, that.zombie_exception)), args);
  683 + } else if (args.Length() == 0) {
  684 + uni::Reset<Value>(that.isolate, that.yielded, Undefined(that.isolate));
  685 + } else if (args.Length() == 1) {
  686 + uni::Reset(that.isolate, that.yielded, args[0]);
  687 + } else {
  688 + THROW(Exception::TypeError, "yield() expects 1 or no arguments");
  689 + }
  690 + that.yielded_exception = false;
  691 +
  692 + // While not running this can be garbage collected if no one has a handle.
  693 + that.MakeWeak();
  694 +
  695 + // Return control back to `Fiber::run()`. While control is outside this function we mark it as
  696 + // ok to garbage collect. If no one ever has a handle to resume the function it's harmful to
  697 + // keep the handle around.
  698 + {
  699 + Unlocker unlocker(that.isolate);
  700 + uni::ReverseIsolateScope isolate_scope(that.isolate);
  701 + that.yielding = true;
  702 + that.entry_fiber->run();
  703 + that.yielding = false;
  704 + }
  705 + // Now `run()` has been called again.
  706 +
  707 + // Don't garbage collect anymore!
  708 + that.ClearWeak();
  709 +
  710 + // Return the yielded value
  711 + return uni::Return(that.ReturnYielded(), args);
  712 + }
  713 +
  714 + /**
  715 + * Getters for `started`, and `current`.
  716 + */
  717 + static uni::FunctionType GetStarted(Local<String> property, const uni::GetterCallbackInfo& info) {
  718 + if (info.This().IsEmpty() || info.This()->InternalFieldCount() != 1) {
  719 + return uni::Return(uni::Undefined(Isolate::GetCurrent()), info);
  720 + }
  721 + Fiber& that = Unwrap(info.This());
  722 + return uni::Return(uni::NewBoolean(that.isolate, that.started), info);
  723 + }
  724 +
  725 + static uni::FunctionType GetCurrent(Local<String> property, const uni::GetterCallbackInfo& info) {
  726 + if (current) {
  727 + return uni::Return(current->handle, info);
  728 + } else {
  729 + return uni::Return(uni::Undefined(Isolate::GetCurrent()), info);
  730 + }
  731 + }
  732 +
  733 + /**
  734 + * Allow access to coroutine pool size
  735 + */
  736 + static uni::FunctionType GetPoolSize(Local<String> property, const uni::GetterCallbackInfo& info) {
  737 + return uni::Return(uni::NewNumber(Isolate::GetCurrent(), Coroutine::pool_size), info);
  738 + }
  739 +
  740 + static void SetPoolSize(Local<String> property, Local<Value> value, const uni::SetterCallbackInfo& info) {
  741 + Coroutine::pool_size = value->ToNumber()->Value();
  742 + }
  743 +
  744 + /**
  745 + * Return number of fibers that have been created
  746 + */
  747 + static uni::FunctionType GetFibersCreated(Local<String> property, const uni::GetterCallbackInfo& info) {
  748 + return uni::Return(uni::NewNumber(Isolate::GetCurrent(), Coroutine::coroutines_created()), info);
  749 + }
  750 +
  751 + public:
  752 + /**
  753 + * Initialize the Fiber library.
  754 + */
  755 + static void Init(Handle<Object> target) {
  756 + // Use a locker which won't get destroyed when this library gets unloaded. This is a hack
  757 + // to prevent v8 from trying to clean up this "thread" while the whole application is
  758 + // shutting down. TODO: There's likely a better way to accomplish this, but since the
  759 + // application is going down lost memory isn't the end of the world. But with a regular lock
  760 + // there's seg faults when node shuts down.
  761 + Isolate* isolate = Isolate::GetCurrent();
  762 + global_locker = new Locker(isolate);
  763 + current = NULL;
  764 +
  765 + // Fiber constructor
  766 + Handle<FunctionTemplate> tmpl = uni::NewFunctionTemplate(isolate, New);
  767 + uni::Reset(isolate, Fiber::tmpl, tmpl);
  768 + tmpl->SetClassName(uni::NewLatin1Symbol(isolate, "Fiber"));
  769 +
  770 + // Guard which only allows these methods to be called on a fiber; prevents
  771 + // `fiber.run.call({})` from seg faulting.
  772 + Handle<Signature> sig = uni::NewSignature(isolate, tmpl);
  773 + tmpl->InstanceTemplate()->SetInternalFieldCount(1);
  774 +
  775 + // Fiber.prototype
  776 + Handle<ObjectTemplate> proto = tmpl->PrototypeTemplate();
  777 + proto->Set(uni::NewLatin1Symbol(isolate, "reset"),
  778 + uni::NewFunctionTemplate(isolate, Reset, Handle<Value>(), sig));
  779 + proto->Set(uni::NewLatin1Symbol(isolate, "run"),
  780 + uni::NewFunctionTemplate(isolate, Run, Handle<Value>(), sig));
  781 + proto->Set(uni::NewLatin1Symbol(isolate, "throwInto"),
  782 + uni::NewFunctionTemplate(isolate, ThrowInto, Handle<Value>(), sig));
  783 + proto->SetAccessor(uni::NewLatin1Symbol(isolate, "started"), GetStarted);
  784 +
  785 + // Global yield() function
  786 + Handle<Function> yield = uni::NewFunctionTemplate(isolate, Yield_)->GetFunction();
  787 + Handle<String> sym_yield = uni::NewLatin1Symbol(isolate, "yield");
  788 + target->Set(sym_yield, yield);
  789 +
  790 + // Fiber properties
  791 + Handle<Function> fn = tmpl->GetFunction();
  792 + fn->Set(sym_yield, yield);
  793 + fn->SetAccessor(uni::NewLatin1Symbol(isolate, "current"), GetCurrent);
  794 + fn->SetAccessor(uni::NewLatin1Symbol(isolate, "poolSize"), GetPoolSize, SetPoolSize);
  795 + fn->SetAccessor(uni::NewLatin1Symbol(isolate, "fibersCreated"), GetFibersCreated);
  796 +
  797 + // Global Fiber
  798 + target->Set(uni::NewLatin1Symbol(isolate, "Fiber"), fn);
  799 + uni::Reset(isolate, fiber_object, fn);
  800 + }
  801 +};
  802 +
  803 +Persistent<FunctionTemplate> Fiber::tmpl;
  804 +Persistent<Function> Fiber::fiber_object;
  805 +Locker* Fiber::global_locker;
  806 +Fiber* Fiber::current = NULL;
  807 +vector<Fiber*> Fiber::orphaned_fibers;
  808 +Persistent<Value> Fiber::fatal_stack;
  809 +bool did_init = false;
  810 +
  811 +#if !NODE_VERSION_AT_LEAST(0,10,0)
  812 +extern "C"
  813 +#endif
  814 +void init(Handle<Object> target) {
  815 + Isolate* isolate = Isolate::GetCurrent();
  816 + if (did_init || !target->Get(uni::NewLatin1Symbol(isolate, "Fiber"))->IsUndefined()) {
  817 + // Oh god. Node will call init() twice even though the library was loaded only once. See Node
  818 + // issue #2621 (no fix).
  819 + return;
  820 + }
  821 + did_init = true;
  822 + uni::HandleScope scope(isolate);
  823 + Coroutine::init(isolate);
  824 + Fiber::Init(target);
  825 + // Default stack size of either 512k or 1M. Perhaps make this configurable by the run time?
  826 + Coroutine::set_stack_size(128 * 1024);
  827 +}
  828 +
  829 +NODE_MODULE(fibers, init)
  1 +Copyright (c) 2000-2009 Marc Alexander Lehmann <schmorp@schmorp.de>
  2 +
  3 +Redistribution and use in source and binary forms, with or without modifica-
  4 +tion, are permitted provided that the following conditions are met:
  5 +
  6 + 1. Redistributions of source code must retain the above copyright notice,
  7 + this list of conditions and the following disclaimer.
  8 +
  9 + 2. Redistributions in binary form must reproduce the above copyright
  10 + notice, this list of conditions and the following disclaimer in the
  11 + documentation and/or other materials provided with the distribution.
  12 +
  13 +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
  14 +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER-
  15 +CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
  16 +EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE-
  17 +CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  18 +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  19 +OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  20 +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH-
  21 +ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  22 +OF THE POSSIBILITY OF SUCH DAMAGE.
  23 +
  24 +Alternatively, the following files carry an additional notice that
  25 +explicitly allows relicensing under the GPLv2: coro.c, coro.h.
  26 +
  1 +Configuration, documentation etc. is provided in the coro.h file. Please
  2 +note that the file conftest.c in this distribution is under the GPL. It is
  3 +not needed for proper operation of this library though, for that, coro.h
  4 +and coro.c suffice.
  5 +
  6 +Marc Lehmann <schmorp@schmorp.de>
  1 +/*
  2 + * This file was taken from pth-1.40/aclocal.m4
  3 + * The original copyright is below.
  4 + *
  5 + * GNU Pth - The GNU Portable Threads
  6 + * Copyright (c) 1999-2001 Ralf S. Engelschall <rse@engelschall.com>
  7 + *
  8 + * This file is part of GNU Pth, a non-preemptive thread scheduling
  9 + * library which can be found at http://www.gnu.org/software/pth/.
  10 + *
  11 + * This file is free software; you can redistribute it and/or
  12 + * modify it under the terms of the GNU Lesser General Public
  13 + * License as published by the Free Software Foundation; either
  14 + * version 2.1 of the License, or (at your option) any later version.
  15 + *
  16 + * This file is distributed in the hope that it will be useful,
  17 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  19 + * Lesser General Public License for more details.
  20 + *
  21 + * You should have received a copy of the GNU Lesser General Public
  22 + * License along with this file; if not, write to the Free Software
  23 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  24 + * USA, or contact Marc Lehmann <schmorp@schmorp.de>.
  25 + */
  26 +
  27 +#include <stdio.h>
  28 +#include <stdlib.h>
  29 +#include <string.h>
  30 +#if defined(TEST_sigstack) || defined(TEST_sigaltstack)
  31 +#include <sys/types.h>
  32 +#include <signal.h>
  33 +#include <unistd.h>
  34 +#endif
  35 +#if defined(TEST_makecontext)
  36 +#include <ucontext.h>
  37 +#endif
  38 +union alltypes {
  39 + long l;
  40 + double d;
  41 + void *vp;
  42 + void (*fp)(void);
  43 + char *cp;
  44 +};
  45 +static volatile char *handler_addr = (char *)0xDEAD;
  46 +#if defined(TEST_sigstack) || defined(TEST_sigaltstack)
  47 +static volatile int handler_done = 0;
  48 +void handler(int sig)
  49 +{
  50 + char garbage[1024];
  51 + int i;
  52 + auto int dummy;
  53 + for (i = 0; i < 1024; i++)
  54 + garbage[i] = 'X';
  55 + handler_addr = (char *)&dummy;
  56 + handler_done = 1;
  57 + return;
  58 +}
  59 +#endif
  60 +#if defined(TEST_makecontext)
  61 +static ucontext_t uc_handler;
  62 +static ucontext_t uc_main;
  63 +void handler(void)
  64 +{
  65 + char garbage[1024];
  66 + int i;
  67 + auto int dummy;
  68 + for (i = 0; i < 1024; i++)
  69 + garbage[i] = 'X';
  70 + handler_addr = (char *)&dummy;
  71 + swapcontext(&uc_handler, &uc_main);
  72 + return;
  73 +}
  74 +#endif
  75 +int main(int argc, char *argv[])
  76 +{
  77 + FILE *f;
  78 + char *skaddr;
  79 + char *skbuf;
  80 + int sksize;
  81 + char result[1024];
  82 + int i;
  83 + sksize = 32768;
  84 + skbuf = (char *)malloc(sksize*2+2*sizeof(union alltypes));
  85 + if (skbuf == NULL)
  86 + exit(1);
  87 + for (i = 0; i < sksize*2+2*sizeof(union alltypes); i++)
  88 + skbuf[i] = 'A';
  89 + skaddr = skbuf+sizeof(union alltypes);
  90 +#if defined(TEST_sigstack) || defined(TEST_sigaltstack)
  91 + {
  92 + struct sigaction sa;
  93 +#if defined(TEST_sigstack)
  94 + struct sigstack ss;
  95 +#elif defined(TEST_sigaltstack) && defined(HAVE_STACK_T)
  96 + stack_t ss;
  97 +#else
  98 + struct sigaltstack ss;
  99 +#endif
  100 +#if defined(TEST_sigstack)
  101 + ss.ss_sp = (void *)(skaddr + sksize);
  102 + ss.ss_onstack = 0;
  103 + if (sigstack(&ss, NULL) < 0)
  104 + exit(1);
  105 +#elif defined(TEST_sigaltstack)
  106 + ss.ss_sp = (void *)(skaddr + sksize);
  107 + ss.ss_size = sksize;
  108 + ss.ss_flags = 0;
  109 + if (sigaltstack(&ss, NULL) < 0)
  110 + exit(1);
  111 +#endif
  112 + memset((void *)&sa, 0, sizeof(struct sigaction));
  113 + sa.sa_handler = handler;
  114 + sa.sa_flags = SA_ONSTACK;
  115 + sigemptyset(&sa.sa_mask);
  116 + sigaction(SIGUSR1, &sa, NULL);
  117 + kill(getpid(), SIGUSR1);
  118 + while (!handler_done)
  119 + /*nop*/;
  120 + }
  121 +#endif
  122 +#if defined(TEST_makecontext)
  123 + {
  124 + if (getcontext(&uc_handler) != 0)
  125 + exit(1);
  126 + uc_handler.uc_link = NULL;
  127 + uc_handler.uc_stack.ss_sp = (void *)(skaddr + sksize);
  128 + uc_handler.uc_stack.ss_size = sksize;
  129 + uc_handler.uc_stack.ss_flags = 0;
  130 + makecontext(&uc_handler, handler, 1);
  131 + swapcontext(&uc_main, &uc_handler);
  132 + }
  133 +#endif
  134 + if (handler_addr == (char *)0xDEAD)
  135 + exit(1);
  136 + if (handler_addr < skaddr+sksize) {
  137 + /* stack was placed into lower area */
  138 + if (*(skaddr+sksize) != 'A')
  139 + sprintf(result, "(skaddr)+(sksize)-%d,(sksize)-%d",
  140 + sizeof(union alltypes), sizeof(union alltypes));
  141 + else
  142 + strcpy(result, "(skaddr)+(sksize),(sksize)");
  143 + }
  144 + else {
  145 + /* stack was placed into higher area */
  146 + if (*(skaddr+sksize*2) != 'A')
  147 + sprintf(result, "(skaddr),(sksize)-%d", sizeof(union alltypes));
  148 + else
  149 + strcpy(result, "(skaddr),(sksize)");
  150 + }
  151 + printf("%s\n", result);
  152 + exit(0);
  153 +}
  154 +