Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
A
Actor Framework
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
cpp-libs
Actor Framework
Commits
8e28cda4
Commit
8e28cda4
authored
May 31, 2019
by
Dominik Charousset
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Reimplement thread-safe actor clock
parent
d49879bb
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
522 additions
and
240 deletions
+522
-240
libcaf_core/caf/detail/make_unique.hpp
libcaf_core/caf/detail/make_unique.hpp
+32
-0
libcaf_core/caf/detail/simple_actor_clock.hpp
libcaf_core/caf/detail/simple_actor_clock.hpp
+241
-45
libcaf_core/caf/detail/test_actor_clock.hpp
libcaf_core/caf/detail/test_actor_clock.hpp
+0
-4
libcaf_core/caf/detail/thread_safe_actor_clock.hpp
libcaf_core/caf/detail/thread_safe_actor_clock.hpp
+19
-6
libcaf_core/src/simple_actor_clock.cpp
libcaf_core/src/simple_actor_clock.cpp
+129
-83
libcaf_core/src/test_actor_clock.cpp
libcaf_core/src/test_actor_clock.cpp
+6
-22
libcaf_core/src/thread_safe_actor_clock.cpp
libcaf_core/src/thread_safe_actor_clock.cpp
+95
-80
No files found.
libcaf_core/caf/detail/make_unique.hpp
0 → 100644
View file @
8e28cda4
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2019 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#pragma once
#include <memory>
namespace
caf
{
namespace
detail
{
template
<
class
T
,
class
...
Ts
>
std
::
unique_ptr
<
T
>
make_unique
(
Ts
&&
...
xs
)
{
return
std
::
unique_ptr
<
T
>
{
new
T
(
std
::
forward
<
Ts
>
(
xs
)...)};
}
}
// namespace detail
}
// namespace caf
libcaf_core/caf/detail/simple_actor_clock.hpp
View file @
8e28cda4
...
@@ -18,10 +18,13 @@
...
@@ -18,10 +18,13 @@
#pragma once
#pragma once
#include <cstdint>
#include <map>
#include <map>
#include <memory>
#include "caf/actor_clock.hpp"
#include "caf/actor_clock.hpp"
#include "caf/actor_control_block.hpp"
#include "caf/actor_control_block.hpp"
#include "caf/detail/make_unique.hpp"
#include "caf/group.hpp"
#include "caf/group.hpp"
#include "caf/mailbox_element.hpp"
#include "caf/mailbox_element.hpp"
#include "caf/message.hpp"
#include "caf/message.hpp"
...
@@ -35,73 +38,234 @@ class simple_actor_clock : public actor_clock {
...
@@ -35,73 +38,234 @@ class simple_actor_clock : public actor_clock {
public:
public:
// -- member types -----------------------------------------------------------
// -- member types -----------------------------------------------------------
/// Request for a `timeout_msg`.
using
super
=
simple_actor_clock
;
struct
ordinary_timeout
{
struct
event
;
struct
delayed_event
;
/// Owning pointer to events.
using
unique_event_ptr
=
std
::
unique_ptr
<
event
>
;
/// Owning pointer to delayed events.
using
unique_delayed_event_ptr
=
std
::
unique_ptr
<
delayed_event
>
;
/// Maps timeouts to delayed events.
using
schedule_map
=
std
::
multimap
<
time_point
,
unique_delayed_event_ptr
>
;
/// Maps actor IDs to schedule entries.
using
actor_lookup_map
=
std
::
multimap
<
actor_id
,
schedule_map
::
iterator
>
;
/// Lists all possible subtypes of ::event.
enum
event_type
{
ordinary_timeout_type
,
multi_timeout_type
,
request_timeout_type
,
actor_msg_type
,
group_msg_type
,
ordinary_timeout_cancellation_type
,
multi_timeout_cancellation_type
,
request_timeout_cancellation_type
,
timeouts_cancellation_type
,
drop_all_type
,
shutdown_type
,
};
/// Base class for clock events.
struct
event
{
event
(
event_type
t
)
:
subtype
(
t
)
{
// nop
}
virtual
~
event
();
/// Identifies the actual type of this object.
event_type
subtype
;
};
/// An event with a timeout attached to it.
struct
delayed_event
:
event
{
delayed_event
(
event_type
type
,
time_point
due
)
:
event
(
type
),
due
(
due
)
{
// nop
}
/// Timestamp when this event should trigger.
time_point
due
;
/// Links back to the actor lookup map.
actor_lookup_map
::
iterator
backlink
;
};
/// An ordinary timeout event for actors. Only one timeout for any timeout
/// type can be active.
struct
ordinary_timeout
final
:
delayed_event
{
static
constexpr
bool
cancellable
=
true
;
ordinary_timeout
(
time_point
due
,
strong_actor_ptr
self
,
atom_value
type
,
uint64_t
id
)
:
delayed_event
(
ordinary_timeout_type
,
due
),
self
(
std
::
move
(
self
)),
type
(
type
),
id
(
id
)
{
// nop
}
strong_actor_ptr
self
;
strong_actor_ptr
self
;
atom_value
type
;
atom_value
type
;
uint64_t
id
;
uint64_t
id
;
};
};
struct
multi_timeout
{
/// An timeout event for actors that allows multiple active timers for the
/// same type.
struct
multi_timeout
final
:
delayed_event
{
static
constexpr
bool
cancellable
=
true
;
multi_timeout
(
time_point
due
,
strong_actor_ptr
self
,
atom_value
type
,
uint64_t
id
)
:
delayed_event
(
multi_timeout_type
,
due
),
self
(
std
::
move
(
self
)),
type
(
type
),
id
(
id
)
{
// nop
}
strong_actor_ptr
self
;
strong_actor_ptr
self
;
atom_value
type
;
atom_value
type
;
uint64_t
id
;
uint64_t
id
;
};
};
/// Request for a `sec::request_timeout` error.
/// A delayed `sec::request_timeout` error that gets cancelled when the
struct
request_timeout
{
/// request arrives in time.
struct
request_timeout
final
:
delayed_event
{
static
constexpr
bool
cancellable
=
true
;
request_timeout
(
time_point
due
,
strong_actor_ptr
self
,
message_id
id
)
:
delayed_event
(
request_timeout_type
,
due
),
self
(
std
::
move
(
self
)),
id
(
id
)
{
// nop
}
strong_actor_ptr
self
;
strong_actor_ptr
self
;
message_id
id
;
message_id
id
;
};
};
/// Request for sending a message to an actor at a later time.
/// A delayed ::message to an actor.
struct
actor_msg
{
struct
actor_msg
final
:
delayed_event
{
static
constexpr
bool
cancellable
=
false
;
actor_msg
(
time_point
due
,
strong_actor_ptr
receiver
,
mailbox_element_ptr
content
)
:
delayed_event
(
actor_msg_type
,
due
),
receiver
(
std
::
move
(
receiver
)),
content
(
std
::
move
(
content
))
{
// nop
}
strong_actor_ptr
receiver
;
strong_actor_ptr
receiver
;
mailbox_element_ptr
content
;
mailbox_element_ptr
content
;
};
};
/// Request for sending a message to a group at a later time.
/// A delayed ::message to a group.
struct
group_msg
{
struct
group_msg
final
:
delayed_event
{
static
constexpr
bool
cancellable
=
false
;
group_msg
(
time_point
due
,
group
target
,
strong_actor_ptr
sender
,
message
content
)
:
delayed_event
(
group_msg_type
,
due
),
target
(
std
::
move
(
target
)),
sender
(
std
::
move
(
sender
)),
content
(
std
::
move
(
content
))
{
// nop
}
group
target
;
group
target
;
strong_actor_ptr
sender
;
strong_actor_ptr
sender
;
message
content
;
message
content
;
};
};
using
value_type
=
variant
<
ordinary_timeout
,
multi_timeout
,
request_timeout
,
/// Cancels a delayed event.
actor_msg
,
group_msg
>
;
struct
cancellation
:
event
{
cancellation
(
event_type
t
,
actor_id
aid
)
:
event
(
t
),
aid
(
aid
)
{
//nop
}
using
map_type
=
std
::
multimap
<
time_point
,
value_type
>
;
actor_id
aid
;
};
using
secondary_map
=
std
::
multimap
<
abstract_actor
*
,
map_type
::
iterator
>
;
/// Cancels matching ordinary timeouts.
struct
ordinary_timeout_cancellation
final
:
cancellation
{
ordinary_timeout_cancellation
(
actor_id
aid
,
atom_value
type
)
:
cancellation
(
ordinary_timeout_cancellation_type
,
aid
),
type
(
type
)
{
// nop
}
struct
ordinary_predicate
{
atom_value
type
;
atom_value
type
;
bool
operator
()(
const
secondary_map
::
value_type
&
x
)
const
noexcept
;
};
};
struct
multi_predicate
{
/// Cancels the matching multi timeout.
struct
multi_timeout_cancellation
final
:
cancellation
{
multi_timeout_cancellation
(
actor_id
aid
,
atom_value
type
,
uint64_t
id
)
:
cancellation
(
ordinary_timeout_cancellation_type
,
aid
),
type
(
type
),
id
(
id
)
{
// nop
}
atom_value
type
;
atom_value
type
;
bool
operator
()(
const
secondary_map
::
value_type
&
x
)
const
noexcept
;
uint64_t
id
;
};
};
struct
request_predicate
{
/// Cancels a `sec::request_timeout` error.
struct
request_timeout_cancellation
final
:
cancellation
{
request_timeout_cancellation
(
actor_id
aid
,
message_id
id
)
:
cancellation
(
request_timeout_cancellation_type
,
aid
),
id
(
id
)
{
// nop
}
message_id
id
;
message_id
id
;
bool
operator
()(
const
secondary_map
::
value_type
&
x
)
const
noexcept
;
};
};
struct
visitor
{
/// Cancels all timeouts for an actor.
simple_actor_clock
*
thisptr
;
struct
timeouts_cancellation
final
:
cancellation
{
timeouts_cancellation
(
actor_id
aid
)
:
cancellation
(
timeouts_cancellation_type
,
aid
)
{
// nop
}
};
void
operator
()(
ordinary_timeout
&
x
);
/// Cancels all timeouts and messages.
struct
drop_all
final
:
event
{
drop_all
()
:
event
(
drop_all_type
)
{
// nop
}
};
void
operator
()(
multi_timeout
&
x
);
/// Shuts down the actor clock.
struct
shutdown
final
:
event
{
shutdown
()
:
event
(
shutdown_type
)
{
// nop
}
};
void
operator
()(
request_timeout
&
x
);
// -- properties -------------------------------------------------------------
void
operator
()(
actor_msg
&
x
);
const
schedule_map
&
schedule
()
const
{
return
schedule_
;
}
void
operator
()(
group_msg
&
x
);
const
actor_lookup_map
&
actor_lookup
()
const
{
};
return
actor_lookup_
;
}
// -- convenience functions --------------------------------------------------
/// Triggers all timeouts with timestamp <= now.
/// @returns The number of triggered timeouts.
/// @private
size_t
trigger_expired_timeouts
();
// -- overridden member functions --------------------------------------------
void
set_ordinary_timeout
(
time_point
t
,
abstract_actor
*
self
,
void
set_ordinary_timeout
(
time_point
t
,
abstract_actor
*
self
,
atom_value
type
,
uint64_t
id
)
override
;
atom_value
type
,
uint64_t
id
)
override
;
...
@@ -126,20 +290,13 @@ public:
...
@@ -126,20 +290,13 @@ public:
void
cancel_all
()
override
;
void
cancel_all
()
override
;
inline
const
map_type
&
schedule
()
const
{
return
schedule_
;
}
inline
const
secondary_map
&
actor_lookup
()
const
{
return
actor_lookup_
;
}
protected:
protected:
// -- helper functions -------------------------------------------------------
template
<
class
Predicate
>
template
<
class
Predicate
>
secondary_map
::
iterator
lookup
(
abstract_actor
*
self
,
actor_lookup_map
::
iterator
lookup
(
actor_id
aid
,
Predicate
pred
)
{
Predicate
pred
)
{
auto
e
=
actor_lookup_
.
end
();
auto
e
=
actor_lookup_
.
end
();
auto
range
=
actor_lookup_
.
equal_range
(
self
);
auto
range
=
actor_lookup_
.
equal_range
(
aid
);
if
(
range
.
first
==
range
.
second
)
if
(
range
.
first
==
range
.
second
)
return
e
;
return
e
;
auto
i
=
std
::
find_if
(
range
.
first
,
range
.
second
,
pred
);
auto
i
=
std
::
find_if
(
range
.
first
,
range
.
second
,
pred
);
...
@@ -147,8 +304,8 @@ protected:
...
@@ -147,8 +304,8 @@ protected:
}
}
template
<
class
Predicate
>
template
<
class
Predicate
>
void
cancel
(
a
bstract_actor
*
self
,
Predicate
pred
)
{
void
cancel
(
a
ctor_id
aid
,
Predicate
pred
)
{
auto
i
=
lookup
(
self
,
pred
);
auto
i
=
lookup
(
aid
,
pred
);
if
(
i
!=
actor_lookup_
.
end
())
{
if
(
i
!=
actor_lookup_
.
end
())
{
schedule_
.
erase
(
i
->
second
);
schedule_
.
erase
(
i
->
second
);
actor_lookup_
.
erase
(
i
);
actor_lookup_
.
erase
(
i
);
...
@@ -156,19 +313,58 @@ protected:
...
@@ -156,19 +313,58 @@ protected:
}
}
template
<
class
Predicate
>
template
<
class
Predicate
>
void
drop_lookup
(
a
bstract_actor
*
self
,
Predicate
pred
)
{
void
drop_lookup
(
a
ctor_id
aid
,
Predicate
pred
)
{
auto
i
=
lookup
(
self
,
pred
);
auto
i
=
lookup
(
aid
,
pred
);
if
(
i
!=
actor_lookup_
.
end
())
if
(
i
!=
actor_lookup_
.
end
())
actor_lookup_
.
erase
(
i
);
actor_lookup_
.
erase
(
i
);
}
}
void
handle
(
const
ordinary_timeout_cancellation
&
x
);
void
handle
(
const
multi_timeout_cancellation
&
x
);
void
handle
(
const
request_timeout_cancellation
&
x
);
void
handle
(
const
timeouts_cancellation
&
x
);
void
ship
(
delayed_event
&
x
);
template
<
class
T
>
detail
::
enable_if_t
<
T
::
cancellable
>
add_schedule_entry
(
time_point
t
,
std
::
unique_ptr
<
T
>
x
)
{
auto
id
=
x
->
self
->
id
();
auto
i
=
schedule_
.
emplace
(
t
,
std
::
move
(
x
));
i
->
second
->
backlink
=
actor_lookup_
.
emplace
(
id
,
i
);
}
template
<
class
T
>
detail
::
enable_if_t
<!
T
::
cancellable
>
add_schedule_entry
(
time_point
t
,
std
::
unique_ptr
<
T
>
x
)
{
auto
i
=
schedule_
.
emplace
(
t
,
std
::
move
(
x
));
i
->
second
->
backlink
=
actor_lookup_
.
end
();
}
void
add_schedule_entry
(
time_point
t
,
std
::
unique_ptr
<
ordinary_timeout
>
x
);
template
<
class
T
>
void
add_schedule_entry
(
std
::
unique_ptr
<
T
>
x
)
{
auto
due
=
x
->
due
;
add_schedule_entry
(
due
,
std
::
move
(
x
));
}
template
<
class
T
,
class
...
Ts
>
void
new_schedule_entry
(
time_point
t
,
Ts
&&
...
xs
)
{
add_schedule_entry
(
t
,
detail
::
make_unique
<
T
>
(
t
,
std
::
forward
<
Ts
>
(
xs
)...));
}
// -- member variables -------------------------------------------------------
/// Timeout schedule.
/// Timeout schedule.
map_type
schedule_
;
schedule_map
schedule_
;
/// Secondary index for accessing timeouts by actor.
/// Secondary index for accessing timeouts by actor.
secondary
_map
actor_lookup_
;
actor_lookup
_map
actor_lookup_
;
};
};
}
// namespace detail
}
// namespace detail
}
// namespace caf
}
// namespace caf
libcaf_core/caf/detail/test_actor_clock.hpp
View file @
8e28cda4
...
@@ -51,10 +51,6 @@ public:
...
@@ -51,10 +51,6 @@ public:
/// @returns The number of triggered timeouts.
/// @returns The number of triggered timeouts.
size_t
trigger_timeouts
();
size_t
trigger_timeouts
();
/// Triggers all timeouts with timestamp <= now.
/// @returns The number of triggered timeouts.
size_t
trigger_expired_timeouts
();
/// Advances the time by `x` and dispatches timeouts and delayed messages.
/// Advances the time by `x` and dispatches timeouts and delayed messages.
/// @returns The number of triggered timeouts.
/// @returns The number of triggered timeouts.
size_t
advance_time
(
duration_type
x
);
size_t
advance_time
(
duration_type
x
);
...
...
libcaf_core/caf/detail/thread_safe_actor_clock.hpp
View file @
8e28cda4
...
@@ -18,10 +18,14 @@
...
@@ -18,10 +18,14 @@
#pragma once
#pragma once
#include <
mutex
>
#include <
array
>
#include <atomic>
#include <atomic>
#include <condition_variable>
#include <condition_variable>
#include <memory>
#include <mutex>
#include "caf/abstract_actor.hpp"
#include "caf/detail/ringbuffer.hpp"
#include "caf/detail/simple_actor_clock.hpp"
#include "caf/detail/simple_actor_clock.hpp"
namespace
caf
{
namespace
caf
{
...
@@ -29,9 +33,15 @@ namespace detail {
...
@@ -29,9 +33,15 @@ namespace detail {
class
thread_safe_actor_clock
:
public
simple_actor_clock
{
class
thread_safe_actor_clock
:
public
simple_actor_clock
{
public:
public:
// -- constants --------------------------------------------------------------
static
constexpr
size_t
buffer_size
=
64
;
// -- member types -----------------------------------------------------------
using
super
=
simple_actor_clock
;
using
super
=
simple_actor_clock
;
thread_safe_actor_clock
();
// -- member functions -------------------------------------------------------
void
set_ordinary_timeout
(
time_point
t
,
abstract_actor
*
self
,
void
set_ordinary_timeout
(
time_point
t
,
abstract_actor
*
self
,
atom_value
type
,
uint64_t
id
)
override
;
atom_value
type
,
uint64_t
id
)
override
;
...
@@ -61,11 +71,14 @@ public:
...
@@ -61,11 +71,14 @@ public:
void
cancel_dispatch_loop
();
void
cancel_dispatch_loop
();
private:
private:
std
::
recursive_mutex
mx_
;
void
push
(
event
*
ptr
);
std
::
condition_variable_any
cv_
;
std
::
atomic
<
bool
>
done_
;
/// Receives timer events from other threads.
detail
::
ringbuffer
<
unique_event_ptr
,
buffer_size
>
queue_
;
/// Locally caches events for processing.
std
::
array
<
unique_event_ptr
,
buffer_size
>
events_
;
};
};
}
// namespace detail
}
// namespace detail
}
// namespace caf
}
// namespace caf
libcaf_core/src/simple_actor_clock.cpp
View file @
8e28cda4
...
@@ -25,108 +25,40 @@
...
@@ -25,108 +25,40 @@
namespace
caf
{
namespace
caf
{
namespace
detail
{
namespace
detail
{
bool
simple_actor_clock
::
ordinary_predicate
::
simple_actor_clock
::
event
::~
event
()
{
operator
()(
const
secondary_map
::
value_type
&
x
)
const
noexcept
{
// nop
auto
ptr
=
get_if
<
ordinary_timeout
>
(
&
x
.
second
->
second
);
return
ptr
!=
nullptr
?
ptr
->
type
==
type
:
false
;
}
}
bool
simple_actor_clock
::
multi_predicate
::
void
simple_actor_clock
::
set_ordinary_timeout
(
time_point
t
,
operator
()(
const
secondary_map
::
value_type
&
x
)
const
noexcept
{
abstract_actor
*
self
,
auto
ptr
=
get_if
<
multi_timeout
>
(
&
x
.
second
->
second
);
return
ptr
!=
nullptr
?
ptr
->
type
==
type
:
false
;
}
bool
simple_actor_clock
::
request_predicate
::
operator
()(
const
secondary_map
::
value_type
&
x
)
const
noexcept
{
auto
ptr
=
get_if
<
request_timeout
>
(
&
x
.
second
->
second
);
return
ptr
!=
nullptr
?
ptr
->
id
==
id
:
false
;
}
void
simple_actor_clock
::
visitor
::
operator
()(
ordinary_timeout
&
x
)
{
CAF_ASSERT
(
x
.
self
!=
nullptr
);
x
.
self
->
get
()
->
eq_impl
(
make_message_id
(),
x
.
self
,
nullptr
,
timeout_msg
{
x
.
type
,
x
.
id
});
ordinary_predicate
pred
{
x
.
type
};
thisptr
->
drop_lookup
(
x
.
self
->
get
(),
pred
);
}
void
simple_actor_clock
::
visitor
::
operator
()(
multi_timeout
&
x
)
{
CAF_ASSERT
(
x
.
self
!=
nullptr
);
x
.
self
->
get
()
->
eq_impl
(
make_message_id
(),
x
.
self
,
nullptr
,
timeout_msg
{
x
.
type
,
x
.
id
});
multi_predicate
pred
{
x
.
type
};
thisptr
->
drop_lookup
(
x
.
self
->
get
(),
pred
);
}
void
simple_actor_clock
::
visitor
::
operator
()(
request_timeout
&
x
)
{
CAF_ASSERT
(
x
.
self
!=
nullptr
);
x
.
self
->
get
()
->
eq_impl
(
x
.
id
,
x
.
self
,
nullptr
,
sec
::
request_timeout
);
request_predicate
pred
{
x
.
id
};
thisptr
->
drop_lookup
(
x
.
self
->
get
(),
pred
);
}
void
simple_actor_clock
::
visitor
::
operator
()(
actor_msg
&
x
)
{
x
.
receiver
->
enqueue
(
std
::
move
(
x
.
content
),
nullptr
);
}
void
simple_actor_clock
::
visitor
::
operator
()(
group_msg
&
x
)
{
x
.
target
->
eq_impl
(
make_message_id
(),
std
::
move
(
x
.
sender
),
nullptr
,
std
::
move
(
x
.
content
));
}
void
simple_actor_clock
::
set_ordinary_timeout
(
time_point
t
,
abstract_actor
*
self
,
atom_value
type
,
uint64_t
id
)
{
atom_value
type
,
uint64_t
id
)
{
ordinary_predicate
pred
{
type
};
new_schedule_entry
<
ordinary_timeout
>
(
t
,
self
->
ctrl
(),
type
,
id
);
auto
i
=
lookup
(
self
,
pred
);
auto
sptr
=
actor_cast
<
strong_actor_ptr
>
(
self
);
ordinary_timeout
tmp
{
std
::
move
(
sptr
),
type
,
id
};
if
(
i
!=
actor_lookup_
.
end
())
{
schedule_
.
erase
(
i
->
second
);
i
->
second
=
schedule_
.
emplace
(
t
,
std
::
move
(
tmp
));
}
else
{
auto
j
=
schedule_
.
emplace
(
t
,
std
::
move
(
tmp
));
actor_lookup_
.
emplace
(
self
,
j
);
}
}
}
void
simple_actor_clock
::
set_multi_timeout
(
time_point
t
,
abstract_actor
*
self
,
void
simple_actor_clock
::
set_multi_timeout
(
time_point
t
,
abstract_actor
*
self
,
atom_value
type
,
uint64_t
id
)
{
atom_value
type
,
uint64_t
id
)
{
auto
sptr
=
actor_cast
<
strong_actor_ptr
>
(
self
);
new_schedule_entry
<
multi_timeout
>
(
t
,
self
->
ctrl
(),
type
,
id
);
multi_timeout
tmp
{
std
::
move
(
sptr
),
type
,
id
};
auto
j
=
schedule_
.
emplace
(
t
,
std
::
move
(
tmp
));
actor_lookup_
.
emplace
(
self
,
j
);
}
}
void
simple_actor_clock
::
set_request_timeout
(
time_point
t
,
abstract_actor
*
self
,
void
simple_actor_clock
::
set_request_timeout
(
time_point
t
,
abstract_actor
*
self
,
message_id
id
)
{
message_id
id
)
{
request_predicate
pred
{
id
};
new_schedule_entry
<
request_timeout
>
(
t
,
self
->
ctrl
(),
id
);
auto
i
=
lookup
(
self
,
pred
);
auto
sptr
=
actor_cast
<
strong_actor_ptr
>
(
self
);
request_timeout
tmp
{
std
::
move
(
sptr
),
id
};
if
(
i
!=
actor_lookup_
.
end
())
{
schedule_
.
erase
(
i
->
second
);
i
->
second
=
schedule_
.
emplace
(
t
,
std
::
move
(
tmp
));
}
else
{
auto
j
=
schedule_
.
emplace
(
t
,
std
::
move
(
tmp
));
actor_lookup_
.
emplace
(
self
,
j
);
}
}
}
void
simple_actor_clock
::
cancel_ordinary_timeout
(
abstract_actor
*
self
,
void
simple_actor_clock
::
cancel_ordinary_timeout
(
abstract_actor
*
self
,
atom_value
type
)
{
atom_value
type
)
{
ordinary_
predicate
pred
{
type
};
ordinary_
timeout_cancellation
tmp
{
self
->
id
(),
type
};
cancel
(
self
,
pred
);
handle
(
tmp
);
}
}
void
simple_actor_clock
::
cancel_request_timeout
(
abstract_actor
*
self
,
void
simple_actor_clock
::
cancel_request_timeout
(
abstract_actor
*
self
,
message_id
id
)
{
message_id
id
)
{
request_
predicate
pred
{
id
};
request_
timeout_cancellation
tmp
{
self
->
id
(),
id
};
cancel
(
self
,
pred
);
handle
(
tmp
);
}
}
void
simple_actor_clock
::
cancel_timeouts
(
abstract_actor
*
self
)
{
void
simple_actor_clock
::
cancel_timeouts
(
abstract_actor
*
self
)
{
auto
range
=
actor_lookup_
.
equal_range
(
self
);
auto
range
=
actor_lookup_
.
equal_range
(
self
->
id
()
);
if
(
range
.
first
==
range
.
second
)
if
(
range
.
first
==
range
.
second
)
return
;
return
;
for
(
auto
i
=
range
.
first
;
i
!=
range
.
second
;
++
i
)
for
(
auto
i
=
range
.
first
;
i
!=
range
.
second
;
++
i
)
...
@@ -137,14 +69,14 @@ void simple_actor_clock::cancel_timeouts(abstract_actor* self) {
...
@@ -137,14 +69,14 @@ void simple_actor_clock::cancel_timeouts(abstract_actor* self) {
void
simple_actor_clock
::
schedule_message
(
time_point
t
,
void
simple_actor_clock
::
schedule_message
(
time_point
t
,
strong_actor_ptr
receiver
,
strong_actor_ptr
receiver
,
mailbox_element_ptr
content
)
{
mailbox_element_ptr
content
)
{
schedule_
.
emplace
(
t
,
actor_msg
{
std
::
move
(
receiver
),
std
::
move
(
content
)}
);
new_schedule_entry
<
actor_msg
>
(
t
,
std
::
move
(
receiver
),
std
::
move
(
content
)
);
}
}
void
simple_actor_clock
::
schedule_message
(
time_point
t
,
group
target
,
void
simple_actor_clock
::
schedule_message
(
time_point
t
,
group
target
,
strong_actor_ptr
sender
,
strong_actor_ptr
sender
,
message
content
)
{
message
content
)
{
schedule_
.
emplace
(
new_schedule_entry
<
group_msg
>
(
t
,
std
::
move
(
target
),
std
::
move
(
sender
),
t
,
group_msg
{
std
::
move
(
target
),
std
::
move
(
sender
),
std
::
move
(
content
)}
);
std
::
move
(
content
)
);
}
}
void
simple_actor_clock
::
cancel_all
()
{
void
simple_actor_clock
::
cancel_all
()
{
...
@@ -152,5 +84,119 @@ void simple_actor_clock::cancel_all() {
...
@@ -152,5 +84,119 @@ void simple_actor_clock::cancel_all() {
schedule_
.
clear
();
schedule_
.
clear
();
}
}
void
simple_actor_clock
::
ship
(
delayed_event
&
x
)
{
switch
(
x
.
subtype
)
{
case
ordinary_timeout_type
:
{
auto
&
dref
=
static_cast
<
ordinary_timeout
&>
(
x
);
auto
&
self
=
dref
.
self
;
self
->
get
()
->
eq_impl
(
make_message_id
(),
self
,
nullptr
,
timeout_msg
{
dref
.
type
,
dref
.
id
});
break
;
}
case
multi_timeout_type
:
{
auto
&
dref
=
static_cast
<
ordinary_timeout
&>
(
x
);
auto
&
self
=
dref
.
self
;
self
->
get
()
->
eq_impl
(
make_message_id
(),
self
,
nullptr
,
timeout_msg
{
dref
.
type
,
dref
.
id
});
break
;
}
case
request_timeout_type
:
{
auto
&
dref
=
static_cast
<
request_timeout
&>
(
x
);
auto
&
self
=
dref
.
self
;
self
->
get
()
->
eq_impl
(
dref
.
id
,
self
,
nullptr
,
sec
::
request_timeout
);
break
;
}
case
actor_msg_type
:
{
auto
&
dref
=
static_cast
<
actor_msg
&>
(
x
);
dref
.
receiver
->
enqueue
(
std
::
move
(
dref
.
content
),
nullptr
);
break
;
}
case
group_msg_type
:
{
auto
&
dref
=
static_cast
<
group_msg
&>
(
x
);
dref
.
target
->
eq_impl
(
make_message_id
(),
std
::
move
(
dref
.
sender
),
nullptr
,
std
::
move
(
dref
.
content
));
break
;
}
default:
break
;
}
}
void
simple_actor_clock
::
handle
(
const
ordinary_timeout_cancellation
&
x
)
{
auto
pred
=
[
&
](
const
actor_lookup_map
::
value_type
&
kvp
)
{
auto
&
y
=
*
kvp
.
second
->
second
;
return
y
.
subtype
==
ordinary_timeout_type
&&
x
.
type
==
static_cast
<
const
ordinary_timeout
&>
(
y
).
type
;
};
cancel
(
x
.
aid
,
pred
);
}
void
simple_actor_clock
::
handle
(
const
multi_timeout_cancellation
&
x
)
{
auto
pred
=
[
&
](
const
actor_lookup_map
::
value_type
&
kvp
)
{
auto
&
y
=
*
kvp
.
second
->
second
;
if
(
y
.
subtype
!=
ordinary_timeout_type
)
return
false
;
auto
&
dref
=
static_cast
<
const
multi_timeout
&>
(
y
);
return
x
.
type
==
dref
.
type
&&
x
.
id
==
dref
.
id
;
};
cancel
(
x
.
aid
,
pred
);
}
void
simple_actor_clock
::
handle
(
const
request_timeout_cancellation
&
x
)
{
auto
pred
=
[
&
](
const
actor_lookup_map
::
value_type
&
kvp
)
{
auto
&
y
=
*
kvp
.
second
->
second
;
return
y
.
subtype
==
request_timeout_type
&&
x
.
id
==
static_cast
<
const
request_timeout
&>
(
y
).
id
;
};
cancel
(
x
.
aid
,
pred
);
}
void
simple_actor_clock
::
handle
(
const
timeouts_cancellation
&
x
)
{
auto
range
=
actor_lookup_
.
equal_range
(
x
.
aid
);
if
(
range
.
first
==
range
.
second
)
return
;
for
(
auto
i
=
range
.
first
;
i
!=
range
.
second
;
++
i
)
schedule_
.
erase
(
i
->
second
);
actor_lookup_
.
erase
(
range
.
first
,
range
.
second
);
}
size_t
simple_actor_clock
::
trigger_expired_timeouts
()
{
size_t
result
=
0
;
auto
t
=
now
();
auto
i
=
schedule_
.
begin
();
auto
e
=
schedule_
.
end
();
while
(
i
!=
e
&&
i
->
first
<=
t
)
{
auto
ptr
=
std
::
move
(
i
->
second
);
auto
backlink
=
ptr
->
backlink
;
if
(
backlink
!=
actor_lookup_
.
end
())
actor_lookup_
.
erase
(
backlink
);
i
=
schedule_
.
erase
(
i
);
ship
(
*
ptr
);
++
result
;
}
return
result
;
}
void
simple_actor_clock
::
add_schedule_entry
(
time_point
t
,
std
::
unique_ptr
<
ordinary_timeout
>
x
)
{
auto
aid
=
x
->
self
->
id
();
auto
type
=
x
->
type
;
auto
pred
=
[
&
](
const
actor_lookup_map
::
value_type
&
kvp
)
{
auto
&
y
=
*
kvp
.
second
->
second
;
return
y
.
subtype
==
ordinary_timeout_type
&&
static_cast
<
const
ordinary_timeout
&>
(
y
).
type
==
type
;
};
auto
i
=
lookup
(
aid
,
pred
);
if
(
i
!=
actor_lookup_
.
end
())
{
schedule_
.
erase
(
i
->
second
);
i
->
second
=
schedule_
.
emplace
(
t
,
std
::
move
(
x
));
}
else
{
auto
j
=
schedule_
.
emplace
(
t
,
std
::
move
(
x
));
i
=
actor_lookup_
.
emplace
(
aid
,
j
);
}
i
->
second
->
second
->
backlink
=
i
;
}
}
// namespace detail
}
// namespace detail
}
// namespace caf
}
// namespace caf
libcaf_core/src/test_actor_clock.cpp
View file @
8e28cda4
...
@@ -46,13 +46,16 @@ bool test_actor_clock::trigger_timeout() {
...
@@ -46,13 +46,16 @@ bool test_actor_clock::trigger_timeout() {
CAF_LOG_TRACE
(
CAF_ARG2
(
"schedule.size"
,
schedule_
.
size
()));
CAF_LOG_TRACE
(
CAF_ARG2
(
"schedule.size"
,
schedule_
.
size
()));
if
(
schedule_
.
empty
())
if
(
schedule_
.
empty
())
return
false
;
return
false
;
visitor
f
{
this
};
auto
i
=
schedule_
.
begin
();
auto
i
=
schedule_
.
begin
();
auto
tout
=
i
->
first
;
auto
tout
=
i
->
first
;
if
(
tout
>
current_time
)
if
(
tout
>
current_time
)
current_time
=
tout
;
current_time
=
tout
;
visit
(
f
,
i
->
second
);
auto
ptr
=
std
::
move
(
i
->
second
);
schedule_
.
erase
(
i
);
schedule_
.
erase
(
i
);
auto
backlink
=
ptr
->
backlink
;
if
(
backlink
!=
actor_lookup_
.
end
())
actor_lookup_
.
erase
(
backlink
);
ship
(
*
ptr
);
return
true
;
return
true
;
}
}
...
@@ -60,28 +63,9 @@ size_t test_actor_clock::trigger_timeouts() {
...
@@ -60,28 +63,9 @@ size_t test_actor_clock::trigger_timeouts() {
CAF_LOG_TRACE
(
CAF_ARG2
(
"schedule.size"
,
schedule_
.
size
()));
CAF_LOG_TRACE
(
CAF_ARG2
(
"schedule.size"
,
schedule_
.
size
()));
if
(
schedule_
.
empty
())
if
(
schedule_
.
empty
())
return
0u
;
return
0u
;
visitor
f
{
this
};
auto
result
=
schedule_
.
size
();
for
(
auto
&
kvp
:
schedule_
)
{
auto
tout
=
kvp
.
first
;
if
(
tout
>
current_time
)
current_time
=
tout
;
visit
(
f
,
kvp
.
second
);
}
schedule_
.
clear
();
return
result
;
}
size_t
test_actor_clock
::
trigger_expired_timeouts
()
{
CAF_LOG_TRACE
(
CAF_ARG2
(
"schedule.size"
,
schedule_
.
size
()));
visitor
f
{
this
};
size_t
result
=
0
;
size_t
result
=
0
;
auto
i
=
schedule_
.
begin
();
while
(
trigger_timeout
())
while
(
i
!=
schedule_
.
end
()
&&
i
->
first
<=
current_time
)
{
++
result
;
++
result
;
visit
(
f
,
i
->
second
);
i
=
schedule_
.
erase
(
i
);
}
return
result
;
return
result
;
}
}
...
...
libcaf_core/src/thread_safe_actor_clock.cpp
View file @
8e28cda4
...
@@ -18,133 +18,148 @@
...
@@ -18,133 +18,148 @@
#include "caf/detail/thread_safe_actor_clock.hpp"
#include "caf/detail/thread_safe_actor_clock.hpp"
#include "caf/actor_control_block.hpp"
#include "caf/logger.hpp"
#include "caf/sec.hpp"
#include "caf/system_messages.hpp"
namespace
caf
{
namespace
caf
{
namespace
detail
{
namespace
detail
{
namespace
{
using
guard_type
=
std
::
unique_lock
<
std
::
recursive_mutex
>
;
}
// namespace <anonymous>
thread_safe_actor_clock
::
thread_safe_actor_clock
()
:
done_
(
false
)
{
// nop
}
void
thread_safe_actor_clock
::
set_ordinary_timeout
(
time_point
t
,
void
thread_safe_actor_clock
::
set_ordinary_timeout
(
time_point
t
,
abstract_actor
*
self
,
abstract_actor
*
self
,
atom_value
type
,
atom_value
type
,
uint64_t
id
)
{
uint64_t
id
)
{
guard_type
guard
{
mx_
};
push
(
new
ordinary_timeout
(
t
,
self
->
ctrl
(),
type
,
id
));
if
(
!
done_
)
{
super
::
set_ordinary_timeout
(
t
,
self
,
type
,
id
);
cv_
.
notify_all
();
}
}
}
void
thread_safe_actor_clock
::
set_request_timeout
(
time_point
t
,
void
thread_safe_actor_clock
::
set_request_timeout
(
time_point
t
,
abstract_actor
*
self
,
abstract_actor
*
self
,
message_id
id
)
{
message_id
id
)
{
guard_type
guard
{
mx_
};
push
(
new
request_timeout
(
t
,
self
->
ctrl
(),
id
));
if
(
!
done_
)
{
super
::
set_request_timeout
(
t
,
self
,
id
);
cv_
.
notify_all
();
}
}
}
void
thread_safe_actor_clock
::
set_multi_timeout
(
time_point
t
,
abstract_actor
*
self
,
void
thread_safe_actor_clock
::
set_multi_timeout
(
time_point
t
,
atom_value
type
,
uint64_t
id
)
{
abstract_actor
*
self
,
guard_type
guard
{
mx_
};
atom_value
type
,
uint64_t
id
)
{
if
(
!
done_
)
{
push
(
new
multi_timeout
(
t
,
self
->
ctrl
(),
type
,
id
));
super
::
set_multi_timeout
(
t
,
self
,
type
,
id
);
cv_
.
notify_all
();
}
}
}
void
thread_safe_actor_clock
::
cancel_ordinary_timeout
(
abstract_actor
*
self
,
void
thread_safe_actor_clock
::
cancel_ordinary_timeout
(
abstract_actor
*
self
,
atom_value
type
)
{
atom_value
type
)
{
guard_type
guard
{
mx_
};
push
(
new
ordinary_timeout_cancellation
(
self
->
id
(),
type
));
if
(
!
done_
)
{
super
::
cancel_ordinary_timeout
(
self
,
type
);
cv_
.
notify_all
();
}
}
}
void
thread_safe_actor_clock
::
cancel_request_timeout
(
abstract_actor
*
self
,
void
thread_safe_actor_clock
::
cancel_request_timeout
(
abstract_actor
*
self
,
message_id
id
)
{
message_id
id
)
{
guard_type
guard
{
mx_
};
push
(
new
request_timeout_cancellation
(
self
->
id
(),
id
));
if
(
!
done_
)
{
super
::
cancel_request_timeout
(
self
,
id
);
cv_
.
notify_all
();
}
}
}
void
thread_safe_actor_clock
::
cancel_timeouts
(
abstract_actor
*
self
)
{
void
thread_safe_actor_clock
::
cancel_timeouts
(
abstract_actor
*
self
)
{
guard_type
guard
{
mx_
};
push
(
new
timeouts_cancellation
(
self
->
id
()));
if
(
!
done_
)
{
super
::
cancel_timeouts
(
self
);
cv_
.
notify_all
();
}
}
}
void
thread_safe_actor_clock
::
schedule_message
(
time_point
t
,
void
thread_safe_actor_clock
::
schedule_message
(
time_point
t
,
strong_actor_ptr
receiver
,
strong_actor_ptr
receiver
,
mailbox_element_ptr
content
)
{
mailbox_element_ptr
content
)
{
guard_type
guard
{
mx_
};
push
(
new
actor_msg
(
t
,
std
::
move
(
receiver
),
std
::
move
(
content
)));
if
(
!
done_
)
{
super
::
schedule_message
(
t
,
std
::
move
(
receiver
),
std
::
move
(
content
));
cv_
.
notify_all
();
}
}
}
void
thread_safe_actor_clock
::
schedule_message
(
time_point
t
,
group
target
,
void
thread_safe_actor_clock
::
schedule_message
(
time_point
t
,
group
target
,
strong_actor_ptr
sender
,
strong_actor_ptr
sender
,
message
content
)
{
message
content
)
{
guard_type
guard
{
mx_
};
push
(
new
group_msg
(
t
,
std
::
move
(
target
),
std
::
move
(
sender
),
if
(
!
done_
)
{
std
::
move
(
content
)));
super
::
schedule_message
(
t
,
std
::
move
(
target
),
std
::
move
(
sender
),
std
::
move
(
content
));
cv_
.
notify_all
();
}
}
}
void
thread_safe_actor_clock
::
cancel_all
()
{
void
thread_safe_actor_clock
::
cancel_all
()
{
guard_type
guard
{
mx_
};
push
(
new
drop_all
);
super
::
cancel_all
();
cv_
.
notify_all
();
}
}
void
thread_safe_actor_clock
::
run_dispatch_loop
()
{
void
thread_safe_actor_clock
::
run_dispatch_loop
()
{
visitor
f
{
this
};
for
(;;)
{
guard_type
guard
{
mx_
};
// Wait until queue is non-empty.
while
(
done_
==
false
)
{
// Wait for non-empty schedule.
// Note: The thread calling run_dispatch_loop() is guaranteed not to lock
// the mutex recursively. Otherwise, cv_.wait() or cv_.wait_until()
// would be unsafe, because wait operations call unlock() only once.
if
(
schedule_
.
empty
())
{
if
(
schedule_
.
empty
())
{
cv_
.
wait
(
guard
);
queue_
.
wait_nonempty
(
);
}
else
{
}
else
{
auto
tout
=
schedule_
.
begin
()
->
first
;
auto
t
=
schedule_
.
begin
()
->
second
->
due
;
cv_
.
wait_until
(
guard
,
tout
);
if
(
!
queue_
.
wait_nonempty
(
t
))
{
// Handle timeout by shipping timed-out events and starting anew.
trigger_expired_timeouts
();
continue
;
}
}
}
// Double-check whether schedule is non-empty and execute it.
// Push all elements from the queue to the events buffer.
if
(
!
schedule_
.
empty
())
{
auto
i
=
events_
.
begin
();
auto
t
=
now
();
auto
e
=
queue_
.
get_all
(
i
);
auto
i
=
schedule_
.
begin
();
for
(;
i
!=
e
;
++
i
)
{
while
(
i
!=
schedule_
.
end
()
&&
i
->
first
<=
t
)
{
auto
&
x
=
*
i
;
visit
(
f
,
i
->
second
);
CAF_ASSERT
(
x
!=
nullptr
);
i
=
schedule_
.
erase
(
i
);
switch
(
x
->
subtype
)
{
case
ordinary_timeout_cancellation_type
:
{
handle
(
static_cast
<
ordinary_timeout_cancellation
&>
(
*
x
));
break
;
}
case
request_timeout_cancellation_type
:
{
handle
(
static_cast
<
request_timeout_cancellation
&>
(
*
x
));
break
;
}
case
timeouts_cancellation_type
:
{
handle
(
static_cast
<
timeouts_cancellation
&>
(
*
x
));
break
;
}
case
drop_all_type
:
{
schedule_
.
clear
();
actor_lookup_
.
clear
();
break
;
}
case
shutdown_type
:
{
schedule_
.
clear
();
actor_lookup_
.
clear
();
// Call it a day.
return
;
}
case
ordinary_timeout_type
:
{
auto
dptr
=
static_cast
<
ordinary_timeout
*>
(
x
.
release
());
add_schedule_entry
(
std
::
unique_ptr
<
ordinary_timeout
>
{
dptr
});
break
;
}
case
multi_timeout_type
:
{
auto
dptr
=
static_cast
<
multi_timeout
*>
(
x
.
release
());
add_schedule_entry
(
std
::
unique_ptr
<
multi_timeout
>
{
dptr
});
break
;
}
case
request_timeout_type
:
{
auto
dptr
=
static_cast
<
request_timeout
*>
(
x
.
release
());
add_schedule_entry
(
std
::
unique_ptr
<
request_timeout
>
{
dptr
});
break
;
}
case
actor_msg_type
:
{
auto
dptr
=
static_cast
<
actor_msg
*>
(
x
.
release
());
add_schedule_entry
(
std
::
unique_ptr
<
actor_msg
>
{
dptr
});
break
;
}
case
group_msg_type
:
{
auto
dptr
=
static_cast
<
group_msg
*>
(
x
.
release
());
add_schedule_entry
(
std
::
unique_ptr
<
group_msg
>
{
dptr
});
break
;
}
default:
{
CAF_LOG_ERROR
(
"unexpected event type"
);
break
;
}
}
}
x
.
reset
();
}
}
}
}
schedule_
.
clear
();
}
}
void
thread_safe_actor_clock
::
cancel_dispatch_loop
()
{
void
thread_safe_actor_clock
::
cancel_dispatch_loop
()
{
guard_type
guard
{
mx_
};
push
(
new
shutdown
);
done_
=
true
;
}
cv_
.
notify_all
();
void
thread_safe_actor_clock
::
push
(
event
*
ptr
)
{
queue_
.
push_back
(
unique_event_ptr
{
ptr
});
}
}
}
// namespace detail
}
// namespace detail
...
...
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