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
98696a57
Commit
98696a57
authored
Nov 21, 2013
by
Kenton Varda
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Correctly generate Resolve messages.
parent
3070f627
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
117 additions
and
17 deletions
+117
-17
capability-context.c++
c++/src/capnp/capability-context.c++
+4
-0
capability.c++
c++/src/capnp/capability.c++
+23
-1
capability.h
c++/src/capnp/capability.h
+8
-1
rpc.c++
c++/src/capnp/rpc.c++
+82
-15
No files found.
c++/src/capnp/capability-context.c++
View file @
98696a57
...
...
@@ -197,6 +197,10 @@ public:
return
VoidPromiseAndPipeline
{
kj
::
cp
(
exception
),
kj
::
heap
<
BrokenPipeline
>
(
exception
)
};
}
kj
::
Maybe
<
const
ClientHook
&>
getResolved
()
const
{
return
nullptr
;
}
kj
::
Maybe
<
kj
::
Promise
<
kj
::
Own
<
const
ClientHook
>>>
whenMoreResolved
()
const
override
{
return
kj
::
Promise
<
kj
::
Own
<
const
ClientHook
>>
(
kj
::
cp
(
exception
));
}
...
...
c++/src/capnp/capability.c++
View file @
98696a57
...
...
@@ -199,7 +199,11 @@ class QueuedClient final: public ClientHook, public kj::Refcounted {
public
:
QueuedClient
(
const
kj
::
EventLoop
&
loop
,
kj
::
Promise
<
kj
::
Own
<
const
ClientHook
>>&&
promise
)
:
loop
(
loop
),
promise
(
loop
.
fork
(
kj
::
mv
(
promise
)))
{}
promise
(
loop
.
fork
(
kj
::
mv
(
promise
))),
selfResolutionOp
(
loop
.
there
(
this
->
promise
.
addBranch
(),
[
this
](
kj
::
Own
<
const
ClientHook
>&&
inner
)
{
*
redirect
.
lockExclusive
()
=
kj
::
mv
(
inner
);
}))
{}
Request
<
ObjectPointer
,
ObjectPointer
>
newCall
(
uint64_t
interfaceId
,
uint16_t
methodId
,
uint
firstSegmentWordSize
)
const
override
{
...
...
@@ -264,6 +268,14 @@ public:
return
VoidPromiseAndPipeline
{
kj
::
mv
(
completionPromise
),
kj
::
mv
(
pipeline
)
};
}
kj
::
Maybe
<
const
ClientHook
&>
getResolved
()
const
{
KJ_IF_MAYBE
(
inner
,
*
redirect
.
lockExclusive
())
{
return
**
inner
;
}
else
{
return
nullptr
;
}
}
kj
::
Maybe
<
kj
::
Promise
<
kj
::
Own
<
const
ClientHook
>>>
whenMoreResolved
()
const
override
{
return
getPromiseForClientResolution
().
addBranch
();
}
...
...
@@ -300,6 +312,12 @@ private:
// resolves). Luckily, we know that queued calls will involve, at the very least, an
// eventLoop.evalLater.
kj
::
MutexGuarded
<
kj
::
Maybe
<
kj
::
Own
<
const
ClientHook
>>>
redirect
;
// Once the promise resolves, this will become non-null and point to the underlying object.
kj
::
Promise
<
void
>
selfResolutionOp
;
// Represents the operation which will set `redirect` when possible.
const
ClientHookPromiseFork
&
getPromiseForCallForwarding
()
const
{
return
promiseForCallForwarding
.
get
([
this
](
kj
::
SpaceFor
<
ClientHookPromiseFork
>&
space
)
{
return
space
.
construct
(
loop
.
fork
(
promise
.
addBranch
()));
...
...
@@ -403,6 +421,10 @@ public:
kj
::
refcounted
<
QueuedPipeline
>
(
server
.
getEventLoop
(),
kj
::
mv
(
pipelinePromise
))
};
}
kj
::
Maybe
<
const
ClientHook
&>
getResolved
()
const
{
return
nullptr
;
}
kj
::
Maybe
<
kj
::
Promise
<
kj
::
Own
<
const
ClientHook
>>>
whenMoreResolved
()
const
override
{
return
nullptr
;
}
...
...
c++/src/capnp/capability.h
View file @
98696a57
...
...
@@ -315,10 +315,17 @@ public:
//
// The call must not begin synchronously, as the caller may hold arbitrary mutexes.
virtual
kj
::
Maybe
<
const
ClientHook
&>
getResolved
()
const
=
0
;
// If this ClientHook is a promise that has already resolved, returns the inner, resolved version
// of the capability. The caller may permanently replace this client with the resolved one if
// desired. Returns null if the client isn't a promise or hasn't resolved yet -- use
// `whenMoreResolved()` to distinguish between them.
virtual
kj
::
Maybe
<
kj
::
Promise
<
kj
::
Own
<
const
ClientHook
>>>
whenMoreResolved
()
const
=
0
;
// If this client is a settled reference (not a promise), return nullptr. Otherwise, return a
// promise that eventually resolves to a new client that is closer to being the final, settled
// client. Calling this repeatedly should eventually produce a settled client.
// client (i.e. the value eventually returned by `getResolved()`). Calling this repeatedly
// should eventually produce a settled client.
kj
::
Promise
<
void
>
whenResolved
()
const
;
// Repeatedly calls whenMoreResolved() until it returns nullptr.
...
...
c++/src/capnp/rpc.c++
View file @
98696a57
...
...
@@ -406,6 +406,10 @@ private:
kj
::
Own
<
const
ClientHook
>
clientHook
;
kj
::
Promise
<
void
>
resolveOp
=
nullptr
;
// If this export is a promise (not a settled capability), the `resolveOp` represents the
// ongoing operation to wait for that promise to resolve and then send a `Resolve` message.
inline
bool
operator
==
(
decltype
(
nullptr
))
const
{
return
refcount
==
0
;
}
inline
bool
operator
!=
(
decltype
(
nullptr
))
const
{
return
refcount
!=
0
;
}
};
...
...
@@ -675,6 +679,10 @@ private:
return
Request
<
ObjectPointer
,
ObjectPointer
>
(
root
,
kj
::
mv
(
request
));
}
kj
::
Maybe
<
const
ClientHook
&>
getResolved
()
const
{
return
nullptr
;
}
kj
::
Maybe
<
kj
::
Promise
<
kj
::
Own
<
const
ClientHook
>>>
whenMoreResolved
()
const
override
{
return
nullptr
;
}
...
...
@@ -727,6 +735,10 @@ private:
return
Request
<
ObjectPointer
,
ObjectPointer
>
(
root
,
kj
::
mv
(
request
));
}
kj
::
Maybe
<
const
ClientHook
&>
getResolved
()
const
{
return
nullptr
;
}
kj
::
Maybe
<
kj
::
Promise
<
kj
::
Own
<
const
ClientHook
>>>
whenMoreResolved
()
const
override
{
return
nullptr
;
}
...
...
@@ -746,7 +758,7 @@ private:
kj
::
Promise
<
kj
::
Own
<
const
ClientHook
>>
eventual
,
kj
::
Maybe
<
ExportId
>
importId
)
:
RpcClient
(
connectionState
),
inner
(
kj
::
mv
(
initial
)
),
inner
(
Inner
{
false
,
kj
::
mv
(
initial
)}
),
importId
(
importId
),
fork
(
connectionState
.
eventLoop
.
fork
(
kj
::
mv
(
eventual
))),
resolveSelfPromise
(
connectionState
.
eventLoop
.
there
(
fork
.
addBranch
(),
...
...
@@ -783,20 +795,28 @@ private:
kj
::
Maybe
<
ExportId
>
writeDescriptor
(
rpc
::
CapDescriptor
::
Builder
descriptor
,
Tables
&
tables
)
const
override
{
auto
cap
=
inner
.
lockExclusive
()
->
get
()
->
addRef
();
return
connectionState
->
writeDescriptor
(
kj
::
mv
(
cap
),
descriptor
,
tables
);
return
connectionState
->
writeDescriptor
(
*
inner
.
lockExclusive
()
->
cap
,
descriptor
,
tables
);
}
kj
::
Maybe
<
kj
::
Own
<
const
ClientHook
>>
writeTarget
(
rpc
::
Call
::
Target
::
Builder
target
)
const
override
{
return
connectionState
->
writeTarget
(
*
*
inner
.
lockExclusive
()
,
target
);
return
connectionState
->
writeTarget
(
*
inner
.
lockExclusive
()
->
cap
,
target
);
}
// implements ClientHook -----------------------------------------
Request
<
ObjectPointer
,
ObjectPointer
>
newCall
(
uint64_t
interfaceId
,
uint16_t
methodId
,
uint
firstSegmentWordSize
)
const
override
{
return
inner
.
lockExclusive
()
->
get
()
->
newCall
(
interfaceId
,
methodId
,
firstSegmentWordSize
);
return
inner
.
lockExclusive
()
->
cap
->
newCall
(
interfaceId
,
methodId
,
firstSegmentWordSize
);
}
kj
::
Maybe
<
const
ClientHook
&>
getResolved
()
const
{
auto
lock
=
inner
.
lockShared
();
if
(
lock
->
isResolved
)
{
return
*
lock
->
cap
;
}
else
{
return
nullptr
;
}
}
kj
::
Maybe
<
kj
::
Promise
<
kj
::
Own
<
const
ClientHook
>>>
whenMoreResolved
()
const
override
{
...
...
@@ -804,7 +824,12 @@ private:
}
private
:
kj
::
MutexGuarded
<
kj
::
Own
<
const
ClientHook
>>
inner
;
struct
Inner
{
bool
isResolved
;
kj
::
Own
<
const
ClientHook
>
cap
;
};
kj
::
MutexGuarded
<
Inner
>
inner
;
kj
::
Maybe
<
ExportId
>
importId
;
kj
::
ForkedPromise
<
kj
::
Own
<
const
ClientHook
>>
fork
;
...
...
@@ -816,33 +841,70 @@ private:
// Careful to make sure the old client is not destroyed until we release the lock.
kj
::
Own
<
const
ClientHook
>
old
;
auto
lock
=
inner
.
lockExclusive
();
old
=
kj
::
mv
(
*
lock
);
*
lock
=
replacement
->
addRef
();
old
=
kj
::
mv
(
lock
->
cap
);
lock
->
cap
=
replacement
->
addRef
();
lock
->
isResolved
=
true
;
}
};
kj
::
Maybe
<
ExportId
>
writeDescriptor
(
kj
::
Own
<
const
ClientHook
>
cap
,
rpc
::
CapDescriptor
::
Builder
descriptor
,
const
ClientHook
&
cap
,
rpc
::
CapDescriptor
::
Builder
descriptor
,
Tables
&
tables
)
const
{
// Write a descriptor for the given capability. The tables must be locked by the caller and
// passed in as a parameter.
if
(
cap
->
getBrand
()
==
this
)
{
return
kj
::
downcast
<
const
RpcClient
>
(
*
cap
).
writeDescriptor
(
descriptor
,
tables
);
// Find the innermost wrapped capability.
const
ClientHook
*
inner
=
&
cap
;
for
(;;)
{
KJ_IF_MAYBE
(
resolved
,
inner
->
getResolved
())
{
inner
=
resolved
;
}
else
{
break
;
}
}
if
(
inner
->
getBrand
()
==
this
)
{
return
kj
::
downcast
<
const
RpcClient
>
(
*
inner
).
writeDescriptor
(
descriptor
,
tables
);
}
else
{
auto
iter
=
tables
.
exportsByCap
.
find
(
cap
);
auto
iter
=
tables
.
exportsByCap
.
find
(
inner
);
if
(
iter
!=
tables
.
exportsByCap
.
end
())
{
// We've already seen and exported this capability before. Just up the refcount.
auto
&
exp
=
KJ_ASSERT_NONNULL
(
tables
.
exports
.
find
(
iter
->
second
));
++
exp
.
refcount
;
// TODO(now): Check if it's a promise.
descriptor
.
setSenderHosted
(
iter
->
second
);
return
iter
->
second
;
}
else
{
// This is the first time we've seen this capability.
ExportId
exportId
;
auto
&
exp
=
tables
.
exports
.
next
(
exportId
);
exp
.
refcount
=
1
;
exp
.
clientHook
=
kj
::
mv
(
cap
);
exp
.
clientHook
=
inner
->
addRef
(
);
descriptor
.
setSenderHosted
(
exportId
);
KJ_IF_MAYBE
(
wrapped
,
inner
->
whenMoreResolved
())
{
// This is a promise. Arrange for the `Resolve` message to be sent later.
exp
.
resolveOp
=
eventLoop
.
there
(
kj
::
mv
(
*
wrapped
),
[
this
,
exportId
](
kj
::
Own
<
const
ClientHook
>&&
resolution
)
{
// send resolve
auto
message
=
connection
->
newOutgoingMessage
(
messageSizeHint
<
rpc
::
Resolve
>
()
+
sizeInWords
<
rpc
::
CapDescriptor
>
()
+
16
);
auto
resolve
=
message
->
getBody
().
initAs
<
rpc
::
Message
>
().
initResolve
();
resolve
.
setPromiseId
(
exportId
);
writeDescriptor
(
*
resolution
,
resolve
.
initCap
(),
*
this
->
tables
.
lockExclusive
());
message
->
send
();
},
[
this
,
exportId
](
kj
::
Exception
&&
exception
)
{
// send resolve
auto
message
=
connection
->
newOutgoingMessage
(
messageSizeHint
<
rpc
::
Resolve
>
()
+
sizeInWords
<
rpc
::
Exception
>
()
+
(
exception
.
getDescription
().
size
()
+
7
/
8
)
+
8
);
auto
resolve
=
message
->
getBody
().
initAs
<
rpc
::
Message
>
().
initResolve
();
resolve
.
setPromiseId
(
exportId
);
fromException
(
exception
,
resolve
.
initException
());
message
->
send
();
});
exp
.
resolveOp
.
eagerlyEvaluate
(
eventLoop
);
}
return
exportId
;
}
}
...
...
@@ -1097,6 +1159,7 @@ private:
for
(
auto
exportId
:
exports
)
{
auto
&
exp
=
KJ_ASSERT_NONNULL
(
lock
->
exports
.
find
(
exportId
));
if
(
--
exp
.
refcount
==
0
)
{
lock
->
exportsByCap
.
erase
(
exp
.
clientHook
);
clientsToRelease
.
add
(
kj
::
mv
(
exp
.
clientHook
));
lock
->
exports
.
erase
(
exportId
);
}
...
...
@@ -1121,7 +1184,7 @@ private:
// If maybeExportId is inlined, GCC 4.7 reports a spurious "may be used uninitialized"
// error (GCC 4.8 and Clang do not complain).
auto
maybeExportId
=
connectionState
.
writeDescriptor
(
entry
.
second
.
cap
->
addRef
()
,
entry
.
second
.
builder
,
tables
);
*
entry
.
second
.
cap
,
entry
.
second
.
builder
,
tables
);
KJ_IF_MAYBE
(
exportId
,
maybeExportId
)
{
KJ_ASSERT
(
tables
.
exports
.
find
(
*
exportId
)
!=
nullptr
);
exports
.
add
(
*
exportId
);
...
...
@@ -1791,6 +1854,10 @@ private:
// TODO(now)
break
;
case
rpc
:
:
Message
::
DISEMBARGO
:
// TODO(now)
break
;
case
rpc
:
:
Message
::
RESTORE
:
handleRestore
(
kj
::
mv
(
message
),
reader
.
getRestore
());
break
;
...
...
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