Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
C
capnproto
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
capnproto
Commits
edbc2a5a
Commit
edbc2a5a
authored
Oct 12, 2013
by
Kenton Varda
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
IT WOOOORRRKKSS: Local capabilities, including pipelining. Now we just need an RPC protocol...
parent
f566cd4d
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
394 additions
and
114 deletions
+394
-114
arena.c++
c++/src/capnp/arena.c++
+9
-9
arena.h
c++/src/capnp/arena.h
+8
-7
capability-test.c++
c++/src/capnp/capability-test.c++
+83
-10
capability.c++
c++/src/capnp/capability.c++
+0
-0
capability.h
c++/src/capnp/capability.h
+40
-71
common.h
c++/src/capnp/common.h
+2
-0
capnpc-c++.c++
c++/src/capnp/compiler/capnpc-c++.c++
+84
-9
grammar.capnp.h
c++/src/capnp/compiler/grammar.capnp.h
+0
-0
lexer.capnp.h
c++/src/capnp/compiler/lexer.capnp.h
+56
-0
layout.c++
c++/src/capnp/layout.c++
+1
-1
object.c++
c++/src/capnp/object.c++
+29
-0
object.h
c++/src/capnp/object.h
+68
-1
orphan.h
c++/src/capnp/orphan.h
+4
-4
schema.capnp.h
c++/src/capnp/schema.capnp.h
+0
-0
test.capnp
c++/src/capnp/test.capnp
+4
-0
async.c++
c++/src/kj/async.c++
+6
-2
No files found.
c++/src/capnp/arena.c++
View file @
edbc2a5a
...
...
@@ -35,9 +35,6 @@
namespace
capnp
{
namespace
_
{
// private
Arena
::~
Arena
()
noexcept
(
false
)
{}
BuilderArena
::~
BuilderArena
()
noexcept
(
false
)
{}
namespace
{
class
BrokenPipeline
final
:
public
PipelineHook
,
public
kj
::
Refcounted
{
...
...
@@ -110,10 +107,13 @@ kj::Own<const ClientHook> BrokenPipeline::getPipelinedCap(
}
// namespace
kj
::
Own
<
const
ClientHook
>
Arena
::
extractNullCap
(
)
{
return
kj
::
refcounted
<
BrokenClient
>
(
"Calling null capability pointer."
);
kj
::
Own
<
const
ClientHook
>
newBrokenCap
(
const
char
*
reason
)
{
return
kj
::
refcounted
<
BrokenClient
>
(
reason
);
}
Arena
::~
Arena
()
noexcept
(
false
)
{}
BuilderArena
::~
BuilderArena
()
noexcept
(
false
)
{}
void
ReadLimiter
::
unread
(
WordCount64
amount
)
{
// Be careful not to overflow here. Since ReadLimiter has no thread-safety, it's possible that
// the limit value was not updated correctly for one or more reads, and therefore unread() could
...
...
@@ -180,7 +180,7 @@ void BasicReaderArena::reportReadLimitReached() {
kj
::
Own
<
const
ClientHook
>
BasicReaderArena
::
extractCap
(
const
_
::
StructReader
&
capDescriptor
)
{
KJ_FAIL_REQUIRE
(
"Message contained a capability but is not imbued with a capability context."
)
{
return
kj
::
heap
<
BrokenClient
>
(
return
newBrokenCap
(
"Calling capability extracted from message that was not imbued with a capability "
"context."
);
}
...
...
@@ -406,7 +406,7 @@ SegmentBuilder* ImbuedBuilderArena::imbue(SegmentBuilder* baseSegment) {
if
(
baseSegment
->
getSegmentId
()
==
SegmentId
(
0
))
{
if
(
segment0
.
getArena
()
==
nullptr
)
{
kj
::
dtor
(
segment0
);
kj
::
ctor
(
segment0
,
baseSegment
);
kj
::
ctor
(
segment0
,
this
,
baseSegment
);
}
result
=
&
segment0
;
}
else
{
...
...
@@ -419,7 +419,7 @@ SegmentBuilder* ImbuedBuilderArena::imbue(SegmentBuilder* baseSegment) {
KJ_IF_MAYBE
(
segment
,
segmentState
->
get
()
->
builders
[
id
])
{
result
=
*
segment
;
}
else
{
auto
newBuilder
=
kj
::
heap
<
ImbuedSegmentBuilder
>
(
baseSegment
);
auto
newBuilder
=
kj
::
heap
<
ImbuedSegmentBuilder
>
(
this
,
baseSegment
);
result
=
newBuilder
;
segmentState
->
get
()
->
builders
[
id
]
=
kj
::
mv
(
newBuilder
);
}
...
...
@@ -448,7 +448,7 @@ SegmentBuilder* ImbuedBuilderArena::getSegment(SegmentId id) {
}
BuilderArena
::
AllocateResult
ImbuedBuilderArena
::
allocate
(
WordCount
amount
)
{
auto
result
=
allocate
(
amount
);
auto
result
=
base
->
allocate
(
amount
);
result
.
segment
=
imbue
(
result
.
segment
);
return
result
;
}
...
...
c++/src/capnp/arena.h
View file @
edbc2a5a
...
...
@@ -57,6 +57,11 @@ class ReadLimiter;
class
Segment
;
typedef
kj
::
Id
<
uint32_t
,
Segment
>
SegmentId
;
kj
::
Own
<
const
ClientHook
>
newBrokenCap
(
const
char
*
reason
);
// Helper function that creates a capability which simply throws exceptions when called.
// Implemented in arena.c++ rather than capability.c++ because it is needed by layout.c++ and we
// don't want capability.c++ to be required by people not using caps.
class
ReadLimiter
{
// Used to keep track of how much data has been processed from a message, and cut off further
// processing if and when a particular limit is reached. This is primarily intended to guard
...
...
@@ -167,7 +172,7 @@ private:
class
ImbuedSegmentBuilder
:
public
SegmentBuilder
{
public
:
inline
ImbuedSegmentBuilder
(
SegmentBuilder
*
base
);
inline
ImbuedSegmentBuilder
(
ImbuedBuilderArena
*
arena
,
SegmentBuilder
*
base
);
inline
ImbuedSegmentBuilder
(
decltype
(
nullptr
));
KJ_DISALLOW_COPY
(
ImbuedSegmentBuilder
);
...
...
@@ -188,10 +193,6 @@ public:
virtual
kj
::
Own
<
const
ClientHook
>
extractCap
(
const
_
::
StructReader
&
capDescriptor
)
=
0
;
// Given a StructReader for a capability descriptor embedded in the message, return the
// corresponding capability.
kj
::
Own
<
const
ClientHook
>
extractNullCap
();
// Like extractCap() but called when the pointer was null. This just returns a dummy capability
// that throws exceptions on any call.
};
class
BasicReaderArena
final
:
public
Arena
{
...
...
@@ -444,8 +445,8 @@ inline BasicSegmentBuilder::BasicSegmentBuilder(
:
SegmentBuilder
(
arena
,
id
,
ptr
,
readLimiter
,
&
actualPos
),
actualPos
(
ptr
.
begin
())
{}
inline
ImbuedSegmentBuilder
::
ImbuedSegmentBuilder
(
SegmentBuilder
*
base
)
:
SegmentBuilder
(
static_cast
<
BuilderArena
*>
(
base
->
arena
)
,
base
->
id
,
inline
ImbuedSegmentBuilder
::
ImbuedSegmentBuilder
(
ImbuedBuilderArena
*
arena
,
SegmentBuilder
*
base
)
:
SegmentBuilder
(
arena
,
base
->
id
,
kj
::
arrayPtr
(
const_cast
<
word
*>
(
base
->
ptr
.
begin
()),
base
->
ptr
.
size
()),
base
->
readLimiter
,
base
->
pos
)
{}
inline
ImbuedSegmentBuilder
::
ImbuedSegmentBuilder
(
decltype
(
nullptr
))
...
...
c++/src/capnp/capability-test.c++
View file @
edbc2a5a
...
...
@@ -21,6 +21,18 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "schema.capnp.h"
#ifdef CAPNP_CAPABILITY_H_
#error "schema.capnp should not depend on capability.h, because it contains no interfaces."
#endif
#include "test.capnp.h"
#ifndef CAPNP_CAPABILITY_H_
#error "test.capnp did not include capability.h."
#endif
#include "capability.h"
#include "test-util.h"
#include <kj/debug.h>
...
...
@@ -36,9 +48,9 @@ public:
int
&
callCount
;
virtual
::
kj
::
Promise
<
void
>
foo
(
::
kj
::
Promise
<
void
>
foo
(
test
::
TestInterface
::
FooParams
::
Reader
params
,
test
::
TestInterface
::
FooResults
::
Builder
result
)
{
test
::
TestInterface
::
FooResults
::
Builder
result
)
override
{
++
callCount
;
EXPECT_EQ
(
123
,
params
.
getI
());
EXPECT_TRUE
(
params
.
getJ
());
...
...
@@ -46,9 +58,9 @@ public:
return
kj
::
READY_NOW
;
}
virtual
::
kj
::
Promise
<
void
>
bazAdvanced
(
::
kj
::
Promise
<
void
>
bazAdvanced
(
::
capnp
::
CallContext
<
test
::
TestInterface
::
BazParams
,
test
::
TestInterface
::
BazResults
>
context
)
{
test
::
TestInterface
::
BazResults
>
context
)
override
{
++
callCount
;
auto
params
=
context
.
getParams
();
checkTestMessage
(
params
.
getS
());
...
...
@@ -64,7 +76,7 @@ public:
TEST
(
Capability
,
Basic
)
{
kj
::
SimpleEventLoop
loop
;
int
callCount
;
int
callCount
=
0
;
test
::
TestInterface
::
Client
client
(
makeLocalClient
(
kj
::
heap
<
TestInterfaceImpl
>
(
callCount
),
loop
));
auto
request1
=
client
.
fooRequest
();
...
...
@@ -103,9 +115,9 @@ public:
int
&
callCount
;
virtual
::
kj
::
Promise
<
void
>
foo
(
::
kj
::
Promise
<
void
>
foo
(
test
::
TestInterface
::
FooParams
::
Reader
params
,
test
::
TestInterface
::
FooResults
::
Builder
result
)
{
test
::
TestInterface
::
FooResults
::
Builder
result
)
override
{
++
callCount
;
EXPECT_EQ
(
321
,
params
.
getI
());
EXPECT_FALSE
(
params
.
getJ
());
...
...
@@ -113,8 +125,8 @@ public:
return
kj
::
READY_NOW
;
}
virtual
::
kj
::
Promise
<
void
>
graultAdvanced
(
::
capnp
::
CallContext
<
test
::
TestExtends
::
GraultParams
,
test
::
TestAllTypes
>
context
)
{
::
kj
::
Promise
<
void
>
graultAdvanced
(
::
capnp
::
CallContext
<
test
::
TestExtends
::
GraultParams
,
test
::
TestAllTypes
>
context
)
override
{
++
callCount
;
context
.
releaseParams
();
...
...
@@ -127,7 +139,7 @@ public:
TEST
(
Capability
,
Inheritance
)
{
kj
::
SimpleEventLoop
loop
;
int
callCount
;
int
callCount
=
0
;
test
::
TestExtends
::
Client
client
(
makeLocalClient
(
kj
::
heap
<
TestExtendsImpl
>
(
callCount
),
loop
));
auto
request1
=
client
.
fooRequest
();
...
...
@@ -150,6 +162,67 @@ TEST(Capability, Inheritance) {
EXPECT_EQ
(
2
,
callCount
);
}
class
TestPipelineImpl
final
:
public
test
::
TestPipeline
::
Server
{
public
:
TestPipelineImpl
(
int
&
callCount
)
:
callCount
(
callCount
)
{}
int
&
callCount
;
::
kj
::
Promise
<
void
>
getCapAdvanced
(
capnp
::
CallContext
<
test
::
TestPipeline
::
GetCapParams
,
test
::
TestPipeline
::
GetCapResults
>
context
)
override
{
++
callCount
;
auto
params
=
context
.
getParams
();
EXPECT_EQ
(
"foo"
,
params
.
getS
());
auto
cap
=
params
.
getInCap
();
context
.
releaseParams
();
auto
request
=
cap
.
fooRequest
();
request
.
setI
(
123
);
request
.
setJ
(
true
);
return
request
.
send
().
then
(
[
this
,
context
](
capnp
::
Response
<
test
::
TestInterface
::
FooResults
>&&
response
)
mutable
{
EXPECT_EQ
(
"foo"
,
response
.
getX
());
auto
result
=
context
.
getResults
();
result
.
setN
(
234
);
result
.
setOutCap
(
test
::
TestExtends
::
Client
(
makeLocalClient
(
kj
::
heap
<
TestExtendsImpl
>
(
callCount
))));
});
}
};
TEST
(
Capability
,
Pipelining
)
{
kj
::
SimpleEventLoop
loop
;
int
callCount
=
0
;
int
chainedCallCount
=
0
;
test
::
TestPipeline
::
Client
client
(
makeLocalClient
(
kj
::
heap
<
TestPipelineImpl
>
(
callCount
),
loop
));
auto
request
=
client
.
getCapRequest
();
request
.
setS
(
"foo"
);
request
.
setInCap
(
test
::
TestInterface
::
Client
(
makeLocalClient
(
kj
::
heap
<
TestInterfaceImpl
>
(
chainedCallCount
),
loop
)));
auto
promise
=
request
.
send
();
auto
pipelineRequest
=
promise
.
getOutCap
().
fooRequest
();
pipelineRequest
.
setI
(
321
);
auto
pipelinePromise
=
pipelineRequest
.
send
();
EXPECT_EQ
(
0
,
callCount
);
EXPECT_EQ
(
0
,
chainedCallCount
);
auto
response
=
loop
.
wait
(
kj
::
mv
(
pipelinePromise
));
EXPECT_EQ
(
"bar"
,
response
.
getX
());
EXPECT_EQ
(
2
,
callCount
);
EXPECT_EQ
(
1
,
chainedCallCount
);
}
}
// namespace
}
// namespace _
}
// namespace capnp
c++/src/capnp/capability.c++
View file @
edbc2a5a
This diff is collapsed.
Click to expand it.
c++/src/capnp/capability.h
View file @
edbc2a5a
...
...
@@ -26,6 +26,7 @@
#include <kj/async.h>
#include "object.h"
#include "pointer-helpers.h"
namespace
capnp
{
...
...
@@ -133,6 +134,9 @@ public:
private
:
kj
::
Own
<
const
ClientHook
>
hook
;
template
<
typename
,
::
capnp
::
Kind
>
friend
struct
::
capnp
::
_
::
PointerHelpers
;
protected
:
Client
()
=
default
;
...
...
@@ -148,7 +152,7 @@ class CallContextHook;
template
<
typename
Params
,
typename
Results
>
class
CallContext
:
public
kj
::
DisallowConstCopy
{
// Wrapper around
TypelessCallContext
with a specific return type.
// Wrapper around
CallContextHook
with a specific return type.
//
// Methods of this class may only be called from within the server's event loop, not from other
// threads.
...
...
@@ -246,51 +250,6 @@ kj::Own<const ClientHook> makeLocalClient(kj::Own<Capability::Server>&& server,
//
// TODO(now): Templated version or something.
// =======================================================================================
struct
PipelineOp
{
enum
Type
{
GET_POINTER_FIELD
// There may be other types in the future...
};
Type
type
;
union
{
uint16_t
pointerIndex
;
// for GET_POINTER_FIELD
};
};
struct
TypelessResults
{
// Result of a call, before it has been type-wrapped. Designed to be used as
// RemotePromise<CallResult>.
typedef
ObjectPointer
::
Reader
Reader
;
// So RemotePromise<CallResult> resolves to Own<ObjectPointer::Reader>.
class
Pipeline
{
public
:
inline
explicit
Pipeline
(
kj
::
Own
<
const
PipelineHook
>&&
hook
)
:
hook
(
kj
::
mv
(
hook
))
{}
Pipeline
getPointerField
(
uint16_t
pointerIndex
)
const
;
// Return a new Promise representing a sub-object of the result. `pointerIndex` is the index
// of the sub-object within the pointer section of the result (the result must be a struct).
//
// TODO(kenton): On GCC 4.8 / Clang 3.3, use rvalue qualifiers to avoid the need for copies.
// Also make `ops` into a Vector to optimize this.
Capability
::
Client
asCap
()
const
;
// Expect that the result is a capability and construct a pipelined version of it now.
private
:
kj
::
Own
<
const
PipelineHook
>
hook
;
kj
::
Array
<
PipelineOp
>
ops
;
inline
Pipeline
(
kj
::
Own
<
const
PipelineHook
>&&
hook
,
kj
::
Array
<
PipelineOp
>&&
ops
)
:
hook
(
kj
::
mv
(
hook
)),
ops
(
kj
::
mv
(
ops
))
{}
};
};
// =======================================================================================
// Hook interfaces which must be implemented by the RPC system. Applications never call these
// directly; the RPC system implements them and the types defined earlier in this file wrap them.
...
...
@@ -299,7 +258,7 @@ class RequestHook {
// Hook interface implemented by RPC system representing a request being built.
public
:
virtual
RemotePromise
<
TypelessResults
>
send
()
=
0
;
virtual
RemotePromise
<
ObjectPointer
>
send
()
=
0
;
// Send the call and return a promise for the result.
};
...
...
@@ -314,26 +273,11 @@ public:
// Just here to make sure the type is dynamic.
};
class
PipelineHook
{
// Represents a currently-running call, and implements pipelined requests on its result.
public
:
virtual
kj
::
Own
<
const
PipelineHook
>
addRef
()
const
=
0
;
// Increment this object's reference count.
virtual
kj
::
Own
<
const
ClientHook
>
getPipelinedCap
(
kj
::
ArrayPtr
<
const
PipelineOp
>
ops
)
const
=
0
;
// Extract a promised Capability from the results.
virtual
kj
::
Own
<
const
ClientHook
>
getPipelinedCap
(
kj
::
Array
<
PipelineOp
>&&
ops
)
const
{
// Version of getPipelinedCap() passing the array by move. May avoid a copy in some cases.
// Default implementation just calls the other version.
return
getPipelinedCap
(
ops
.
asPtr
());
}
};
// class PipelineHook is declared in object.h because it is needed there.
class
ClientHook
{
public
:
virtual
Request
<
ObjectPointer
,
TypelessResults
>
newCall
(
virtual
Request
<
ObjectPointer
,
ObjectPointer
>
newCall
(
uint64_t
interfaceId
,
uint16_t
methodId
,
uint
firstSegmentWordSize
)
const
=
0
;
// Start a new call, allowing the client to allocate request/response objects as it sees fit.
// This version is used when calls are made from application code in the local process.
...
...
@@ -386,6 +330,35 @@ public:
virtual
kj
::
Own
<
CallContextHook
>
addRef
()
=
0
;
};
kj
::
Own
<
const
ClientHook
>
newBrokenCap
(
const
char
*
reason
);
// Helper function that creates a capability which simply throws exceptions when called.
// =======================================================================================
// Extend PointerHelpers for interfaces
namespace
_
{
// private
template
<
typename
T
>
struct
PointerHelpers
<
T
,
Kind
::
INTERFACE
>
{
static
inline
typename
T
::
Client
get
(
PointerReader
reader
)
{
return
typename
T
::
Client
(
reader
.
getCapability
());
}
static
inline
typename
T
::
Client
get
(
PointerBuilder
builder
)
{
return
typename
T
::
Client
(
builder
.
getCapability
());
}
static
inline
void
set
(
PointerBuilder
builder
,
typename
T
::
Client
&&
value
)
{
builder
.
setCapability
(
kj
::
mv
(
value
.
Capability
::
Client
::
hook
));
}
static
inline
void
adopt
(
PointerBuilder
builder
,
Orphan
<
T
>&&
value
)
{
builder
.
adopt
(
kj
::
mv
(
value
.
builder
));
}
static
inline
Orphan
<
T
>
disown
(
PointerBuilder
builder
)
{
return
Orphan
<
T
>
(
builder
.
disown
());
}
};
}
// namespace _ (private)
// =======================================================================================
// Inline implementation details
...
...
@@ -396,22 +369,18 @@ RemotePromise<Results> Request<Params, Results>::send() {
// Convert the Promise to return the correct response type.
// Explicitly upcast to kj::Promise to make clear that calling .then() doesn't invalidate the
// Pipeline part of the RemotePromise.
auto
typedPromise
=
kj
::
implicitCast
<
kj
::
Promise
<
Response
<
TypelessResults
>>&>
(
typelessPromise
)
.
thenInAnyThread
([](
Response
<
TypelessResults
>&&
response
)
->
Response
<
Results
>
{
auto
typedPromise
=
kj
::
implicitCast
<
kj
::
Promise
<
Response
<
ObjectPointer
>>&>
(
typelessPromise
)
.
thenInAnyThread
([](
Response
<
ObjectPointer
>&&
response
)
->
Response
<
Results
>
{
return
Response
<
Results
>
(
response
.
getAs
<
Results
>
(),
kj
::
mv
(
response
.
hook
));
});
// Wrap the typeless pipeline in a typed wrapper.
typename
Results
::
Pipeline
typedPipeline
(
kj
::
mv
(
kj
::
implicitCast
<
TypelessResults
::
Pipeline
&>
(
typelessPromise
)));
kj
::
mv
(
kj
::
implicitCast
<
ObjectPointer
::
Pipeline
&>
(
typelessPromise
)));
return
RemotePromise
<
Results
>
(
kj
::
mv
(
typedPromise
),
kj
::
mv
(
typedPipeline
));
}
inline
Capability
::
Client
TypelessResults
::
Pipeline
::
asCap
()
const
{
return
Capability
::
Client
(
hook
->
getPipelinedCap
(
ops
));
}
inline
Capability
::
Client
::
Client
(
kj
::
Own
<
const
ClientHook
>&&
hook
)
:
hook
(
kj
::
mv
(
hook
))
{}
inline
Capability
::
Client
::
Client
(
const
Client
&
other
)
:
hook
(
other
.
hook
->
addRef
())
{}
inline
Capability
::
Client
&
Capability
::
Client
::
operator
=
(
const
Client
&
other
)
{
...
...
c++/src/capnp/common.h
View file @
edbc2a5a
...
...
@@ -110,12 +110,14 @@ template <typename T, Kind k> struct Kind_<List<T, k>> { static constexpr Kind k
template
<
typename
T
,
Kind
k
=
kind
<
T
>
()
>
struct
ReaderFor_
{
typedef
typename
T
::
Reader
Type
;
};
template
<
typename
T
>
struct
ReaderFor_
<
T
,
Kind
::
PRIMITIVE
>
{
typedef
T
Type
;
};
template
<
typename
T
>
struct
ReaderFor_
<
T
,
Kind
::
ENUM
>
{
typedef
T
Type
;
};
template
<
typename
T
>
struct
ReaderFor_
<
T
,
Kind
::
INTERFACE
>
{
typedef
typename
T
::
Client
Type
;
};
template
<
typename
T
>
using
ReaderFor
=
typename
ReaderFor_
<
T
>::
Type
;
// The type returned by List<T>::Reader::operator[].
template
<
typename
T
,
Kind
k
=
kind
<
T
>
()
>
struct
BuilderFor_
{
typedef
typename
T
::
Builder
Type
;
};
template
<
typename
T
>
struct
BuilderFor_
<
T
,
Kind
::
PRIMITIVE
>
{
typedef
T
Type
;
};
template
<
typename
T
>
struct
BuilderFor_
<
T
,
Kind
::
ENUM
>
{
typedef
T
Type
;
};
template
<
typename
T
>
struct
BuilderFor_
<
T
,
Kind
::
INTERFACE
>
{
typedef
typename
T
::
Client
Type
;
};
template
<
typename
T
>
using
BuilderFor
=
typename
BuilderFor_
<
T
>::
Type
;
// The type returned by List<T>::Builder::operator[].
...
...
c++/src/capnp/compiler/capnpc-c++.c++
View file @
edbc2a5a
...
...
@@ -571,7 +571,8 @@ private:
" inline "
,
titleCase
,
"::Builder init"
,
titleCase
,
"();
\n
"
"
\n
"
),
kj
::
strTree
(),
proto
.
hasDiscriminantValue
()
?
kj
::
strTree
()
:
kj
::
strTree
(
" inline "
,
titleCase
,
"::Pipeline get"
,
titleCase
,
"() const;
\n
"
),
kj
::
strTree
(
kj
::
mv
(
unionDiscrim
.
isDefs
),
...
...
@@ -620,7 +621,11 @@ private:
"inline "
,
scope
,
titleCase
,
"::Builder "
,
scope
,
"Builder::get"
,
titleCase
,
"() {
\n
"
,
unionDiscrim
.
check
,
" return "
,
scope
,
titleCase
,
"::Builder(_builder);
\n
"
"}
\n
"
"}
\n
"
,
proto
.
hasDiscriminantValue
()
?
kj
::
strTree
()
:
kj
::
strTree
(
"inline "
,
scope
,
titleCase
,
"::Pipeline "
,
scope
,
"Pipeline::get"
,
titleCase
,
"() const {
\n
"
,
" return "
,
scope
,
titleCase
,
"::Pipeline(_typeless.noop());
\n
"
"}
\n
"
),
"inline "
,
scope
,
titleCase
,
"::Builder "
,
scope
,
"Builder::init"
,
titleCase
,
"() {
\n
"
,
unionDiscrim
.
set
,
KJ_MAP
(
slot
,
slots
)
{
...
...
@@ -810,8 +815,68 @@ private:
};
}
else
if
(
kind
==
FieldKind
::
INTERFACE
)
{
// Not implemented.
return
FieldText
{
kj
::
strTree
(),
kj
::
strTree
(),
kj
::
strTree
(),
kj
::
strTree
()
};
return
FieldText
{
kj
::
strTree
(
kj
::
mv
(
unionDiscrim
.
readerIsDecl
),
" inline bool has"
,
titleCase
,
"() const;
\n
"
" inline "
,
type
,
"::Client get"
,
titleCase
,
"() const;
\n
"
"
\n
"
),
kj
::
strTree
(
kj
::
mv
(
unionDiscrim
.
builderIsDecl
),
" inline bool has"
,
titleCase
,
"();
\n
"
" inline "
,
type
,
"::Client get"
,
titleCase
,
"();
\n
"
" inline void set"
,
titleCase
,
"("
,
type
,
"::Client&& value);
\n
"
,
" inline void adopt"
,
titleCase
,
"(::capnp::Orphan<"
,
type
,
">&& value);
\n
"
" inline ::capnp::Orphan<"
,
type
,
"> disown"
,
titleCase
,
"();
\n
"
"
\n
"
),
kj
::
strTree
(
proto
.
hasDiscriminantValue
()
?
kj
::
strTree
()
:
kj
::
strTree
(
" inline "
,
type
,
"::Client get"
,
titleCase
,
"() const;
\n
"
)),
kj
::
strTree
(
kj
::
mv
(
unionDiscrim
.
isDefs
),
"inline bool "
,
scope
,
"Reader::has"
,
titleCase
,
"() const {
\n
"
,
unionDiscrim
.
has
,
" return !_reader.getPointerField("
,
offset
,
" * ::capnp::POINTERS).isNull();
\n
"
"}
\n
"
"inline bool "
,
scope
,
"Builder::has"
,
titleCase
,
"() {
\n
"
,
unionDiscrim
.
has
,
" return !_builder.getPointerField("
,
offset
,
" * ::capnp::POINTERS).isNull();
\n
"
"}
\n
"
"inline "
,
type
,
"::Client "
,
scope
,
"Reader::get"
,
titleCase
,
"() const {
\n
"
,
unionDiscrim
.
check
,
" return ::capnp::_::PointerHelpers<"
,
type
,
">::get(
\n
"
" _reader.getPointerField("
,
offset
,
" * ::capnp::POINTERS));
\n
"
"}
\n
"
"inline "
,
type
,
"::Client "
,
scope
,
"Builder::get"
,
titleCase
,
"() {
\n
"
,
unionDiscrim
.
check
,
" return ::capnp::_::PointerHelpers<"
,
type
,
">::get(
\n
"
" _builder.getPointerField("
,
offset
,
" * ::capnp::POINTERS));
\n
"
"}
\n
"
,
proto
.
hasDiscriminantValue
()
?
kj
::
strTree
()
:
kj
::
strTree
(
"inline "
,
type
,
"::Client "
,
scope
,
"Pipeline::get"
,
titleCase
,
"() const {
\n
"
,
" return "
,
type
,
"::Client(_typeless.getPointerField("
,
offset
,
").asCap());
\n
"
"}
\n
"
),
"inline void "
,
scope
,
"Builder::set"
,
titleCase
,
"("
,
type
,
"::Client&& cap) {
\n
"
,
unionDiscrim
.
set
,
" ::capnp::_::PointerHelpers<"
,
type
,
">::set(
\n
"
" _builder.getPointerField("
,
offset
,
" * ::capnp::POINTERS), kj::mv(cap));
\n
"
"}
\n
"
,
"inline void "
,
scope
,
"Builder::adopt"
,
titleCase
,
"(
\n
"
" ::capnp::Orphan<"
,
type
,
">&& value) {
\n
"
,
unionDiscrim
.
set
,
" ::capnp::_::PointerHelpers<"
,
type
,
">::adopt(
\n
"
" _builder.getPointerField("
,
offset
,
" * ::capnp::POINTERS), kj::mv(value));
\n
"
"}
\n
"
"inline ::capnp::Orphan<"
,
type
,
"> "
,
scope
,
"Builder::disown"
,
titleCase
,
"() {
\n
"
,
unionDiscrim
.
check
,
" return ::capnp::_::PointerHelpers<"
,
type
,
">::disown(
\n
"
" _builder.getPointerField("
,
offset
,
" * ::capnp::POINTERS));
\n
"
"}
\n
"
"
\n
"
)
};
}
else
if
(
kind
==
FieldKind
::
OBJECT
)
{
return
FieldText
{
...
...
@@ -932,7 +997,11 @@ private:
" inline ::capnp::Orphan<"
,
type
,
"> disown"
,
titleCase
,
"();
\n
"
"
\n
"
),
kj
::
strTree
(),
kj
::
strTree
(
kind
==
FieldKind
::
STRUCT
&&
!
proto
.
hasDiscriminantValue
()
?
kj
::
strTree
(
" inline "
,
type
,
"::Pipeline get"
,
titleCase
,
"() const;
\n
"
)
:
kj
::
strTree
()),
kj
::
strTree
(
kj
::
mv
(
unionDiscrim
.
isDefs
),
...
...
@@ -953,7 +1022,13 @@ private:
unionDiscrim
.
check
,
" return ::capnp::_::PointerHelpers<"
,
type
,
">::get(
\n
"
" _builder.getPointerField("
,
offset
,
" * ::capnp::POINTERS)"
,
defaultParam
,
");
\n
"
"}
\n
"
"}
\n
"
,
kind
==
FieldKind
::
STRUCT
&&
!
proto
.
hasDiscriminantValue
()
?
kj
::
strTree
(
"inline "
,
type
,
"::Pipeline "
,
scope
,
"Pipeline::get"
,
titleCase
,
"() const {
\n
"
,
" return "
,
type
,
"::Pipeline(_typeless.getPointerField("
,
offset
,
"));
\n
"
"}
\n
"
)
:
kj
::
strTree
(),
"inline void "
,
scope
,
"Builder::set"
,
titleCase
,
"("
,
type
,
"::Reader value) {
\n
"
,
unionDiscrim
.
set
,
" ::capnp::_::PointerHelpers<"
,
type
,
">::set(
\n
"
...
...
@@ -1079,12 +1154,12 @@ private:
"public:
\n
"
" typedef "
,
unqualifiedParentType
,
" Pipelines;
\n
"
"
\n
"
" inline explicit Pipeline(::capnp::
TypelessResults
::Pipeline&& typeless)
\n
"
" inline explicit Pipeline(::capnp::
ObjectPointer
::Pipeline&& typeless)
\n
"
" : _typeless(kj::mv(typeless)) {}
\n
"
"
\n
"
,
kj
::
mv
(
methodDecls
),
"private:
\n
"
" ::capnp::
TypelessResults
::Pipeline _typeless;
\n
"
" ::capnp::
ObjectPointer
::Pipeline _typeless;
\n
"
" template <typename T, ::capnp::Kind k>
\n
"
" friend struct ::capnp::ToDynamic_;
\n
"
"};
\n
"
...
...
@@ -1263,7 +1338,7 @@ private:
return
kj
::
strTree
(
",
\n
public virtual "
,
e
.
typeName
,
"::Client"
);
},
" {
\n
"
"public:
\n
"
" inline Client(::kj::Own<const ::capnp::ClientHook>&& hook)
\n
"
" inline
explicit
Client(::kj::Own<const ::capnp::ClientHook>&& hook)
\n
"
" : ::capnp::Capability::Client(::kj::mv(hook)) {}
\n
"
"
\n
"
,
KJ_MAP
(
m
,
methods
)
{
return
kj
::
mv
(
m
.
clientDecls
);
},
...
...
c++/src/capnp/compiler/grammar.capnp.h
View file @
edbc2a5a
This diff is collapsed.
Click to expand it.
c++/src/capnp/compiler/lexer.capnp.h
View file @
edbc2a5a
...
...
@@ -19,6 +19,7 @@ struct Token {
class
Reader
;
class
Builder
;
class
Pipeline
;
enum
Which
:
uint16_t
{
IDENTIFIER
,
STRING_LITERAL
,
...
...
@@ -35,6 +36,7 @@ struct Statement {
class
Reader
;
class
Builder
;
class
Pipeline
;
enum
Which
:
uint16_t
{
LINE
,
BLOCK
,
...
...
@@ -46,6 +48,7 @@ struct LexedTokens {
class
Reader
;
class
Builder
;
class
Pipeline
;
};
struct
LexedStatements
{
...
...
@@ -53,6 +56,7 @@ struct LexedStatements {
class
Reader
;
class
Builder
;
class
Pipeline
;
};
}
// namespace
...
...
@@ -241,6 +245,19 @@ inline ::kj::StringTree KJ_STRINGIFY(Token::Builder builder) {
return
::
capnp
::
_
::
structString
<
Token
>
(
builder
.
_builder
.
asReader
());
}
class
Token
::
Pipeline
{
public
:
typedef
Token
Pipelines
;
inline
explicit
Pipeline
(
::
capnp
::
ObjectPointer
::
Pipeline
&&
typeless
)
:
_typeless
(
kj
::
mv
(
typeless
))
{}
private
:
::
capnp
::
ObjectPointer
::
Pipeline
_typeless
;
template
<
typename
T
,
::
capnp
::
Kind
k
>
friend
struct
::
capnp
::
ToDynamic_
;
};
class
Statement
::
Reader
{
public
:
typedef
Statement
Reads
;
...
...
@@ -351,6 +368,19 @@ inline ::kj::StringTree KJ_STRINGIFY(Statement::Builder builder) {
return
::
capnp
::
_
::
structString
<
Statement
>
(
builder
.
_builder
.
asReader
());
}
class
Statement
::
Pipeline
{
public
:
typedef
Statement
Pipelines
;
inline
explicit
Pipeline
(
::
capnp
::
ObjectPointer
::
Pipeline
&&
typeless
)
:
_typeless
(
kj
::
mv
(
typeless
))
{}
private
:
::
capnp
::
ObjectPointer
::
Pipeline
_typeless
;
template
<
typename
T
,
::
capnp
::
Kind
k
>
friend
struct
::
capnp
::
ToDynamic_
;
};
class
LexedTokens
::
Reader
{
public
:
typedef
LexedTokens
Reads
;
...
...
@@ -414,6 +444,19 @@ inline ::kj::StringTree KJ_STRINGIFY(LexedTokens::Builder builder) {
return
::
capnp
::
_
::
structString
<
LexedTokens
>
(
builder
.
_builder
.
asReader
());
}
class
LexedTokens
::
Pipeline
{
public
:
typedef
LexedTokens
Pipelines
;
inline
explicit
Pipeline
(
::
capnp
::
ObjectPointer
::
Pipeline
&&
typeless
)
:
_typeless
(
kj
::
mv
(
typeless
))
{}
private
:
::
capnp
::
ObjectPointer
::
Pipeline
_typeless
;
template
<
typename
T
,
::
capnp
::
Kind
k
>
friend
struct
::
capnp
::
ToDynamic_
;
};
class
LexedStatements
::
Reader
{
public
:
typedef
LexedStatements
Reads
;
...
...
@@ -477,6 +520,19 @@ inline ::kj::StringTree KJ_STRINGIFY(LexedStatements::Builder builder) {
return
::
capnp
::
_
::
structString
<
LexedStatements
>
(
builder
.
_builder
.
asReader
());
}
class
LexedStatements
::
Pipeline
{
public
:
typedef
LexedStatements
Pipelines
;
inline
explicit
Pipeline
(
::
capnp
::
ObjectPointer
::
Pipeline
&&
typeless
)
:
_typeless
(
kj
::
mv
(
typeless
))
{}
private
:
::
capnp
::
ObjectPointer
::
Pipeline
_typeless
;
template
<
typename
T
,
::
capnp
::
Kind
k
>
friend
struct
::
capnp
::
ToDynamic_
;
};
// =======================================================================================
inline
Token
::
Which
Token
::
Reader
::
which
()
const
{
...
...
c++/src/capnp/layout.c++
View file @
edbc2a5a
...
...
@@ -1798,7 +1798,7 @@ struct WireHelpers {
static
KJ_ALWAYS_INLINE
(
kj
::
Own
<
const
ClientHook
>
readCapabilityPointer
(
SegmentReader
*
segment
,
const
WirePointer
*
ref
,
const
word
*
refTarget
,
int
nestingLimit
))
{
if
(
ref
->
isNull
())
{
return
segment
->
getArena
()
->
extractNullCap
(
);
return
newBrokenCap
(
"Calling null capability pointer."
);
}
else
{
return
segment
->
getArena
()
->
extractCap
(
readStructOrCapDescPointer
(
WirePointer
::
CAPABILITY
,
segment
,
ref
,
refTarget
,
nullptr
,
nestingLimit
));
...
...
c++/src/capnp/object.c++
View file @
edbc2a5a
...
...
@@ -26,6 +26,10 @@
namespace
capnp
{
kj
::
Own
<
const
ClientHook
>
PipelineHook
::
getPipelinedCap
(
kj
::
Array
<
PipelineOp
>&&
ops
)
const
{
return
getPipelinedCap
(
ops
.
asPtr
());
}
kj
::
Own
<
const
ClientHook
>
ObjectPointer
::
Reader
::
getPipelinedCap
(
kj
::
ArrayPtr
<
const
PipelineOp
>
ops
)
const
{
_
::
PointerReader
pointer
=
reader
;
...
...
@@ -41,4 +45,29 @@ kj::Own<const ClientHook> ObjectPointer::Reader::getPipelinedCap(
return
pointer
.
getCapability
();
}
ObjectPointer
::
Pipeline
ObjectPointer
::
Pipeline
::
noop
()
const
{
auto
newOps
=
kj
::
heapArray
<
PipelineOp
>
(
ops
.
size
());
for
(
auto
i
:
kj
::
indices
(
ops
))
{
newOps
[
i
]
=
ops
[
i
];
}
return
Pipeline
(
hook
->
addRef
(),
kj
::
mv
(
newOps
));
}
ObjectPointer
::
Pipeline
ObjectPointer
::
Pipeline
::
getPointerField
(
uint16_t
pointerIndex
)
const
{
auto
newOps
=
kj
::
heapArray
<
PipelineOp
>
(
ops
.
size
()
+
1
);
for
(
auto
i
:
kj
::
indices
(
ops
))
{
newOps
[
i
]
=
ops
[
i
];
}
auto
&
newOp
=
newOps
[
ops
.
size
()];
newOp
.
type
=
PipelineOp
::
GET_POINTER_FIELD
;
newOp
.
pointerIndex
=
pointerIndex
;
return
Pipeline
(
hook
->
addRef
(),
kj
::
mv
(
newOps
));
}
kj
::
Own
<
const
ClientHook
>
ObjectPointer
::
Pipeline
::
asCap
()
const
{
return
hook
->
getPipelinedCap
(
ops
);
}
}
// namespace capnp
c++/src/capnp/object.h
View file @
edbc2a5a
...
...
@@ -33,8 +33,47 @@ namespace capnp {
class
StructSchema
;
class
ListSchema
;
class
Orphanage
;
struct
PipelineOp
;
class
ClientHook
;
class
PipelineHook
;
// =======================================================================================
// Pipeline helpers
//
// These relate to capabilities, but we don't declare them in capability.h because generated code
// for structs needs to know about these, even in files that contain no interfaces.
struct
PipelineOp
{
// Corresponds to rpc.capnp's PromisedAnswer.Op.
enum
Type
{
GET_POINTER_FIELD
// There may be other types in the future...
};
Type
type
;
union
{
uint16_t
pointerIndex
;
// for GET_POINTER_FIELD
};
};
class
PipelineHook
{
// Represents a currently-running call, and implements pipelined requests on its result.
public
:
virtual
kj
::
Own
<
const
PipelineHook
>
addRef
()
const
=
0
;
// Increment this object's reference count.
virtual
kj
::
Own
<
const
ClientHook
>
getPipelinedCap
(
kj
::
ArrayPtr
<
const
PipelineOp
>
ops
)
const
=
0
;
// Extract a promised Capability from the results.
virtual
kj
::
Own
<
const
ClientHook
>
getPipelinedCap
(
kj
::
Array
<
PipelineOp
>&&
ops
)
const
;
// Version of getPipelinedCap() passing the array by move. May avoid a copy in some cases.
// Default implementation just calls the other version.
};
// =======================================================================================
// ObjectPointer!
struct
ObjectPointer
{
// Reader/Builder for the `Object` field type, i.e. a pointer that can point to an arbitrary
...
...
@@ -152,8 +191,36 @@ struct ObjectPointer {
_
::
PointerBuilder
builder
;
friend
class
CapBuilderContext
;
};
class
Pipeline
{
public
:
inline
explicit
Pipeline
(
kj
::
Own
<
const
PipelineHook
>&&
hook
)
:
hook
(
kj
::
mv
(
hook
))
{}
Pipeline
noop
()
const
;
// Just make a copy.
Pipeline
getPointerField
(
uint16_t
pointerIndex
)
const
;
// Return a new Promise representing a sub-object of the result. `pointerIndex` is the index
// of the sub-object within the pointer section of the result (the result must be a struct).
//
// TODO(kenton): On GCC 4.8 / Clang 3.3, use rvalue qualifiers to avoid the need for copies.
// Also make `ops` into a Vector to optimize this.
kj
::
Own
<
const
ClientHook
>
asCap
()
const
;
// Expect that the result is a capability and construct a pipelined version of it now.
private
:
kj
::
Own
<
const
PipelineHook
>
hook
;
kj
::
Array
<
PipelineOp
>
ops
;
inline
Pipeline
(
kj
::
Own
<
const
PipelineHook
>&&
hook
,
kj
::
Array
<
PipelineOp
>&&
ops
)
:
hook
(
kj
::
mv
(
hook
)),
ops
(
kj
::
mv
(
ops
))
{}
};
};
// TODO(now): delete
typedef
ObjectPointer
TypelessResults
;
template
<>
class
Orphan
<
ObjectPointer
>
{
// An orphaned object of unknown type.
...
...
c++/src/capnp/orphan.h
View file @
edbc2a5a
...
...
@@ -52,14 +52,14 @@ public:
Orphan
(
Orphan
&&
)
=
default
;
Orphan
&
operator
=
(
Orphan
&&
)
=
default
;
inline
typename
T
::
Builder
get
();
inline
BuilderFor
<
T
>
get
();
// Get the underlying builder. If the orphan is null, this will allocate and return a default
// object rather than crash. This is done for security -- otherwise, you might enable a DoS
// attack any time you disown a field and fail to check if it is null. In the case of structs,
// this means that the orphan is no longer null after get() returns. In the case of lists,
// no actual object is allocated since a simple empty ListBuilder can be returned.
inline
typename
T
::
Reader
getReader
()
const
;
inline
ReaderFor
<
T
>
getReader
()
const
;
inline
bool
operator
==
(
decltype
(
nullptr
))
const
{
return
builder
==
nullptr
;
}
inline
bool
operator
!=
(
decltype
(
nullptr
))
const
{
return
builder
!=
nullptr
;
}
...
...
@@ -198,12 +198,12 @@ struct OrphanGetImpl<Data, Kind::BLOB> {
}
// namespace _ (private)
template
<
typename
T
>
inline
typename
T
::
Builder
Orphan
<
T
>::
get
()
{
inline
BuilderFor
<
T
>
Orphan
<
T
>::
get
()
{
return
_
::
OrphanGetImpl
<
T
>::
apply
(
builder
);
}
template
<
typename
T
>
inline
typename
T
::
Reader
Orphan
<
T
>::
getReader
()
const
{
inline
ReaderFor
<
T
>
Orphan
<
T
>::
getReader
()
const
{
return
_
::
OrphanGetImpl
<
T
>::
applyReader
(
builder
);
}
...
...
c++/src/capnp/schema.capnp.h
View file @
edbc2a5a
This diff is collapsed.
Click to expand it.
c++/src/capnp/test.capnp
View file @
edbc2a5a
...
...
@@ -584,3 +584,7 @@ interface TestExtends extends(TestInterface) {
corge @1 TestAllTypes -> ();
grault @2 () -> TestAllTypes;
}
interface TestPipeline {
getCap @0 (s: Text, inCap :TestInterface) -> (n :UInt32, outCap :TestExtends);
}
c++/src/kj/async.c++
View file @
edbc2a5a
...
...
@@ -118,7 +118,9 @@ void EventLoop::waitImpl(Own<_::PromiseNode> node, _::ExceptionOrValue& result)
EventLoop
::
Event
::~
Event
()
noexcept
(
false
)
{
if
(
this
!=
&
loop
.
queue
)
{
KJ_ASSERT
(
next
==
nullptr
||
std
::
uncaught_exception
(),
"Event destroyed while armed."
);
KJ_ASSERT
(
next
==
nullptr
||
std
::
uncaught_exception
(),
"Event destroyed while armed. You must call disarm() in the subclass's destructor "
"in order to ensure that fire() is not running when the event is destroyed."
);
}
}
...
...
@@ -393,7 +395,9 @@ ForkHubBase::ForkHubBase(const EventLoop& loop, Own<PromiseNode>&& inner,
arm
(
YIELD
);
}
ForkHubBase
::~
ForkHubBase
()
noexcept
(
false
)
{}
ForkHubBase
::~
ForkHubBase
()
noexcept
(
false
)
{
disarm
();
}
void
ForkHubBase
::
fire
()
{
if
(
!
isWaiting
&&
!
inner
->
onReady
(
*
this
))
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment