Commit 2a359791 authored by Kirill Smelkov's avatar Kirill Smelkov

context: Move/Port context package to C++/Pyx nogil

Provide context-related functionality that can be used directly from C++
and Pyx/nogil codes. Python-level classes and functions become small
wrappers around pyx/nogil ones.

Like with timers (b073f6df "time: Move/Port timers to C++/Pyx nogil")
and interfaces (5a99b769 "libgolang: Start providing interfaces")
memory for objects dynamically allocated on heap is managed
automatically.
parent 9785f2d3
include COPYING README.rst CHANGELOG.rst tox.ini pyproject.toml trun
include golang/libgolang.h
include golang/runtime/libgolang.cpp
include golang/context.h
include golang/context.cpp
include golang/cxx.h
include golang/errors.h
include golang/errors.cpp
......
# cython: language_level=2
# Copyright (C) 2019 Nexedi SA and Contributors.
# Kirill Smelkov <kirr@nexedi.com>
#
# This program is free software: you can Use, Study, Modify and Redistribute
# it under the terms of the GNU General Public License version 3, or (at your
# option) any later version, as published by the Free Software Foundation.
#
# You can also Link and Combine this program with other software covered by
# the terms of any of the Free Software licenses or any of the Open Source
# Initiative approved licenses and Convey the resulting work. Corresponding
# source of such a combination shall include the source code for all other
# software used.
#
# This program is distributed WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#
# See COPYING file for full licensing terms.
# See https://www.nexedi.com/licensing for rationale and options.
"""Package context mirrors and amends Go package context.
- `Context` represents operational context that carries deadline, cancellation
signal and immutable context-local key -> value dict.
- `background` returns empty context that is never canceled.
- `with_cancel` creates new context that can be canceled on its own.
- `with_deadline` creates new context with deadline.
- `with_timeout` creates new context with timeout.
- `with_value` creates new context with attached key=value.
- `merge` creates new context from 2 parents(*).
See also https://golang.org/pkg/context for Go context package documentation.
See also https://blog.golang.org/context for overview.
(*) not provided in Go version.
"""
from golang cimport chan, structZ, error, refptr, interface
from golang cimport cxx
from libcpp.utility cimport pair
# XXX for std::function cython does not provide operator() and =nullptr
#from libcpp.functional cimport function
#ctypedef function[void()] cancelFunc
cdef extern from "<functional>" namespace "std" nogil:
cppclass cancelFunc "std::function<void()>":
void operator() ()
void operator= (nullptr_t)
cdef extern from "golang/context.h" namespace "golang::context" nogil:
cppclass _Context:
double deadline()
chan[structZ] done()
error err()
interface value(const void *key)
cppclass Context (refptr[_Context]):
# Context.X = Context->X in C++
double deadline "_ptr()->deadline" ()
chan[structZ] done "_ptr()->done" ()
error err "_ptr()->err" ()
interface value "_ptr()->value" (const void *key)
Context background()
error canceled
error deadlineExceeded
pair[Context, cancelFunc] with_cancel (Context parent)
Context with_value (Context parent, const void *key, interface value)
pair[Context, cancelFunc] with_deadline (Context parent, double deadline)
pair[Context, cancelFunc] with_timeout (Context parent, double timeout)
pair[Context, cancelFunc] merge (Context parent1, Context parent2)
# for testing
cxx.set[Context] _tctxchildren(Context ctx)
This diff is collapsed.
This diff is collapsed.
#ifndef _NXD_LIBGOLANG_CONTEXT_H
#define _NXD_LIBGOLANG_CONTEXT_H
// Copyright (C) 2019 Nexedi SA and Contributors.
// Kirill Smelkov <kirr@nexedi.com>
//
// This program is free software: you can Use, Study, Modify and Redistribute
// it under the terms of the GNU General Public License version 3, or (at your
// option) any later version, as published by the Free Software Foundation.
//
// You can also Link and Combine this program with other software covered by
// the terms of any of the Free Software licenses or any of the Open Source
// Initiative approved licenses and Convey the resulting work. Corresponding
// source of such a combination shall include the source code for all other
// software used.
//
// This program is distributed WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//
// See COPYING file for full licensing terms.
// See https://www.nexedi.com/licensing for rationale and options.
// Package context mirrors and amends Go package context.
//
// - `Context` represents operational context that carries deadline, cancellation
// signal and immutable context-local key -> value dict.
// - `background` returns empty context that is never canceled.
// - `with_cancel` creates new context that can be canceled on its own.
// - `with_deadline` creates new context with deadline.
// - `with_timeout` creates new context with timeout.
// - `with_value` creates new context with attached key=value.
// - `merge` creates new context from 2 parents(*).
//
// See also https://golang.org/pkg/context for Go context package documentation.
// See also https://blog.golang.org/context for overview.
//
// (*) not provided in Go version.
#include <golang/libgolang.h>
#include <golang/cxx.h>
// golang::context::
namespace golang {
namespace context {
// Context is the interface that every context must implement.
//
// A context carries deadline, cancellation signal and immutable context-local
// key -> value dict.
struct _Context : _interface {
// deadline() returns context deadline or +inf, if there is no deadline.
virtual double deadline() = 0; // -> time | INFINITY
// done returns channel that is closed when the context is canceled.
virtual chan<structZ> done() = 0;
// err returns nil if done is not yet closed, or error that explains why context was canceled.
virtual error err() = 0;
// value returns value associated with key, or nil, if context has no key.
virtual interface value(const void *key) = 0; // -> value | nil
};
typedef refptr<_Context> Context;
// background returns empty context that is never canceled.
LIBGOLANG_API Context background();
// canceled is the error returned by Context.err when context is canceled.
extern LIBGOLANG_API const error canceled;
// deadlineExceeded is the error returned by Context.err when time goes past context's deadline.
extern LIBGOLANG_API const error deadlineExceeded;
// with_cancel creates new context that can be canceled on its own.
//
// Returned context inherits from parent and in particular is canceled when
// parent is done.
//
// The caller should explicitly call cancel to release context resources as soon
// the context is no longer needed.
LIBGOLANG_API std::pair<Context, std::function<void()>>
with_cancel(Context parent); // -> ctx, cancel
// with_value creates new context with key=value.
//
// Returned context inherits from parent and in particular has all other
// (key, value) pairs provided by parent.
LIBGOLANG_API Context
with_value(Context parent, const void *key, interface value); // -> ctx
// with_deadline creates new context with deadline.
//
// The deadline of created context is the earliest of provided deadline or
// deadline of parent. Created context will be canceled when time goes past
// context deadline or cancel called, whichever happens first.
//
// The caller should explicitly call cancel to release context resources as soon
// the context is no longer needed.
LIBGOLANG_API std::pair<Context, std::function<void()>>
with_deadline(Context parent, double deadline); // -> ctx, cancel
// with_timeout creates new context with timeout.
//
// it is shorthand for with_deadline(parent, now+timeout).
LIBGOLANG_API std::pair<Context, std::function<void()>>
with_timeout(Context parent, double timeout); // -> ctx, cancel
// merge merges 2 contexts into 1.
//
// The result context:
//
// - is done when parent1 or parent2 is done, or cancel called, whichever happens first,
// - has deadline = min(parent1.Deadline, parent2.Deadline),
// - has associated values merged from parent1 and parent2, with parent1 taking precedence.
//
// Canceling this context releases resources associated with it, so code should
// call cancel as soon as the operations running in this Context complete.
//
// Note: on Go side merge is not part of stdlib context and is provided by
// https://godoc.org/lab.nexedi.com/kirr/go123/xcontext#hdr-Merging_contexts
LIBGOLANG_API std::pair<Context, std::function<void()>>
merge(Context parent1, Context parent2); // -> ctx, cancel
// for testing
LIBGOLANG_API cxx::set<Context> _tctxchildren(Context ctx);
}} // golang::context::
#endif // _NXD_LIBGOLANG_CONTEXT_H
# cython: language_level=2
# Copyright (C) 2019 Nexedi SA and Contributors.
# Kirill Smelkov <kirr@nexedi.com>
#
# This program is free software: you can Use, Study, Modify and Redistribute
# it under the terms of the GNU General Public License version 3, or (at your
# option) any later version, as published by the Free Software Foundation.
#
# You can also Link and Combine this program with other software covered by
# the terms of any of the Free Software licenses or any of the Open Source
# Initiative approved licenses and Convey the resulting work. Corresponding
# source of such a combination shall include the source code for all other
# software used.
#
# This program is distributed WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#
# See COPYING file for full licensing terms.
# See https://www.nexedi.com/licensing for rationale and options.
"""Package context mirrors and amends Go package context.
See _context.pxd for package documentation.
"""
# redirect cimport: golang.context -> golang._context (see __init__.pxd for rationale)
from golang._context cimport *
......@@ -20,18 +20,19 @@
from __future__ import print_function, absolute_import
from golang import context, _context, time, nilchan
from golang._context import _tctxchildren as tctxchildren, _ready as ready
from golang import nilchan, select, default
from golang import context, _context, time
from golang._context import _tctxAssertChildren as tctxAssertChildren
from golang.time_test import dt
# assertCtx asserts on state of _BaseCtx*
def assertCtx(ctx, children, deadline=None, err=None, done=False):
assert isinstance(ctx, _context._BaseCtx)
assert isinstance(ctx, _context.PyContext)
assert ctx.deadline() == deadline
assert ctx.err() is err
ctxdone = ctx.done()
assert ready(ctxdone) == done
assert tctxchildren(ctx) == children
tctxAssertChildren(ctx, children)
for i in range(10): # repeated .done() returns the same pyobject
assert ctx.done() is ctxdone
......@@ -262,3 +263,17 @@ def test_deadline():
time.sleep(11*dt)
assertCtx(ctx, Z, deadline=d, err=D, done=Y)
# ---- misc ----
# _ready returns whether channel ch is ready.
def ready(ch):
_, _rx = select(
ch.recv, # 0
default, # 1
)
if _ == 0:
return True
if _ == 1:
return False
......@@ -166,6 +166,9 @@ def Extension(name, sources, **kw):
dependv.append('%s/golang/libgolang.h' % pygo)
dependv.append('%s/golang/_golang.pxd' % pygo)
dependv.append('%s/golang/__init__.pxd' % pygo)
dependv.append('%s/golang/context.h' % pygo)
dependv.append('%s/golang/context.pxd' % pygo)
dependv.append('%s/golang/_context.pxd' % pygo)
dependv.append('%s/golang/cxx.h' % pygo)
dependv.append('%s/golang/cxx.pxd' % pygo)
dependv.append('%s/golang/errors.h' % pygo)
......
......@@ -193,11 +193,13 @@ setup(
x_dsos = [DSO('golang.runtime.libgolang',
['golang/runtime/libgolang.cpp',
'golang/context.cpp',
'golang/errors.cpp',
'golang/sync.cpp',
'golang/time.cpp'],
depends = [
'golang/libgolang.h',
'golang/context.h',
'golang/cxx.h',
'golang/errors.h',
'golang/sync.h',
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment