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
a19cb8e6
Unverified
Commit
a19cb8e6
authored
Jul 27, 2023
by
Samir Halilčević
Committed by
GitHub
Jul 27, 2023
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Refactor multiplexer to be an interface
parent
bb22e7fe
Changes
6
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
554 additions
and
659 deletions
+554
-659
libcaf_net/CMakeLists.txt
libcaf_net/CMakeLists.txt
+0
-1
libcaf_net/caf/detail/pollset_updater.cpp
libcaf_net/caf/detail/pollset_updater.cpp
+0
-102
libcaf_net/caf/detail/pollset_updater.hpp
libcaf_net/caf/detail/pollset_updater.hpp
+0
-64
libcaf_net/caf/net/fwd.hpp
libcaf_net/caf/net/fwd.hpp
+0
-6
libcaf_net/caf/net/multiplexer.cpp
libcaf_net/caf/net/multiplexer.cpp
+531
-334
libcaf_net/caf/net/multiplexer.hpp
libcaf_net/caf/net/multiplexer.hpp
+23
-152
No files found.
libcaf_net/CMakeLists.txt
View file @
a19cb8e6
...
...
@@ -29,7 +29,6 @@ caf_add_component(
${
CAF_NET_HEADERS
}
SOURCES
caf/detail/convert_ip_endpoint.cpp
caf/detail/pollset_updater.cpp
caf/detail/rfc6455.cpp
caf/detail/rfc6455.test.cpp
caf/net/abstract_actor_shell.cpp
...
...
libcaf_net/caf/detail/pollset_updater.cpp
deleted
100644 → 0
View file @
bb22e7fe
// This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
#include "caf/detail/pollset_updater.hpp"
#include "caf/net/multiplexer.hpp"
#include "caf/action.hpp"
#include "caf/actor_system.hpp"
#include "caf/logger.hpp"
#include "caf/sec.hpp"
#include "caf/span.hpp"
#include <cstring>
namespace
caf
::
detail
{
// -- constructors, destructors, and assignment operators ----------------------
pollset_updater
::
pollset_updater
(
net
::
pipe_socket
fd
)
:
fd_
(
fd
)
{
// nop
}
// -- factories ----------------------------------------------------------------
std
::
unique_ptr
<
pollset_updater
>
pollset_updater
::
make
(
net
::
pipe_socket
fd
)
{
return
std
::
make_unique
<
pollset_updater
>
(
fd
);
}
// -- interface functions ------------------------------------------------------
error
pollset_updater
::
start
(
net
::
socket_manager
*
owner
)
{
CAF_LOG_TRACE
(
""
);
owner_
=
owner
;
mpx_
=
owner
->
mpx_ptr
();
return
net
::
nonblocking
(
fd_
,
true
);
}
net
::
socket
pollset_updater
::
handle
()
const
{
return
fd_
;
}
void
pollset_updater
::
handle_read_event
()
{
CAF_LOG_TRACE
(
""
);
auto
as_mgr
=
[](
intptr_t
ptr
)
{
return
intrusive_ptr
{
reinterpret_cast
<
net
::
socket_manager
*>
(
ptr
),
false
};
};
auto
add_action
=
[
this
](
intptr_t
ptr
)
{
auto
f
=
action
{
intrusive_ptr
{
reinterpret_cast
<
action
::
impl
*>
(
ptr
),
false
}};
mpx_
->
pending_actions_
.
push_back
(
std
::
move
(
f
));
};
for
(;;)
{
CAF_ASSERT
((
buf_
.
size
()
-
buf_size_
)
>
0
);
auto
num_bytes
=
read
(
fd_
,
make_span
(
buf_
.
data
()
+
buf_size_
,
buf_
.
size
()
-
buf_size_
));
if
(
num_bytes
>
0
)
{
buf_size_
+=
static_cast
<
size_t
>
(
num_bytes
);
if
(
buf_
.
size
()
==
buf_size_
)
{
buf_size_
=
0
;
auto
opcode
=
static_cast
<
uint8_t
>
(
buf_
[
0
]);
intptr_t
ptr
;
memcpy
(
&
ptr
,
buf_
.
data
()
+
1
,
sizeof
(
intptr_t
));
switch
(
static_cast
<
code
>
(
opcode
))
{
case
code
:
:
start_manager
:
mpx_
->
do_start
(
as_mgr
(
ptr
));
break
;
case
code
:
:
run_action
:
add_action
(
ptr
);
break
;
case
code
:
:
shutdown
:
CAF_ASSERT
(
ptr
==
0
);
mpx_
->
do_shutdown
();
break
;
default:
CAF_LOG_ERROR
(
"opcode not recognized: "
<<
CAF_ARG
(
opcode
));
break
;
}
}
}
else
if
(
num_bytes
==
0
)
{
CAF_LOG_DEBUG
(
"pipe closed, assume shutdown"
);
owner_
->
deregister
();
return
;
}
else
if
(
net
::
last_socket_error_is_temporary
())
{
return
;
}
else
{
CAF_LOG_ERROR
(
"pollset updater failed to read from the pipe"
);
owner_
->
deregister
();
return
;
}
}
}
void
pollset_updater
::
handle_write_event
()
{
owner_
->
deregister_writing
();
}
void
pollset_updater
::
abort
(
const
error
&
)
{
// nop
}
}
// namespace caf::detail
libcaf_net/caf/detail/pollset_updater.hpp
deleted
100644 → 0
View file @
bb22e7fe
// This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
#pragma once
#include "caf/net/pipe_socket.hpp"
#include "caf/net/socket_event_layer.hpp"
#include "caf/net/socket_manager.hpp"
#include "caf/detail/net_export.hpp"
#include <array>
#include <cstddef>
#include <cstdint>
#include <mutex>
namespace
caf
::
detail
{
class
CAF_NET_EXPORT
pollset_updater
:
public
net
::
socket_event_layer
{
public:
// -- member types -----------------------------------------------------------
using
super
=
net
::
socket_manager
;
using
msg_buf
=
std
::
array
<
std
::
byte
,
sizeof
(
intptr_t
)
+
1
>
;
enum
class
code
:
uint8_t
{
start_manager
,
shutdown_reading
,
shutdown_writing
,
run_action
,
shutdown
,
};
// -- constructors, destructors, and assignment operators --------------------
explicit
pollset_updater
(
net
::
pipe_socket
fd
);
// -- factories --------------------------------------------------------------
static
std
::
unique_ptr
<
pollset_updater
>
make
(
net
::
pipe_socket
fd
);
// -- implementation of socket_event_layer -----------------------------------
error
start
(
net
::
socket_manager
*
owner
)
override
;
net
::
socket
handle
()
const
override
;
void
handle_read_event
()
override
;
void
handle_write_event
()
override
;
void
abort
(
const
error
&
reason
)
override
;
private:
net
::
pipe_socket
fd_
;
net
::
socket_manager
*
owner_
=
nullptr
;
net
::
multiplexer
*
mpx_
=
nullptr
;
msg_buf
buf_
;
size_t
buf_size_
=
0
;
};
}
// namespace caf::detail
libcaf_net/caf/net/fwd.hpp
View file @
a19cb8e6
...
...
@@ -90,12 +90,6 @@ enum class errc;
}
// namespace caf::net::octet_stream
namespace
caf
::
detail
{
class
pollset_updater
;
}
// namespace caf::detail
namespace
caf
::
net
::
lp
{
class
client
;
...
...
libcaf_net/caf/net/multiplexer.cpp
View file @
a19cb8e6
...
...
@@ -4,23 +4,38 @@
#include "caf/net/multiplexer.hpp"
#include "caf/net/fwd.hpp"
#include "caf/net/middleman.hpp"
#include "caf/net/pipe_socket.hpp"
#include "caf/net/socket.hpp"
#include "caf/net/socket_event_layer.hpp"
#include "caf/net/socket_manager.hpp"
#include "caf/action.hpp"
#include "caf/actor_system.hpp"
#include "caf/async/execution_context.hpp"
#include "caf/byte.hpp"
#include "caf/config.hpp"
#include "caf/detail/pollset_updater.hpp"
#include "caf/detail/atomic_ref_counted.hpp"
#include "caf/detail/net_export.hpp"
#include "caf/error.hpp"
#include "caf/expected.hpp"
#include "caf/logger.hpp"
#include "caf/make_counted.hpp"
#include "caf/ref_counted.hpp"
#include "caf/sec.hpp"
#include "caf/span.hpp"
#include "caf/unordered_flat_map.hpp"
#include <algorithm>
#include <array>
#include <cstddef>
#include <cstdint>
#include <deque>
#include <memory>
#include <mutex>
#include <optional>
#include <thread>
#ifndef CAF_WINDOWS
# include <poll.h>
...
...
@@ -31,6 +46,10 @@
namespace
caf
::
net
{
namespace
{
class
default_multiplexer
;
#ifndef POLLRDHUP
# define POLLRDHUP POLLHUP
#endif
...
...
@@ -39,8 +58,6 @@ namespace caf::net {
# define POLLPRI POLLIN
#endif
namespace
{
#ifdef CAF_WINDOWS
// From the MSDN: If the POLLPRI flag is set on a socket for the Microsoft
// Winsock provider, the WSAPoll function will fail.
...
...
@@ -53,174 +70,200 @@ const short error_mask = POLLRDHUP | POLLERR | POLLHUP | POLLNVAL;
const
short
output_mask
=
POLLOUT
;
}
// namespace
class
pollset_updater
:
public
socket_event_layer
{
public:
// -- member types -----------------------------------------------------------
// -- static utility functions -------------------------------------------------
using
super
=
socket_manager
;
#ifdef CAF_LINUX
using
msg_buf
=
std
::
array
<
std
::
byte
,
sizeof
(
intptr_t
)
+
1
>
;
void
multiplexer
::
block_sigpipe
()
{
sigset_t
sigpipe_mask
;
sigemptyset
(
&
sigpipe_mask
);
sigaddset
(
&
sigpipe_mask
,
SIGPIPE
);
sigset_t
saved_mask
;
if
(
pthread_sigmask
(
SIG_BLOCK
,
&
sigpipe_mask
,
&
saved_mask
)
==
-
1
)
{
perror
(
"pthread_sigmask"
);
exit
(
1
);
}
}
enum
class
code
:
uint8_t
{
start_manager
,
shutdown_reading
,
shutdown_writing
,
run_action
,
shutdown
,
};
#else
// -- constructors, destructors, and assignment operators --------------------
void
multiplexer
::
block_sigpipe
(
)
{
explicit
pollset_updater
(
pipe_socket
fd
)
:
fd_
(
fd
)
{
// nop
}
}
#endif
// -- factories --------------------------------------------------------------
multiplexer
*
multiplexer
::
from
(
actor_system
&
sys
)
{
return
sys
.
network_manager
().
mpx_ptr
(
);
}
static
std
::
unique_ptr
<
pollset_updater
>
make
(
pipe_socket
fd
)
{
return
std
::
make_unique
<
pollset_updater
>
(
fd
);
}
// -- constructors, destructors, and assignment operators ----------------------
// -- implementation of socket_event_layer -----------------------------------
error
start
(
socket_manager
*
owner
)
override
;
multiplexer
::
multiplexer
(
middleman
*
owner
)
:
owner_
(
owner
)
{
socket
handle
()
const
override
{
return
fd_
;
}
void
handle_read_event
()
override
;
void
handle_write_event
()
override
{
owner_
->
deregister_writing
();
}
void
abort
(
const
error
&
)
override
{
// nop
}
}
multiplexer
::~
multiplexer
()
{
private:
pipe_socket
fd_
;
socket_manager
*
owner_
=
nullptr
;
default_multiplexer
*
mpx_
=
nullptr
;
msg_buf
buf_
;
size_t
buf_size_
=
0
;
};
/// Multiplexes any number of ::socket_manager objects with a ::socket.
class
default_multiplexer
:
public
detail
::
atomic_ref_counted
,
public
multiplexer
{
public:
// -- member types -----------------------------------------------------------
struct
poll_update
{
short
events
=
0
;
socket_manager_ptr
mgr
;
};
using
poll_update_map
=
unordered_flat_map
<
socket
,
poll_update
>
;
using
pollfd_list
=
std
::
vector
<
pollfd
>
;
using
manager_list
=
std
::
vector
<
socket_manager_ptr
>
;
// -- friends ----------------------------------------------------------------
friend
class
pollset_updater
;
// Needs access to the `do_*` functions.
// -- constructors, destructors, and assignment operators --------------------
explicit
default_multiplexer
(
middleman
*
parent
)
:
owner_
(
parent
)
{
// nop
}
}
// -- initialization ---------------------------
--------------------------------
// -- implementation of caf::net::multiplexer
--------------------------------
error
multiplexer
::
init
()
{
error
init
()
override
{
auto
pipe_handles
=
make_pipe
();
if
(
!
pipe_handles
)
return
std
::
move
(
pipe_handles
.
error
());
auto
updater
=
detail
::
pollset_updater
::
make
(
pipe_handles
->
first
);
auto
updater
=
pollset_updater
::
make
(
pipe_handles
->
first
);
auto
mgr
=
socket_manager
::
make
(
this
,
std
::
move
(
updater
));
if
(
auto
err
=
mgr
->
start
())
if
(
auto
err
=
mgr
->
start
())
{
close
(
pipe_handles
->
second
);
return
err
;
}
write_handle_
=
pipe_handles
->
second
;
pollset_
.
emplace_back
(
pollfd
{
pipe_handles
->
first
.
id
,
input_mask
,
0
});
managers_
.
emplace_back
(
mgr
);
return
none
;
}
// -- properties ---------------------------------------------------------------
}
size_t
multiplexer
::
num_socket_managers
()
const
noexcept
{
size_t
num_socket_managers
()
const
noexcept
override
{
return
managers_
.
size
();
}
ptrdiff_t
multiplexer
::
index_of
(
const
socket_manager_ptr
&
mgr
)
const
noexcept
{
auto
first
=
managers_
.
begin
();
auto
last
=
managers_
.
end
();
auto
i
=
std
::
find
(
first
,
last
,
mgr
);
return
i
==
last
?
-
1
:
std
::
distance
(
first
,
i
);
}
ptrdiff_t
multiplexer
::
index_of
(
socket
fd
)
const
noexcept
{
auto
first
=
pollset_
.
begin
();
auto
last
=
pollset_
.
end
();
auto
i
=
std
::
find_if
(
first
,
last
,
[
fd
](
const
pollfd
&
x
)
{
return
x
.
fd
==
fd
.
id
;
});
return
i
==
last
?
-
1
:
std
::
distance
(
first
,
i
);
}
}
middleman
&
multiplexer
::
owner
()
{
middleman
&
owner
()
override
{
CAF_ASSERT
(
owner_
!=
nullptr
);
return
*
owner_
;
}
actor_system
&
multiplexer
::
system
()
{
}
actor_system
&
system
()
override
{
return
owner
().
system
();
}
}
// -- implementation of execution_context --
------------------------------------
// -- implementation of execution_context
------------------------------------
void
multiplexer
::
ref_execution_context
()
const
noexcept
{
void
ref_execution_context
()
const
noexcept
override
{
ref
();
}
}
void
multiplexer
::
deref_execution_context
()
const
noexcept
{
void
deref_execution_context
()
const
noexcept
override
{
deref
();
}
}
void
multiplexer
::
schedule
(
action
what
)
{
void
schedule
(
action
what
)
override
{
CAF_LOG_TRACE
(
""
);
if
(
std
::
this_thread
::
get_id
()
==
tid_
)
{
pending_actions_
.
push_back
(
what
);
pending_actions
.
push_back
(
what
);
}
else
{
auto
ptr
=
std
::
move
(
what
).
as_intrusive_ptr
().
release
();
write_to_pipe
(
detail
::
pollset_updater
::
code
::
run_action
,
ptr
);
write_to_pipe
(
pollset_updater
::
code
::
run_action
,
ptr
);
}
}
}
void
multiplexer
::
watch
(
disposable
what
)
{
void
watch
(
disposable
what
)
override
{
watched_
.
emplace_back
(
what
);
}
}
// -- thread-safe signaling --
--------------------------------------------------
// -- thread-safe signaling
--------------------------------------------------
void
multiplexer
::
start
(
socket_manager_ptr
mgr
)
{
void
start
(
socket_manager_ptr
mgr
)
override
{
CAF_LOG_TRACE
(
CAF_ARG2
(
"socket"
,
mgr
->
handle
().
id
));
if
(
std
::
this_thread
::
get_id
()
==
tid_
)
{
do_start
(
mgr
);
}
else
{
write_to_pipe
(
detail
::
pollset_updater
::
code
::
start_manager
,
mgr
.
release
());
write_to_pipe
(
pollset_updater
::
code
::
start_manager
,
mgr
.
release
());
}
}
}
void
multiplexer
::
shutdown
()
{
void
shutdown
()
override
{
CAF_LOG_TRACE
(
""
);
// Note: there is no 'shortcut' when calling the function in the multiplexer's
// thread, because do_shutdown calls apply_updates. This must only be called
//
from the pollset_updater.
// Note: there is no 'shortcut' when calling the function in the
// default_multiplexer's thread, because do_shutdown calls apply_updates.
// This must only be called
from the pollset_updater.
CAF_LOG_DEBUG
(
"push shutdown event to pipe"
);
write_to_pipe
(
detail
::
pollset_updater
::
code
::
shutdown
,
write_to_pipe
(
pollset_updater
::
code
::
shutdown
,
static_cast
<
socket_manager
*>
(
nullptr
));
}
}
// -- callbacks for socket managers --
------------------------------------------
// -- callbacks for socket managers
------------------------------------------
void
multiplexer
::
register_reading
(
socket_manager
*
mgr
)
{
void
register_reading
(
socket_manager
*
mgr
)
override
{
CAF_LOG_TRACE
(
CAF_ARG2
(
"socket"
,
mgr
->
handle
().
id
));
update_for
(
mgr
).
events
|=
input_mask
;
}
}
void
multiplexer
::
register_writing
(
socket_manager
*
mgr
)
{
void
register_writing
(
socket_manager
*
mgr
)
override
{
CAF_LOG_TRACE
(
CAF_ARG2
(
"socket"
,
mgr
->
handle
().
id
));
update_for
(
mgr
).
events
|=
output_mask
;
}
}
void
multiplexer
::
deregister_reading
(
socket_manager
*
mgr
)
{
void
deregister_reading
(
socket_manager
*
mgr
)
override
{
CAF_LOG_TRACE
(
CAF_ARG2
(
"socket"
,
mgr
->
handle
().
id
));
update_for
(
mgr
).
events
&=
~
input_mask
;
}
}
void
multiplexer
::
deregister_writing
(
socket_manager
*
mgr
)
{
void
deregister_writing
(
socket_manager
*
mgr
)
override
{
CAF_LOG_TRACE
(
CAF_ARG2
(
"socket"
,
mgr
->
handle
().
id
));
update_for
(
mgr
).
events
&=
~
output_mask
;
}
}
void
multiplexer
::
deregister
(
socket_manager
*
mgr
)
{
void
deregister
(
socket_manager
*
mgr
)
override
{
CAF_LOG_TRACE
(
CAF_ARG2
(
"socket"
,
mgr
->
handle
().
id
));
update_for
(
mgr
).
events
=
0
;
}
}
bool
multiplexer
::
is_reading
(
const
socket_manager
*
mgr
)
const
noexcept
{
bool
is_reading
(
const
socket_manager
*
mgr
)
const
noexcept
override
{
return
(
active_mask_of
(
mgr
)
&
input_mask
)
!=
0
;
}
}
bool
multiplexer
::
is_writing
(
const
socket_manager
*
mgr
)
const
noexcept
{
bool
is_writing
(
const
socket_manager
*
mgr
)
const
noexcept
override
{
return
(
active_mask_of
(
mgr
)
&
output_mask
)
!=
0
;
}
}
// -- control flow --
-----------------------------------------------------------
// -- control flow
-----------------------------------------------------------
bool
multiplexer
::
poll_once
(
bool
blocking
)
{
bool
poll_once
(
bool
blocking
)
override
{
CAF_LOG_TRACE
(
CAF_ARG
(
blocking
));
if
(
pollset_
.
empty
())
return
false
;
...
...
@@ -239,9 +282,10 @@ bool multiplexer::poll_once(bool blocking) {
<<
presult
<<
"event(s)"
);
// Scan pollset for events.
if
(
auto
revents
=
pollset_
[
0
].
revents
;
revents
!=
0
)
{
// Index 0 is always the pollset updater. This is the only handler that
// is allowed to modify pollset_ and managers_. Since this may very well
// mess with the for loop below, we process this handler first.
// Index 0 is always the pollset updater. This is the only handler
// that is allowed to modify pollset_ and managers_. Since this may
// very well mess with the for loop below, we process this handler
// first.
auto
mgr
=
managers_
[
0
];
handle
(
mgr
,
pollset_
[
0
].
events
,
revents
);
--
presult
;
...
...
@@ -283,14 +327,9 @@ bool multiplexer::poll_once(bool blocking) {
}
}
}
}
void
multiplexer
::
poll
()
{
while
(
poll_once
(
false
))
;
// repeat
}
}
void
multiplexer
::
apply_updates
()
{
void
apply_updates
()
override
{
CAF_LOG_DEBUG
(
"apply"
<<
updates_
.
size
()
<<
"updates"
);
for
(;;)
{
if
(
!
updates_
.
empty
())
{
...
...
@@ -311,28 +350,29 @@ void multiplexer::apply_updates() {
}
updates_
.
clear
();
}
while
(
!
pending_actions_
.
empty
())
{
auto
next
=
std
::
move
(
pending_actions_
.
front
());
pending_actions_
.
pop_front
();
while
(
!
pending_actions
.
empty
())
{
auto
next
=
std
::
move
(
pending_actions
.
front
());
pending_actions
.
pop_front
();
next
.
run
();
}
if
(
updates_
.
empty
())
return
;
}
}
}
void
multiplexer
::
set_thread_id
()
{
void
set_thread_id
()
override
{
CAF_LOG_TRACE
(
""
);
tid_
=
std
::
this_thread
::
get_id
();
}
}
void
multiplexer
::
run
()
{
void
run
()
override
{
CAF_LOG_TRACE
(
""
);
CAF_LOG_DEBUG
(
"run multiplexer"
<<
CAF_ARG
(
input_mask
)
<<
CAF_ARG
(
error_mask
)
CAF_LOG_DEBUG
(
"run default_multiplexer"
<<
CAF_ARG
(
input_mask
)
<<
CAF_ARG
(
error_mask
)
<<
CAF_ARG
(
output_mask
));
// On systems like Linux, we cannot disable sigpipe on the socket alone. We
// need to block the signal at thread level since some APIs (such as OpenSSL)
//
are unsafe to call otherwise.
// need to block the signal at thread level since some APIs (such as
// OpenSSL)
are unsafe to call otherwise.
block_sigpipe
();
while
(
!
shutting_down_
||
pollset_
.
size
()
>
1
||
!
watched_
.
empty
())
{
poll_once
(
true
);
...
...
@@ -344,26 +384,71 @@ void multiplexer::run() {
close
(
write_handle_
);
write_handle_
=
pipe_socket
{};
}
}
}
// -- internal callbacks the pollset updater ---------------------------------
void
do_shutdown
()
{
// Note: calling apply_updates here is only safe because we know that the
// pollset updater runs outside of the for-loop in run_once.
CAF_LOG_DEBUG
(
"initiate shutdown"
);
shutting_down_
=
true
;
apply_updates
();
// Skip the first manager (the pollset updater).
for
(
size_t
i
=
1
;
i
<
managers_
.
size
();
++
i
)
managers_
[
i
]
->
dispose
();
apply_updates
();
}
// -- utility functions --------------------------------------------------------
void
do_start
(
const
socket_manager_ptr
&
mgr
)
{
CAF_LOG_TRACE
(
CAF_ARG2
(
"socket"
,
mgr
->
handle
().
id
));
if
(
!
shutting_down_
)
{
error
err
;
err
=
mgr
->
start
();
if
(
err
)
{
CAF_LOG_DEBUG
(
"mgr->init failed: "
<<
err
);
// The socket manager should not register itself for any events if
// initialization fails. Purge any state just in case.
update_for
(
mgr
.
get
()).
events
=
0
;
}
}
}
// -- utility functions ------------------------------------------------------
/// Returns the index of `mgr` in the pollset or `-1`.
ptrdiff_t
index_of
(
const
socket_manager_ptr
&
mgr
)
const
noexcept
{
auto
first
=
managers_
.
begin
();
auto
last
=
managers_
.
end
();
auto
i
=
std
::
find
(
first
,
last
,
mgr
);
return
i
==
last
?
-
1
:
std
::
distance
(
first
,
i
);
}
/// Returns the index of `fd` in the pollset or `-1`.
ptrdiff_t
index_of
(
socket
fd
)
const
noexcept
{
auto
first
=
pollset_
.
begin
();
auto
last
=
pollset_
.
end
();
auto
i
=
std
::
find_if
(
first
,
last
,
[
fd
](
const
pollfd
&
x
)
{
return
x
.
fd
==
fd
.
id
;
});
return
i
==
last
?
-
1
:
std
::
distance
(
first
,
i
);
}
void
multiplexer
::
handle
(
const
socket_manager_ptr
&
mgr
,
[[
maybe_unused
]]
short
events
,
short
revents
)
{
/// Handles an I/O event on given manager.
void
handle
(
const
socket_manager_ptr
&
mgr
,
short
events
,
short
revents
)
{
CAF_LOG_TRACE
(
CAF_ARG2
(
"socket"
,
mgr
->
handle
().
id
)
<<
CAF_ARG
(
events
)
<<
CAF_ARG
(
revents
));
CAF_ASSERT
(
mgr
!=
nullptr
);
bool
checkerror
=
true
;
CAF_LOG_DEBUG
(
"handle event on socket"
<<
mgr
->
handle
().
id
<<
CAF_ARG
(
events
)
<<
CAF_ARG
(
revents
));
CAF_LOG_DEBUG
(
"handle event on socket"
<<
mgr
->
handle
().
id
<<
CAF_ARG
(
events
)
<<
CAF_ARG
(
revents
));
// Note: we double-check whether the manager is actually reading because a
// previous action from the pipe may have disabled reading.
if
((
revents
&
input_mask
)
!=
0
&&
is_reading
(
mgr
.
get
()))
{
checkerror
=
false
;
mgr
->
handle_read_event
();
}
// Similar reasoning than before: double-check whether this event should still
//
get dispatched.
// Similar reasoning than before: double-check whether this event should
// still
get dispatched.
if
((
revents
&
output_mask
)
!=
0
&&
is_writing
(
mgr
.
get
()))
{
checkerror
=
false
;
mgr
->
handle_write_event
();
...
...
@@ -377,9 +462,11 @@ void multiplexer::handle(const socket_manager_ptr& mgr,
mgr
->
handle_error
(
sec
::
socket_operation_failed
);
update_for
(
mgr
.
get
()).
events
=
0
;
}
}
}
multiplexer
::
poll_update
&
multiplexer
::
update_for
(
ptrdiff_t
index
)
{
/// Returns a change entry for the socket at given index. Lazily creates a new
/// entry before returning if necessary.
poll_update
&
update_for
(
ptrdiff_t
index
)
{
auto
fd
=
socket
{
pollset_
[
index
].
fd
};
if
(
auto
i
=
updates_
.
find
(
fd
);
i
!=
updates_
.
end
())
{
return
i
->
second
;
...
...
@@ -388,25 +475,29 @@ multiplexer::poll_update& multiplexer::update_for(ptrdiff_t index) {
managers_
[
index
]});
return
updates_
.
container
().
back
().
second
;
}
}
}
multiplexer
::
poll_update
&
multiplexer
::
update_for
(
socket_manager
*
mgr
)
{
/// Returns a change entry for the socket of the manager.
poll_update
&
update_for
(
socket_manager
*
mgr
)
{
auto
fd
=
mgr
->
handle
();
if
(
auto
i
=
updates_
.
find
(
fd
);
i
!=
updates_
.
end
())
{
return
i
->
second
;
}
else
if
(
auto
index
=
index_of
(
fd
);
index
!=
-
1
)
{
updates_
.
container
().
emplace_back
(
fd
,
poll_update
{
pollset_
[
index
].
events
,
socket_manager_ptr
{
mgr
}});
updates_
.
container
().
emplace_back
(
fd
,
poll_update
{
pollset_
[
index
].
events
,
socket_manager_ptr
{
mgr
}});
return
updates_
.
container
().
back
().
second
;
}
else
{
updates_
.
container
().
emplace_back
(
fd
,
poll_update
{
0
,
mgr
});
return
updates_
.
container
().
back
().
second
;
}
}
}
template
<
class
T
>
void
multiplexer
::
write_to_pipe
(
uint8_t
opcode
,
T
*
ptr
)
{
detail
::
pollset_updater
::
msg_buf
buf
;
/// Writes `opcode` and pointer to `mgr` the the pipe for handling an event
/// later via the pollset updater.
/// @warning assumes ownership of @p ptr.
template
<
class
T
>
void
write_to_pipe
(
uint8_t
opcode
,
T
*
ptr
)
{
pollset_updater
::
msg_buf
buf
;
// Note: no intrusive_ptr_add_ref(ptr) since we take ownership of `ptr`.
buf
[
0
]
=
static_cast
<
std
::
byte
>
(
opcode
);
auto
value
=
reinterpret_cast
<
intptr_t
>
(
ptr
);
...
...
@@ -419,9 +510,16 @@ void multiplexer::write_to_pipe(uint8_t opcode, T* ptr) {
}
if
(
res
<=
0
&&
ptr
)
intrusive_ptr_release
(
ptr
);
}
}
short
multiplexer
::
active_mask_of
(
const
socket_manager
*
mgr
)
const
noexcept
{
/// @copydoc write_to_pipe
template
<
class
Enum
,
class
T
>
std
::
enable_if_t
<
std
::
is_enum_v
<
Enum
>>
write_to_pipe
(
Enum
opcode
,
T
*
ptr
)
{
write_to_pipe
(
static_cast
<
uint8_t
>
(
opcode
),
ptr
);
}
/// Queries the currently active event bitmask for `mgr`.
short
active_mask_of
(
const
socket_manager
*
mgr
)
const
noexcept
{
auto
fd
=
mgr
->
handle
();
if
(
auto
i
=
updates_
.
find
(
fd
);
i
!=
updates_
.
end
())
{
return
i
->
second
.
events
;
...
...
@@ -430,34 +528,133 @@ short multiplexer::active_mask_of(const socket_manager* mgr) const noexcept {
}
else
{
return
0
;
}
}
}
// -- internal callbacks the pollset updater -----------------------------------
/// Pending actions via `schedule`.
std
::
deque
<
action
>
pending_actions
;
void
multiplexer
::
do_shutdown
()
{
// Note: calling apply_updates here is only safe because we know that the
// pollset updater runs outside of the for-loop in run_once.
CAF_LOG_DEBUG
(
"initiate shutdown"
);
shutting_down_
=
true
;
apply_updates
();
// Skip the first manager (the pollset updater).
for
(
size_t
i
=
1
;
i
<
managers_
.
size
();
++
i
)
managers_
[
i
]
->
dispose
();
apply_updates
();
private:
// -- member variables -------------------------------------------------------
/// Bookkeeping data for managed sockets.
pollfd_list
pollset_
;
/// Maps sockets to their owning managers by storing the managers in the same
/// order as their sockets appear in `pollset_`.
manager_list
managers_
;
/// Caches changes to the events mask of managed sockets until they can safely
/// take place.
poll_update_map
updates_
;
/// Stores the ID of the thread this multiplexer is running in. Set when
/// calling `init()`.
std
::
thread
::
id
tid_
;
/// Guards `write_handle_`.
std
::
mutex
write_lock_
;
/// Used for pushing updates to the multiplexer's thread.
pipe_socket
write_handle_
;
/// Points to the owning middleman.
middleman
*
owner_
;
/// Signals whether shutdown has been requested.
bool
shutting_down_
=
false
;
/// Keeps track of watched disposables.
std
::
vector
<
disposable
>
watched_
;
};
error
pollset_updater
::
start
(
socket_manager
*
owner
)
{
CAF_LOG_TRACE
(
""
);
owner_
=
owner
;
mpx_
=
static_cast
<
default_multiplexer
*>
(
owner
->
mpx_ptr
());
return
nonblocking
(
fd_
,
true
);
}
void
multiplexer
::
do_start
(
const
socket_manager_ptr
&
mgr
)
{
CAF_LOG_TRACE
(
CAF_ARG2
(
"socket"
,
mgr
->
handle
().
id
));
if
(
!
shutting_down_
)
{
error
err
;
err
=
mgr
->
start
();
if
(
err
)
{
CAF_LOG_DEBUG
(
"mgr->init failed: "
<<
err
);
// The socket manager should not register itself for any events if
// initialization fails. Purge any state just in case.
update_for
(
mgr
.
get
()).
events
=
0
;
void
pollset_updater
::
handle_read_event
()
{
CAF_LOG_TRACE
(
""
);
auto
as_mgr
=
[](
intptr_t
ptr
)
{
return
intrusive_ptr
{
reinterpret_cast
<
socket_manager
*>
(
ptr
),
false
};
};
auto
add_action
=
[
this
](
intptr_t
ptr
)
{
auto
f
=
action
{
intrusive_ptr
{
reinterpret_cast
<
action
::
impl
*>
(
ptr
),
false
}};
mpx_
->
pending_actions
.
push_back
(
std
::
move
(
f
));
};
for
(;;)
{
CAF_ASSERT
((
buf_
.
size
()
-
buf_size_
)
>
0
);
auto
num_bytes
=
read
(
fd_
,
make_span
(
buf_
.
data
()
+
buf_size_
,
buf_
.
size
()
-
buf_size_
));
if
(
num_bytes
>
0
)
{
buf_size_
+=
static_cast
<
size_t
>
(
num_bytes
);
if
(
buf_
.
size
()
==
buf_size_
)
{
buf_size_
=
0
;
auto
opcode
=
static_cast
<
uint8_t
>
(
buf_
[
0
]);
intptr_t
ptr
;
memcpy
(
&
ptr
,
buf_
.
data
()
+
1
,
sizeof
(
intptr_t
));
switch
(
static_cast
<
code
>
(
opcode
))
{
case
code
:
:
start_manager
:
mpx_
->
do_start
(
as_mgr
(
ptr
));
break
;
case
code
:
:
run_action
:
add_action
(
ptr
);
break
;
case
code
:
:
shutdown
:
CAF_ASSERT
(
ptr
==
0
);
mpx_
->
do_shutdown
();
break
;
default:
CAF_LOG_ERROR
(
"opcode not recognized: "
<<
CAF_ARG
(
opcode
));
break
;
}
}
}
else
if
(
num_bytes
==
0
)
{
CAF_LOG_DEBUG
(
"pipe closed, assume shutdown"
);
owner_
->
deregister
();
return
;
}
else
if
(
last_socket_error_is_temporary
())
{
return
;
}
else
{
CAF_LOG_ERROR
(
"pollset updater failed to read from the pipe"
);
owner_
->
deregister
();
return
;
}
}
}
}
// namespace
// -- multiplexer implementation -----------------------------------------------
// -- static utility functions -------------------------------------------------
void
multiplexer
::
block_sigpipe
()
{
#ifdef CAF_LINUX
sigset_t
sigpipe_mask
;
sigemptyset
(
&
sigpipe_mask
);
sigaddset
(
&
sigpipe_mask
,
SIGPIPE
);
sigset_t
saved_mask
;
if
(
pthread_sigmask
(
SIG_BLOCK
,
&
sigpipe_mask
,
&
saved_mask
)
==
-
1
)
{
perror
(
"pthread_sigmask"
);
exit
(
1
);
}
#endif
}
multiplexer_ptr
multiplexer
::
make
(
middleman
*
parent
)
{
return
make_counted
<
default_multiplexer
>
(
parent
);
}
multiplexer
*
multiplexer
::
from
(
actor_system
&
sys
)
{
return
sys
.
network_manager
().
mpx_ptr
();
}
// -- constructors, destructors, and assignment operators ----------------------
multiplexer
::~
multiplexer
()
{
// nop
}
}
// namespace caf::net
libcaf_net/caf/net/multiplexer.hpp
View file @
a19cb8e6
...
...
@@ -5,54 +5,25 @@
#pragma once
#include "caf/net/fwd.hpp"
#include "caf/net/pipe_socket.hpp"
#include "caf/net/socket.hpp"
#include "caf/action.hpp"
#include "caf/async/execution_context.hpp"
#include "caf/detail/atomic_ref_counted.hpp"
#include "caf/detail/net_export.hpp"
#include "caf/ref_counted.hpp"
#include "caf/unordered_flat_map.hpp"
#include <deque>
#include <memory>
#include <mutex>
#include <thread>
extern
"C"
{
struct
pollfd
;
}
// extern "C"
namespace
caf
::
net
{
/// Multiplexes any number of ::socket_manager objects with a ::socket.
class
CAF_NET_EXPORT
multiplexer
:
public
detail
::
atomic_ref_counted
,
public
async
::
execution_context
{
class
CAF_NET_EXPORT
multiplexer
:
public
async
::
execution_context
{
public:
// -- member types -----------------------------------------------------------
struct
poll_update
{
short
events
=
0
;
socket_manager_ptr
mgr
;
};
using
poll_update_map
=
unordered_flat_map
<
socket
,
poll_update
>
;
using
pollfd_list
=
std
::
vector
<
pollfd
>
;
using
manager_list
=
std
::
vector
<
socket_manager_ptr
>
;
// -- friends ----------------------------------------------------------------
friend
class
detail
::
pollset_updater
;
// Needs access to the `do_*` functions.
// -- static utility functions -----------------------------------------------
/// Blocks the PIPE signal on the current thread when running on
a POSIX
///
windows. Has no effect when running on Windows
.
/// Blocks the PIPE signal on the current thread when running on
Linux. Has no
///
effect otherwise
.
static
void
block_sigpipe
();
/// Returns a pointer to the multiplexer from the actor system.
...
...
@@ -60,179 +31,79 @@ public:
// -- constructors, destructors, and assignment operators --------------------
~
multiplexer
();
~
multiplexer
()
override
;
// -- factories --------------------------------------------------------------
/// Creates a new multiplexer instance with the default implementation.
/// @param parent Points to the owning middleman instance. May be `nullptr`
/// only for the purpose of unit testing if no @ref
/// socket_manager requires access to the @ref middleman or the
/// @ref actor_system.
static
multiplexer_ptr
make
(
middleman
*
parent
)
{
auto
ptr
=
new
multiplexer
(
parent
);
return
multiplexer_ptr
{
ptr
,
false
};
}
static
multiplexer_ptr
make
(
middleman
*
parent
);
// -- initialization ---------------------------------------------------------
error
init
()
;
virtual
error
init
()
=
0
;
// -- properties -------------------------------------------------------------
/// Returns the number of currently active socket managers.
size_t
num_socket_managers
()
const
noexcept
;
/// Returns the index of `mgr` in the pollset or `-1`.
ptrdiff_t
index_of
(
const
socket_manager_ptr
&
mgr
)
const
noexcept
;
/// Returns the index of `fd` in the pollset or `-1`.
ptrdiff_t
index_of
(
socket
fd
)
const
noexcept
;
virtual
size_t
num_socket_managers
()
const
noexcept
=
0
;
/// Returns the owning @ref middleman instance.
middleman
&
owner
()
;
virtual
middleman
&
owner
()
=
0
;
/// Returns the enclosing @ref actor_system.
actor_system
&
system
();
// -- implementation of execution_context ------------------------------------
void
ref_execution_context
()
const
noexcept
override
;
void
deref_execution_context
()
const
noexcept
override
;
void
schedule
(
action
what
)
override
;
void
watch
(
disposable
what
)
override
;
virtual
actor_system
&
system
()
=
0
;
// -- thread-safe signaling --------------------------------------------------
/// Registers `mgr` for initialization in the multiplexer's thread.
/// @thread-safe
v
oid
start
(
socket_manager_ptr
mgr
)
;
v
irtual
void
start
(
socket_manager_ptr
mgr
)
=
0
;
/// Signals the multiplexer to initiate shutdown.
/// @thread-safe
v
oid
shutdown
()
;
v
irtual
void
shutdown
()
=
0
;
// -- callbacks for socket managers ------------------------------------------
/// Registers `mgr` for read events.
v
oid
register_reading
(
socket_manager
*
mgr
)
;
v
irtual
void
register_reading
(
socket_manager
*
mgr
)
=
0
;
/// Registers `mgr` for write events.
v
oid
register_writing
(
socket_manager
*
mgr
)
;
v
irtual
void
register_writing
(
socket_manager
*
mgr
)
=
0
;
/// Deregisters `mgr` from read events.
v
oid
deregister_reading
(
socket_manager
*
mgr
)
;
v
irtual
void
deregister_reading
(
socket_manager
*
mgr
)
=
0
;
/// Deregisters `mgr` from write events.
v
oid
deregister_writing
(
socket_manager
*
mgr
)
;
v
irtual
void
deregister_writing
(
socket_manager
*
mgr
)
=
0
;
/// Deregisters @p mgr from read and write events.
v
oid
deregister
(
socket_manager
*
mgr
)
;
v
irtual
void
deregister
(
socket_manager
*
mgr
)
=
0
;
/// Queries whether `mgr` is currently registered for reading.
bool
is_reading
(
const
socket_manager
*
mgr
)
const
noexcept
;
virtual
bool
is_reading
(
const
socket_manager
*
mgr
)
const
noexcept
=
0
;
/// Queries whether `mgr` is currently registered for writing.
bool
is_writing
(
const
socket_manager
*
mgr
)
const
noexcept
;
virtual
bool
is_writing
(
const
socket_manager
*
mgr
)
const
noexcept
=
0
;
// -- control flow -----------------------------------------------------------
/// Polls I/O activity once and runs all socket event handlers that become
/// ready as a result.
bool
poll_once
(
bool
blocking
);
/// Runs `poll_once(false)` until it returns `true`.`
void
poll
();
virtual
bool
poll_once
(
bool
blocking
)
=
0
;
/// Applies all pending updates.
void
apply_updates
();
/// Runs all pending actions.
void
run_actions
();
virtual
void
apply_updates
()
=
0
;
/// Sets the thread ID to `std::this_thread::id()`.
v
oid
set_thread_id
()
;
v
irtual
void
set_thread_id
()
=
0
;
/// Runs the multiplexer until no socket event handler remains active.
void
run
();
protected:
// -- utility functions ------------------------------------------------------
/// Handles an I/O event on given manager.
void
handle
(
const
socket_manager_ptr
&
mgr
,
short
events
,
short
revents
);
/// Returns a change entry for the socket at given index. Lazily creates a new
/// entry before returning if necessary.
poll_update
&
update_for
(
ptrdiff_t
index
);
/// Returns a change entry for the socket of the manager.
poll_update
&
update_for
(
socket_manager
*
mgr
);
/// Writes `opcode` and pointer to `mgr` the the pipe for handling an event
/// later via the pollset updater.
/// @warning assumes ownership of @p ptr.
template
<
class
T
>
void
write_to_pipe
(
uint8_t
opcode
,
T
*
ptr
);
/// @copydoc write_to_pipe
template
<
class
Enum
,
class
T
>
std
::
enable_if_t
<
std
::
is_enum_v
<
Enum
>>
write_to_pipe
(
Enum
opcode
,
T
*
ptr
)
{
write_to_pipe
(
static_cast
<
uint8_t
>
(
opcode
),
ptr
);
}
/// Queries the currently active event bitmask for `mgr`.
short
active_mask_of
(
const
socket_manager
*
mgr
)
const
noexcept
;
// -- member variables -------------------------------------------------------
/// Bookkeeping data for managed sockets.
pollfd_list
pollset_
;
/// Maps sockets to their owning managers by storing the managers in the same
/// order as their sockets appear in `pollset_`.
manager_list
managers_
;
/// Caches changes to the events mask of managed sockets until they can safely
/// take place.
poll_update_map
updates_
;
/// Stores the ID of the thread this multiplexer is running in. Set when
/// calling `init()`.
std
::
thread
::
id
tid_
;
/// Guards `write_handle_`.
std
::
mutex
write_lock_
;
/// Used for pushing updates to the multiplexer's thread.
pipe_socket
write_handle_
;
/// Points to the owning middleman.
middleman
*
owner_
;
/// Signals whether shutdown has been requested.
bool
shutting_down_
=
false
;
/// Pending actions via `schedule`.
std
::
deque
<
action
>
pending_actions_
;
/// Keeps track of watched disposables.
std
::
vector
<
disposable
>
watched_
;
private:
// -- constructors, destructors, and assignment operators --------------------
explicit
multiplexer
(
middleman
*
parent
);
// -- internal callbacks the pollset updater ---------------------------------
void
do_shutdown
();
void
do_register_reading
(
const
socket_manager_ptr
&
mgr
);
void
do_start
(
const
socket_manager_ptr
&
mgr
);
virtual
void
run
()
=
0
;
};
}
// namespace caf::net
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