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
f4ab3d2d
Commit
f4ab3d2d
authored
Nov 19, 2013
by
Kenton Varda
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Refactor how promise imports are represented in the RPC implementation.
parent
2aa37a8a
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
163 additions
and
6 deletions
+163
-6
rpc.c++
c++/src/capnp/rpc.c++
+0
-0
rpc.capnp
c++/src/capnp/rpc.capnp
+5
-5
array.h
c++/src/kj/array.h
+8
-0
async-test.c++
c++/src/kj/async-test.c++
+54
-0
async.c++
c++/src/kj/async.c++
+30
-0
async.h
c++/src/kj/async.h
+66
-1
No files found.
c++/src/capnp/rpc.c++
View file @
f4ab3d2d
This diff is collapsed.
Click to expand it.
c++/src/capnp/rpc.capnp
View file @
f4ab3d2d
...
...
@@ -428,7 +428,7 @@ struct Resolve {
# When a promise ID is first sent over the wire (e.g. in a `CapDescriptor`), the sender (exporter)
# guarantees that it will follow up at some point with exactly one `Resolve` message. If the
# same `promiseId` is sent again before `Resolve`, still only one `Resolve` is sent. If the
# same ID is
reused
again later _after_ a `Resolve`, it can only be because the export's
# same ID is
sent
again later _after_ a `Resolve`, it can only be because the export's
# reference count hit zero in the meantime and the ID was re-assigned to a new export, therefore
# this later promise does _not_ correspond to the earlier `Resolve`.
#
...
...
@@ -816,10 +816,10 @@ struct CapDescriptor {
senderPromise @1 :ExportId;
# A promise which the sender will resolve later. The sender will send exactly one Resolve
# message at a future point in time to replace this promise.
#
#
TODO(soon): Can we merge this with senderHosted? Change `Resolve` to be allowed on any
#
export (i.e. it can be delivered zero or one times). Maybe rename it to `Replace`
.
# message at a future point in time to replace this promise.
Note that even if the same
#
`senderPromise` is received multiple times, only one `Resolve` is sent to cover all of
#
them. The `Resolve` is delivered even if `senderPromise` is not retained, or is retained
#
but then released before the `Resolve` is sent
.
receiverHosted @2 :ExportId;
# A capability (or promise) previously exported by the receiver.
...
...
c++/src/kj/array.h
View file @
f4ab3d2d
...
...
@@ -259,6 +259,7 @@ inline Array<T> heapArray(size_t size) {
}
template
<
typename
T
>
Array
<
T
>
heapArray
(
const
T
*
content
,
size_t
size
);
template
<
typename
T
>
Array
<
T
>
heapArray
(
ArrayPtr
<
T
>
content
);
template
<
typename
T
>
Array
<
T
>
heapArray
(
ArrayPtr
<
const
T
>
content
);
template
<
typename
T
,
typename
Iterator
>
Array
<
T
>
heapArray
(
Iterator
begin
,
Iterator
end
);
template
<
typename
T
>
Array
<
T
>
heapArray
(
std
::
initializer_list
<
T
>
init
);
...
...
@@ -654,6 +655,13 @@ Array<T> heapArray(const T* content, size_t size) {
return
builder
.
finish
();
}
template
<
typename
T
>
Array
<
T
>
heapArray
(
ArrayPtr
<
T
>
content
)
{
ArrayBuilder
<
T
>
builder
=
heapArrayBuilder
<
T
>
(
content
.
size
());
builder
.
addAll
(
content
);
return
builder
.
finish
();
}
template
<
typename
T
>
Array
<
T
>
heapArray
(
ArrayPtr
<
const
T
>
content
)
{
ArrayBuilder
<
T
>
builder
=
heapArrayBuilder
<
T
>
(
content
.
size
());
...
...
c++/src/kj/async-test.c++
View file @
f4ab3d2d
...
...
@@ -536,5 +536,59 @@ TEST(Async, EventLoopGuarded) {
}
}
class
DestructorDetector
{
public
:
DestructorDetector
(
bool
&
setTrue
)
:
setTrue
(
setTrue
)
{}
~
DestructorDetector
()
{
setTrue
=
true
;
}
private
:
bool
&
setTrue
;
};
TEST
(
Async
,
Attach
)
{
bool
destroyed
=
false
;
SimpleEventLoop
loop
;
Promise
<
int
>
promise
=
loop
.
evalLater
([
&
]()
{
EXPECT_FALSE
(
destroyed
);
return
123
;
});
promise
.
attach
(
kj
::
heap
<
DestructorDetector
>
(
destroyed
));
promise
=
loop
.
there
(
kj
::
mv
(
promise
),
[
&
](
int
i
)
{
EXPECT_TRUE
(
destroyed
);
return
i
+
321
;
});
EXPECT_FALSE
(
destroyed
);
EXPECT_EQ
(
444
,
loop
.
wait
(
kj
::
mv
(
promise
)));
EXPECT_TRUE
(
destroyed
);
}
TEST
(
Async
,
EagerlyEvaluate
)
{
bool
called
=
false
;
SimpleEventLoop
loop
;
Promise
<
void
>
promise
=
nullptr
;
loop
.
wait
(
loop
.
evalLater
([
&
]()
{
promise
=
Promise
<
void
>
(
READY_NOW
).
then
([
&
]()
{
called
=
true
;
});
}));
loop
.
wait
(
loop
.
evalLater
([]()
{}));
EXPECT_FALSE
(
called
);
promise
.
eagerlyEvaluate
(
loop
);
loop
.
wait
(
loop
.
evalLater
([]()
{}));
EXPECT_TRUE
(
called
);
}
}
// namespace
}
// namespace kj
c++/src/kj/async.c++
View file @
f4ab3d2d
...
...
@@ -350,6 +350,27 @@ void ImmediateBrokenPromiseNode::get(ExceptionOrValue& output) noexcept {
// -------------------------------------------------------------------
AttachmentPromiseNodeBase
::
AttachmentPromiseNodeBase
(
Own
<
PromiseNode
>&&
dependency
)
:
dependency
(
kj
::
mv
(
dependency
))
{}
bool
AttachmentPromiseNodeBase
::
onReady
(
EventLoop
::
Event
&
event
)
noexcept
{
return
dependency
->
onReady
(
event
);
}
void
AttachmentPromiseNodeBase
::
get
(
ExceptionOrValue
&
output
)
noexcept
{
dependency
->
get
(
output
);
}
Maybe
<
const
EventLoop
&>
AttachmentPromiseNodeBase
::
getSafeEventLoop
()
noexcept
{
return
dependency
->
getSafeEventLoop
();
}
void
AttachmentPromiseNodeBase
::
dropDependency
()
{
dependency
=
nullptr
;
}
// -------------------------------------------------------------------
TransformPromiseNodeBase
::
TransformPromiseNodeBase
(
Maybe
<
const
EventLoop
&>
loop
,
Own
<
PromiseNode
>&&
dependency
)
:
loop
(
loop
),
dependency
(
kj
::
mv
(
dependency
))
{}
...
...
@@ -375,6 +396,15 @@ void TransformPromiseNodeBase::dropDependency() {
dependency
=
nullptr
;
}
void
TransformPromiseNodeBase
::
getDepResult
(
ExceptionOrValue
&
output
)
{
dependency
->
get
(
output
);
KJ_IF_MAYBE
(
exception
,
kj
::
runCatchingExceptions
([
&
]()
{
dependency
=
nullptr
;
}))
{
output
.
addException
(
kj
::
mv
(
*
exception
));
}
}
// -------------------------------------------------------------------
ForkBranchBase
::
ForkBranchBase
(
Own
<
const
ForkHubBase
>&&
hubParam
)
:
hub
(
kj
::
mv
(
hubParam
))
{
...
...
c++/src/kj/async.h
View file @
f4ab3d2d
...
...
@@ -28,6 +28,7 @@
#include "mutex.h"
#include "refcount.h"
#include "work-queue.h"
#include "tuple.h"
namespace
kj
{
...
...
@@ -631,6 +632,18 @@ public:
// `Own<U>`, `U` must have a method `Own<const U> addRef() const` which returns a new reference
// to the same (or an equivalent) object (probably implemented via reference counting).
template
<
typename
...
Attachments
>
void
attach
(
Attachments
&&
...
attachments
);
// "Attaches" one or more movable objects (often, Own<T>s) to the promise, such that they will
// be destroyed when the promise resolves. This is useful when a promise's callback contains
// pointers into some object and you want to make sure the object still exists when the callback
// runs -- after calling then(), use attach() to add necessary objects to the result.
void
eagerlyEvaluate
(
const
EventLoop
&
eventLoop
=
EventLoop
::
current
());
// Force eager evaluation of this promise. Use this if you are going to hold on to the promise
// for awhile without consuming the result, but you want to make sure that the system actually
// processes it.
private
:
Promise
(
bool
,
Own
<
_
::
PromiseNode
>&&
node
)
:
PromiseBase
(
kj
::
mv
(
node
))
{}
// Second parameter prevent ambiguity with immediate-value constructor.
...
...
@@ -996,6 +1009,45 @@ private:
// -------------------------------------------------------------------
class
AttachmentPromiseNodeBase
:
public
PromiseNode
{
public
:
AttachmentPromiseNodeBase
(
Own
<
PromiseNode
>&&
dependency
);
bool
onReady
(
EventLoop
::
Event
&
event
)
noexcept
override
;
void
get
(
ExceptionOrValue
&
output
)
noexcept
override
;
Maybe
<
const
EventLoop
&>
getSafeEventLoop
()
noexcept
override
;
private
:
Own
<
PromiseNode
>
dependency
;
void
dropDependency
();
template
<
typename
>
friend
class
AttachmentPromiseNode
;
};
template
<
typename
Attachment
>
class
AttachmentPromiseNode
final
:
public
AttachmentPromiseNodeBase
{
// A PromiseNode that holds on to some object (usually, an Own<T>, but could be any movable
// object) until the promise resolves.
public
:
AttachmentPromiseNode
(
Own
<
PromiseNode
>&&
dependency
,
Attachment
&&
attachment
)
:
AttachmentPromiseNodeBase
(
kj
::
mv
(
dependency
)),
attachment
(
kj
::
mv
<
Attachment
>
(
attachment
))
{}
~
AttachmentPromiseNode
()
noexcept
(
false
)
{
// We need to make sure the dependency is deleted before we delete the attachment because the
// dependency may be using the attachment.
dropDependency
();
}
private
:
Attachment
attachment
;
};
// -------------------------------------------------------------------
class
TransformPromiseNodeBase
:
public
PromiseNode
{
public
:
TransformPromiseNodeBase
(
Maybe
<
const
EventLoop
&>
loop
,
Own
<
PromiseNode
>&&
dependency
);
...
...
@@ -1009,6 +1061,7 @@ private:
Own
<
PromiseNode
>
dependency
;
void
dropDependency
();
void
getDepResult
(
ExceptionOrValue
&
output
);
virtual
void
getImpl
(
ExceptionOrValue
&
output
)
=
0
;
...
...
@@ -1040,7 +1093,7 @@ private:
void
getImpl
(
ExceptionOrValue
&
output
)
override
{
ExceptionOr
<
DepT
>
depResult
;
dependency
->
ge
t
(
depResult
);
getDepResul
t
(
depResult
);
KJ_IF_MAYBE
(
depException
,
depResult
.
exception
)
{
output
.
as
<
T
>
()
=
handle
(
MaybeVoidCaller
<
Exception
,
FixVoid
<
ReturnType
<
ErrorFunc
,
Exception
>>>::
apply
(
...
...
@@ -1452,6 +1505,18 @@ Promise<_::Forked<T>> ForkedPromise<T>::addBranch() const {
return
hub
->
addBranch
();
}
template
<
typename
T
>
template
<
typename
...
Attachments
>
void
Promise
<
T
>::
attach
(
Attachments
&&
...
attachments
)
{
node
=
kj
::
heap
<
_
::
AttachmentPromiseNode
<
Tuple
<
Attachments
...
>>>
(
kj
::
mv
(
node
),
kj
::
tuple
(
kj
::
fwd
<
Attachments
>
(
attachments
)...));
}
template
<
typename
T
>
void
Promise
<
T
>::
eagerlyEvaluate
(
const
EventLoop
&
eventLoop
)
{
node
=
_
::
spark
<
_
::
FixVoid
<
T
>>
(
kj
::
mv
(
node
),
eventLoop
);
}
// =======================================================================================
namespace
_
{
// private
...
...
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