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
114e20cc
Commit
114e20cc
authored
5 years ago
by
Kenton Varda
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add tests for cross-thread-event cancellation, fix bug.
parent
b715ecaf
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
109 additions
and
1 deletion
+109
-1
async-test.c++
c++/src/kj/async-test.c++
+109
-0
async.c++
c++/src/kj/async.c++
+0
-1
No files found.
c++/src/kj/async-test.c++
View file @
114e20cc
...
...
@@ -25,6 +25,15 @@
#include "mutex.h"
#include <kj/compat/gtest.h>
#if _WIN32
#define WIN32_LEAN_AND_MEAN 1 // lolz
#include <windows.h>
inline
void
delay
()
{
Sleep
(
10
);
}
#else
#include <unistd.h>
inline
void
delay
()
{
usleep
(
10000
);
}
#endif
namespace
kj
{
namespace
{
...
...
@@ -1084,5 +1093,105 @@ KJ_TEST("asynchonous promise cross-thread events") {
}
}
KJ_TEST
(
"cancel cross-thread event before it runs"
)
{
MutexGuarded
<
kj
::
Maybe
<
const
Executor
&>>
executor
;
// to get the Executor from the other thread
Thread
thread
([
&
]()
{
KJ_IF_MAYBE
(
exception
,
kj
::
runCatchingExceptions
([
&
]()
{
EventLoop
loop
;
WaitScope
waitScope
(
loop
);
*
executor
.
lockExclusive
()
=
getCurrentThreadExecutor
();
// We never run the loop here, so that when the event is canceled, it's still queued.
// Wait until parent thread sets executor to null, as a way to tell us to quit.
executor
.
lockExclusive
().
wait
([](
auto
&
val
)
{
return
val
==
nullptr
;
});
}))
{
// Log here because it's likely the parent thread will never join and we'll hang forever
// without propagating the exception.
KJ_LOG
(
ERROR
,
*
exception
);
kj
::
throwRecoverableException
(
kj
::
mv
(
*
exception
));
}
});
EventLoop
loop
;
WaitScope
waitScope
(
loop
);
KJ_IF_MAYBE
(
exception
,
kj
::
runCatchingExceptions
([
&
]()
{
const
Executor
*
exec
;
{
auto
lock
=
executor
.
lockExclusive
();
lock
.
wait
([
&
](
kj
::
Maybe
<
const
Executor
&>
value
)
{
return
value
!=
nullptr
;
});
exec
=
&
KJ_ASSERT_NONNULL
(
*
lock
);
}
{
Promise
<
uint
>
promise
=
exec
->
executeAsync
([
&
]()
{
return
123u
;
});
delay
();
KJ_EXPECT
(
!
promise
.
poll
(
waitScope
));
}
*
executor
.
lockExclusive
()
=
nullptr
;
}))
{
// Log here because the thread join is likely to hang forever...
KJ_FAIL_EXPECT
(
*
exception
);
}
}
KJ_TEST
(
"cancel cross-thread event while it runs"
)
{
MutexGuarded
<
kj
::
Maybe
<
const
Executor
&>>
executor
;
// to get the Executor from the other thread
Own
<
PromiseFulfiller
<
void
>>
fulfiller
;
// accessed only from the subthread
Thread
thread
([
&
]()
{
KJ_IF_MAYBE
(
exception
,
kj
::
runCatchingExceptions
([
&
]()
{
EventLoop
loop
;
WaitScope
waitScope
(
loop
);
auto
paf
=
newPromiseAndFulfiller
<
void
>
();
fulfiller
=
kj
::
mv
(
paf
.
fulfiller
);
*
executor
.
lockExclusive
()
=
getCurrentThreadExecutor
();
paf
.
promise
.
wait
(
waitScope
);
// Wait until parent thread sets executor to null, as a way to tell us to quit.
executor
.
lockExclusive
().
wait
([](
auto
&
val
)
{
return
val
==
nullptr
;
});
}))
{
// Log here because it's likely the parent thread will never join and we'll hang forever
// without propagating the exception.
KJ_LOG
(
ERROR
,
*
exception
);
kj
::
throwRecoverableException
(
kj
::
mv
(
*
exception
));
}
});
EventLoop
loop
;
WaitScope
waitScope
(
loop
);
KJ_IF_MAYBE
(
exception
,
kj
::
runCatchingExceptions
([
&
]()
{
const
Executor
*
exec
;
{
auto
lock
=
executor
.
lockExclusive
();
lock
.
wait
([
&
](
kj
::
Maybe
<
const
Executor
&>
value
)
{
return
value
!=
nullptr
;
});
exec
=
&
KJ_ASSERT_NONNULL
(
*
lock
);
}
{
Promise
<
uint
>
promise
=
exec
->
executeAsync
([
&
]()
->
kj
::
Promise
<
uint
>
{
return
kj
::
NEVER_DONE
;
});
delay
();
KJ_EXPECT
(
!
promise
.
poll
(
waitScope
));
}
exec
->
executeSync
([
&
]()
{
fulfiller
->
fulfill
();
});
*
executor
.
lockExclusive
()
=
nullptr
;
}))
{
// Log here because the thread join is likely to hang forever...
KJ_FAIL_EXPECT
(
*
exception
);
}
}
}
// namespace
}
// namespace kj
This diff is collapsed.
Click to expand it.
c++/src/kj/async.c++
View file @
114e20cc
...
...
@@ -349,7 +349,6 @@ struct Executor::Impl {
event
.
disarm
();
event
.
state
=
_
::
XThreadEvent
::
DONE
;
}
event
.
armBreadthFirst
();
});
replies
.
forEach
([
&
](
_
::
XThreadEvent
&
event
)
{
...
...
This diff is collapsed.
Click to expand it.
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