GithubHelp home page GithubHelp logo

phargobikcin / greenlet Goto Github PK

View Code? Open in Web Editor NEW

This project forked from treeform/greenlet

0.0 0.0 0.0 232 KB

Greenlet - Coroutines library for nim similar to python's greenlet.

Nim 4.75% Makefile 13.44% Python 15.11% Batchfile 9.61% C++ 14.20% C 37.04% Assembly 5.85%

greenlet's Introduction

Greenlet - Coroutines library for nim simmilar to python's greenlet.

Greenlet tries to be a FAST!, easy to use and yet simple to understand and library for using flavor of coroutines called "greenlets".

Very simple to use

Only a 3 procs do most of the work:

  • newGreenlet()
  • g.switchTo()
  • g.destroy()

Only 2 extra convience procs to manage errors or gain speed:

  • g.inject()
  • g.reset()

And 5 getter procs to see state of things:

  • rootGreenlet()
  • currentGreenlet()
  • parentGreenlet()
  • g.started
  • g.dead

Example

import greenlet

var g = newGreenlet proc (arg: pointer): pointer =
  echo "in func1 (greenlet 1)"
  discard rootGreenlet().switchTo()
  echo "exiting func1 (greenlet 1)"
  return nil

echo "entering greenlet 1"
discard g.switchTo()

echo "re-entering greenlet 1"
discard g.switchTo() 

echo "exiting program"
g.destroy()

output:

entering greenlet 1
in func1 (greenlet 1)
re-entering greenlet 1
exiting func1 (greenlet 1)
exiting program

Very fast switching:

Compared to other coroutines methods:

Method million saves+restores/sec
getcontext/setcontext 0.97
sigsetjmp/siglongjmp 1.10
setjmp/longjmp 88.32
greenlet save/swtich 214.09

Compared to threads:

Method million context switches/sec
setjmp/longjmp 0.06
greenlet switch_to 27.39

Basaed on CGreenlet

It is based on the cgreenlet library: https://github.com/geertj/cgreenlet

Following is the explanation of how cgreenlet library works.

Platform portability

Greenlet requires 4 platform and/or architecture specific pieces of functionality in order to be able to offer coroutines:

  1. Thread-local storage.
  2. Stack allocation and deallocation
  3. Stack switching
  4. Context switching

For each platform that is supported, these 4 areas of functionality have to be provided. What follows now is an overview on how each of these are implemented:

Thread-local storage

Currently two approaches are supported. The fastest and preferred way is to use a __thread allocation class keyword on thread-local variables. This is available on Linux and on Windows. This if is not available (e.g. on Mac OSX), the pthread_getspecific() API is used.

Thread-local storage is implemented in "greenlet-system.c".

Allocation of the stack

On Unix-like systems, greenlet uses mmap() and on Windows, it uses VirtualAlloc(). The stack is protected with one PROT_NONE guard page. Stack allocation is implemented in "greenlet-system.c".

Stack switching

There is really no portably way to do this. On Unix-like platforms, we could use sigaltstack() + longjmp(), or the deprecated POSIX makecontext(). On Windows, the Fiber API could be used.

The approach that greenlet has taken is to implement an architecture specific function to switch stacks:

  void _greenlet_callnewstack(void *stack, void *(*func)(void *), void *arg);

This function will switch stack to stack, and call func(arg) on the new stack. The function may not return. If it does try to return, a SIGSEGV will be raised because we overwrite the return address to NULL. The way to get out of this function is to switch context to a parent of the current context (see next section).

This function is implemented in assembly in "greenlet-asm.S".

Context switching

A relatively portably way to implement this would be setjmp()/longjmp(). The function is available on Unix-like platforms and Windows. However the performance of these functions varies greatly, as on some platforms this saves the signal stack and on others it doesn't. Also, setjmp()/longjmp() do not allow you to inject code just before execution is resumed in the target. Code injection is needed to propagate exceptions.

The approach taken by greenlet is to provide a fast architecture specific implementation of setjmp()/longjmp():

  int _greenlet_setjmp_fast(void *frame);
  void _greenlet_longjmp_fast(void *frame, void (*inject_func)(void *),
                              void *arg);

These functions work just like setjmp()/longjmp() only that they are about 2x faster and allow for code injection.

These functios are implemented in assemlby in "greenlet-asm.S".

Contributing

Feel free to add an issue on the github site, or fork it and send me a merge request.

greenlet's People

Contributors

treeform avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.