2020-09-11 16:09:46 +02:00
|
|
|
/*
|
|
|
|
|
* Copyright 2020 The WebRTC Project Authors. All rights reserved.
|
|
|
|
|
*
|
|
|
|
|
* Use of this source code is governed by a BSD-style license
|
|
|
|
|
* that can be found in the LICENSE file in the root of the source
|
|
|
|
|
* tree. An additional intellectual property rights grant can be found
|
|
|
|
|
* in the file PATENTS. All contributing project authors may
|
|
|
|
|
* be found in the AUTHORS file in the root of the source tree.
|
|
|
|
|
*/
|
|
|
|
|
|
2020-10-23 12:04:40 +02:00
|
|
|
#include "rtc_base/callback_list.h"
|
2020-09-11 16:09:46 +02:00
|
|
|
|
2020-11-11 11:48:04 +01:00
|
|
|
#include "rtc_base/checks.h"
|
|
|
|
|
|
2020-09-11 16:09:46 +02:00
|
|
|
namespace webrtc {
|
2020-10-23 12:04:40 +02:00
|
|
|
namespace callback_list_impl {
|
2020-09-11 16:09:46 +02:00
|
|
|
|
2020-10-23 12:04:40 +02:00
|
|
|
CallbackListReceivers::CallbackListReceivers() = default;
|
2020-11-11 11:48:04 +01:00
|
|
|
|
|
|
|
|
CallbackListReceivers::~CallbackListReceivers() {
|
|
|
|
|
RTC_CHECK(!send_in_progress_);
|
|
|
|
|
}
|
2020-09-11 16:09:46 +02:00
|
|
|
|
2020-11-25 21:26:17 +01:00
|
|
|
void CallbackListReceivers::RemoveReceivers(const void* removal_tag) {
|
2022-04-09 17:49:00 +02:00
|
|
|
RTC_DCHECK(removal_tag);
|
2020-11-25 21:26:17 +01:00
|
|
|
|
|
|
|
|
// We divide the receivers_ vector into three regions: from right to left, the
|
|
|
|
|
// "keep" region, the "todo" region, and the "remove" region. The "todo"
|
|
|
|
|
// region initially covers the whole vector.
|
|
|
|
|
size_t first_todo = 0; // First element of the "todo"
|
|
|
|
|
// region.
|
|
|
|
|
size_t first_remove = receivers_.size(); // First element of the "remove"
|
|
|
|
|
// region.
|
|
|
|
|
|
|
|
|
|
// Loop until the "todo" region is empty.
|
|
|
|
|
while (first_todo != first_remove) {
|
|
|
|
|
if (receivers_[first_todo].removal_tag != removal_tag) {
|
|
|
|
|
// The first element of the "todo" region should be kept. Move the
|
|
|
|
|
// "keep"/"todo" boundary.
|
|
|
|
|
++first_todo;
|
|
|
|
|
} else if (receivers_[first_remove - 1].removal_tag == removal_tag) {
|
|
|
|
|
// The last element of the "todo" region should be removed. Move the
|
|
|
|
|
// "todo"/"remove" boundary.
|
2022-04-09 17:49:00 +02:00
|
|
|
if (send_in_progress_) {
|
|
|
|
|
// Tag this receiver for removal, which will be done when `ForEach`
|
|
|
|
|
// has completed.
|
|
|
|
|
receivers_[first_remove - 1].removal_tag = pending_removal_tag();
|
|
|
|
|
}
|
2020-11-25 21:26:17 +01:00
|
|
|
--first_remove;
|
2022-04-09 17:49:00 +02:00
|
|
|
} else if (!send_in_progress_) {
|
2020-11-25 21:26:17 +01:00
|
|
|
// The first element of the "todo" region should be removed, and the last
|
|
|
|
|
// element of the "todo" region should be kept. Swap them, and then shrink
|
|
|
|
|
// the "todo" region from both ends.
|
|
|
|
|
RTC_DCHECK_NE(first_todo, first_remove - 1);
|
|
|
|
|
using std::swap;
|
|
|
|
|
swap(receivers_[first_todo], receivers_[first_remove - 1]);
|
|
|
|
|
RTC_DCHECK_NE(receivers_[first_todo].removal_tag, removal_tag);
|
|
|
|
|
++first_todo;
|
|
|
|
|
RTC_DCHECK_EQ(receivers_[first_remove - 1].removal_tag, removal_tag);
|
|
|
|
|
--first_remove;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-09 17:49:00 +02:00
|
|
|
if (!send_in_progress_) {
|
|
|
|
|
// Discard the remove region.
|
|
|
|
|
receivers_.resize(first_remove);
|
|
|
|
|
}
|
2020-11-25 21:26:17 +01:00
|
|
|
}
|
|
|
|
|
|
2020-10-23 12:04:40 +02:00
|
|
|
void CallbackListReceivers::Foreach(
|
2020-09-11 16:09:46 +02:00
|
|
|
rtc::FunctionView<void(UntypedFunction&)> fv) {
|
2020-11-11 11:48:04 +01:00
|
|
|
RTC_CHECK(!send_in_progress_);
|
2022-04-09 17:49:00 +02:00
|
|
|
bool removals_detected = false;
|
2020-11-11 11:48:04 +01:00
|
|
|
send_in_progress_ = true;
|
2020-09-11 16:09:46 +02:00
|
|
|
for (auto& r : receivers_) {
|
2022-04-09 17:49:00 +02:00
|
|
|
RTC_DCHECK_NE(r.removal_tag, pending_removal_tag());
|
2020-11-25 21:26:17 +01:00
|
|
|
fv(r.function);
|
2022-04-09 17:49:00 +02:00
|
|
|
if (r.removal_tag == pending_removal_tag()) {
|
|
|
|
|
removals_detected = true;
|
|
|
|
|
}
|
2020-09-11 16:09:46 +02:00
|
|
|
}
|
2020-11-11 11:48:04 +01:00
|
|
|
send_in_progress_ = false;
|
2022-04-09 17:49:00 +02:00
|
|
|
if (removals_detected) {
|
|
|
|
|
RemoveReceivers(pending_removal_tag());
|
|
|
|
|
}
|
2020-09-11 16:09:46 +02:00
|
|
|
}
|
|
|
|
|
|
2020-11-25 21:26:17 +01:00
|
|
|
template void CallbackListReceivers::AddReceiver(
|
|
|
|
|
const void*,
|
|
|
|
|
UntypedFunction::TrivialUntypedFunctionArgs<1>);
|
|
|
|
|
template void CallbackListReceivers::AddReceiver(
|
|
|
|
|
const void*,
|
|
|
|
|
UntypedFunction::TrivialUntypedFunctionArgs<2>);
|
|
|
|
|
template void CallbackListReceivers::AddReceiver(
|
|
|
|
|
const void*,
|
|
|
|
|
UntypedFunction::TrivialUntypedFunctionArgs<3>);
|
|
|
|
|
template void CallbackListReceivers::AddReceiver(
|
|
|
|
|
const void*,
|
|
|
|
|
UntypedFunction::TrivialUntypedFunctionArgs<4>);
|
|
|
|
|
template void CallbackListReceivers::AddReceiver(
|
|
|
|
|
const void*,
|
|
|
|
|
UntypedFunction::NontrivialUntypedFunctionArgs);
|
|
|
|
|
template void CallbackListReceivers::AddReceiver(
|
|
|
|
|
const void*,
|
|
|
|
|
UntypedFunction::FunctionPointerUntypedFunctionArgs);
|
|
|
|
|
|
2020-10-23 12:04:40 +02:00
|
|
|
template void CallbackListReceivers::AddReceiver(
|
Optimize RoboCaller::AddReceiver() for code size
Essentially, instead of having the inlined UntypedFunction::Create(f)
return an UntypedFunction which is then passed as an argument to
non-inlined RoboCallerReceivers::AddReceiverImpl(), we let
UntypedFunction::PrepareArgs(f) return a few different kinds of
trivial structs (depending on what sort of type f has) which are
passed as arguments to non-inlined RoboCallerReceivers::AddReceiver()
(which then converts them to UntypedFunction by calling
UntypedFunction::Create()). These structs are smaller than
UntypedFunction and optimized for argument passing, so many fewer
instructions are needed.
Example code:
struct Foo {
void Receive(int, float, int, float);
void TestAddLambdaReceiver();
webrtc::RoboCaller<int, float, int, float> rc;
};
void Foo::TestAddLambdaReceiver() {
rc.AddReceiver([this](int a, float b, int c, float d){
Receive(a, b, c, d);});
}
On arm32, we get before this CL:
Foo::TestAddLambdaReceiver():
push {r11, lr}
mov r11, sp
sub sp, sp, #24
ldr r1, .LCPI0_0
mov r2, #0
stm sp, {r0, r2}
add r1, pc, r1
str r2, [sp, #20]
str r1, [sp, #16]
mov r1, sp
bl RoboCallerReceivers::AddReceiverImpl
mov sp, r11
pop {r11, pc}
.LCPI0_0:
.long CallInlineStorage<Foo::TestAddLambdaReceiver()::$_0>
CallInlineStorage<Foo::TestAddLambdaReceiver()::$_0>:
ldr r0, [r0]
b Foo::Receive(int, float, int, float)
After this CL:
Foo::TestAddLambdaReceiver():
ldr r3, .LCPI0_0
mov r2, r0
add r3, pc, r3
b RoboCallerReceivers::AddReceiver<1u>
.LCPI0_0:
.long CallInlineStorage<Foo::TestAddLambdaReceiver()::$_0>
CallInlineStorage<Foo::TestAddLambdaReceiver()::$_0>:
ldr r0, [r0]
b Foo::Receive(int, float, int, float)
(Symbol names abbreviated so that they'll fit on one line.)
So a reduction from 64 to 28 bytes. The improvements on arm64 and
x86_64 are similar.
Bug: webrtc:11943
Change-Id: I93fbba083be0235051c3279d3e3f6852a4a9fdad
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/185960
Commit-Queue: Karl Wiberg <kwiberg@webrtc.org>
Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#32244}
2020-09-29 13:55:13 +02:00
|
|
|
UntypedFunction::TrivialUntypedFunctionArgs<1>);
|
2020-10-23 12:04:40 +02:00
|
|
|
template void CallbackListReceivers::AddReceiver(
|
Optimize RoboCaller::AddReceiver() for code size
Essentially, instead of having the inlined UntypedFunction::Create(f)
return an UntypedFunction which is then passed as an argument to
non-inlined RoboCallerReceivers::AddReceiverImpl(), we let
UntypedFunction::PrepareArgs(f) return a few different kinds of
trivial structs (depending on what sort of type f has) which are
passed as arguments to non-inlined RoboCallerReceivers::AddReceiver()
(which then converts them to UntypedFunction by calling
UntypedFunction::Create()). These structs are smaller than
UntypedFunction and optimized for argument passing, so many fewer
instructions are needed.
Example code:
struct Foo {
void Receive(int, float, int, float);
void TestAddLambdaReceiver();
webrtc::RoboCaller<int, float, int, float> rc;
};
void Foo::TestAddLambdaReceiver() {
rc.AddReceiver([this](int a, float b, int c, float d){
Receive(a, b, c, d);});
}
On arm32, we get before this CL:
Foo::TestAddLambdaReceiver():
push {r11, lr}
mov r11, sp
sub sp, sp, #24
ldr r1, .LCPI0_0
mov r2, #0
stm sp, {r0, r2}
add r1, pc, r1
str r2, [sp, #20]
str r1, [sp, #16]
mov r1, sp
bl RoboCallerReceivers::AddReceiverImpl
mov sp, r11
pop {r11, pc}
.LCPI0_0:
.long CallInlineStorage<Foo::TestAddLambdaReceiver()::$_0>
CallInlineStorage<Foo::TestAddLambdaReceiver()::$_0>:
ldr r0, [r0]
b Foo::Receive(int, float, int, float)
After this CL:
Foo::TestAddLambdaReceiver():
ldr r3, .LCPI0_0
mov r2, r0
add r3, pc, r3
b RoboCallerReceivers::AddReceiver<1u>
.LCPI0_0:
.long CallInlineStorage<Foo::TestAddLambdaReceiver()::$_0>
CallInlineStorage<Foo::TestAddLambdaReceiver()::$_0>:
ldr r0, [r0]
b Foo::Receive(int, float, int, float)
(Symbol names abbreviated so that they'll fit on one line.)
So a reduction from 64 to 28 bytes. The improvements on arm64 and
x86_64 are similar.
Bug: webrtc:11943
Change-Id: I93fbba083be0235051c3279d3e3f6852a4a9fdad
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/185960
Commit-Queue: Karl Wiberg <kwiberg@webrtc.org>
Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#32244}
2020-09-29 13:55:13 +02:00
|
|
|
UntypedFunction::TrivialUntypedFunctionArgs<2>);
|
2020-10-23 12:04:40 +02:00
|
|
|
template void CallbackListReceivers::AddReceiver(
|
Optimize RoboCaller::AddReceiver() for code size
Essentially, instead of having the inlined UntypedFunction::Create(f)
return an UntypedFunction which is then passed as an argument to
non-inlined RoboCallerReceivers::AddReceiverImpl(), we let
UntypedFunction::PrepareArgs(f) return a few different kinds of
trivial structs (depending on what sort of type f has) which are
passed as arguments to non-inlined RoboCallerReceivers::AddReceiver()
(which then converts them to UntypedFunction by calling
UntypedFunction::Create()). These structs are smaller than
UntypedFunction and optimized for argument passing, so many fewer
instructions are needed.
Example code:
struct Foo {
void Receive(int, float, int, float);
void TestAddLambdaReceiver();
webrtc::RoboCaller<int, float, int, float> rc;
};
void Foo::TestAddLambdaReceiver() {
rc.AddReceiver([this](int a, float b, int c, float d){
Receive(a, b, c, d);});
}
On arm32, we get before this CL:
Foo::TestAddLambdaReceiver():
push {r11, lr}
mov r11, sp
sub sp, sp, #24
ldr r1, .LCPI0_0
mov r2, #0
stm sp, {r0, r2}
add r1, pc, r1
str r2, [sp, #20]
str r1, [sp, #16]
mov r1, sp
bl RoboCallerReceivers::AddReceiverImpl
mov sp, r11
pop {r11, pc}
.LCPI0_0:
.long CallInlineStorage<Foo::TestAddLambdaReceiver()::$_0>
CallInlineStorage<Foo::TestAddLambdaReceiver()::$_0>:
ldr r0, [r0]
b Foo::Receive(int, float, int, float)
After this CL:
Foo::TestAddLambdaReceiver():
ldr r3, .LCPI0_0
mov r2, r0
add r3, pc, r3
b RoboCallerReceivers::AddReceiver<1u>
.LCPI0_0:
.long CallInlineStorage<Foo::TestAddLambdaReceiver()::$_0>
CallInlineStorage<Foo::TestAddLambdaReceiver()::$_0>:
ldr r0, [r0]
b Foo::Receive(int, float, int, float)
(Symbol names abbreviated so that they'll fit on one line.)
So a reduction from 64 to 28 bytes. The improvements on arm64 and
x86_64 are similar.
Bug: webrtc:11943
Change-Id: I93fbba083be0235051c3279d3e3f6852a4a9fdad
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/185960
Commit-Queue: Karl Wiberg <kwiberg@webrtc.org>
Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#32244}
2020-09-29 13:55:13 +02:00
|
|
|
UntypedFunction::TrivialUntypedFunctionArgs<3>);
|
2020-10-23 12:04:40 +02:00
|
|
|
template void CallbackListReceivers::AddReceiver(
|
Optimize RoboCaller::AddReceiver() for code size
Essentially, instead of having the inlined UntypedFunction::Create(f)
return an UntypedFunction which is then passed as an argument to
non-inlined RoboCallerReceivers::AddReceiverImpl(), we let
UntypedFunction::PrepareArgs(f) return a few different kinds of
trivial structs (depending on what sort of type f has) which are
passed as arguments to non-inlined RoboCallerReceivers::AddReceiver()
(which then converts them to UntypedFunction by calling
UntypedFunction::Create()). These structs are smaller than
UntypedFunction and optimized for argument passing, so many fewer
instructions are needed.
Example code:
struct Foo {
void Receive(int, float, int, float);
void TestAddLambdaReceiver();
webrtc::RoboCaller<int, float, int, float> rc;
};
void Foo::TestAddLambdaReceiver() {
rc.AddReceiver([this](int a, float b, int c, float d){
Receive(a, b, c, d);});
}
On arm32, we get before this CL:
Foo::TestAddLambdaReceiver():
push {r11, lr}
mov r11, sp
sub sp, sp, #24
ldr r1, .LCPI0_0
mov r2, #0
stm sp, {r0, r2}
add r1, pc, r1
str r2, [sp, #20]
str r1, [sp, #16]
mov r1, sp
bl RoboCallerReceivers::AddReceiverImpl
mov sp, r11
pop {r11, pc}
.LCPI0_0:
.long CallInlineStorage<Foo::TestAddLambdaReceiver()::$_0>
CallInlineStorage<Foo::TestAddLambdaReceiver()::$_0>:
ldr r0, [r0]
b Foo::Receive(int, float, int, float)
After this CL:
Foo::TestAddLambdaReceiver():
ldr r3, .LCPI0_0
mov r2, r0
add r3, pc, r3
b RoboCallerReceivers::AddReceiver<1u>
.LCPI0_0:
.long CallInlineStorage<Foo::TestAddLambdaReceiver()::$_0>
CallInlineStorage<Foo::TestAddLambdaReceiver()::$_0>:
ldr r0, [r0]
b Foo::Receive(int, float, int, float)
(Symbol names abbreviated so that they'll fit on one line.)
So a reduction from 64 to 28 bytes. The improvements on arm64 and
x86_64 are similar.
Bug: webrtc:11943
Change-Id: I93fbba083be0235051c3279d3e3f6852a4a9fdad
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/185960
Commit-Queue: Karl Wiberg <kwiberg@webrtc.org>
Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#32244}
2020-09-29 13:55:13 +02:00
|
|
|
UntypedFunction::TrivialUntypedFunctionArgs<4>);
|
2020-10-23 12:04:40 +02:00
|
|
|
template void CallbackListReceivers::AddReceiver(
|
Optimize RoboCaller::AddReceiver() for code size
Essentially, instead of having the inlined UntypedFunction::Create(f)
return an UntypedFunction which is then passed as an argument to
non-inlined RoboCallerReceivers::AddReceiverImpl(), we let
UntypedFunction::PrepareArgs(f) return a few different kinds of
trivial structs (depending on what sort of type f has) which are
passed as arguments to non-inlined RoboCallerReceivers::AddReceiver()
(which then converts them to UntypedFunction by calling
UntypedFunction::Create()). These structs are smaller than
UntypedFunction and optimized for argument passing, so many fewer
instructions are needed.
Example code:
struct Foo {
void Receive(int, float, int, float);
void TestAddLambdaReceiver();
webrtc::RoboCaller<int, float, int, float> rc;
};
void Foo::TestAddLambdaReceiver() {
rc.AddReceiver([this](int a, float b, int c, float d){
Receive(a, b, c, d);});
}
On arm32, we get before this CL:
Foo::TestAddLambdaReceiver():
push {r11, lr}
mov r11, sp
sub sp, sp, #24
ldr r1, .LCPI0_0
mov r2, #0
stm sp, {r0, r2}
add r1, pc, r1
str r2, [sp, #20]
str r1, [sp, #16]
mov r1, sp
bl RoboCallerReceivers::AddReceiverImpl
mov sp, r11
pop {r11, pc}
.LCPI0_0:
.long CallInlineStorage<Foo::TestAddLambdaReceiver()::$_0>
CallInlineStorage<Foo::TestAddLambdaReceiver()::$_0>:
ldr r0, [r0]
b Foo::Receive(int, float, int, float)
After this CL:
Foo::TestAddLambdaReceiver():
ldr r3, .LCPI0_0
mov r2, r0
add r3, pc, r3
b RoboCallerReceivers::AddReceiver<1u>
.LCPI0_0:
.long CallInlineStorage<Foo::TestAddLambdaReceiver()::$_0>
CallInlineStorage<Foo::TestAddLambdaReceiver()::$_0>:
ldr r0, [r0]
b Foo::Receive(int, float, int, float)
(Symbol names abbreviated so that they'll fit on one line.)
So a reduction from 64 to 28 bytes. The improvements on arm64 and
x86_64 are similar.
Bug: webrtc:11943
Change-Id: I93fbba083be0235051c3279d3e3f6852a4a9fdad
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/185960
Commit-Queue: Karl Wiberg <kwiberg@webrtc.org>
Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#32244}
2020-09-29 13:55:13 +02:00
|
|
|
UntypedFunction::NontrivialUntypedFunctionArgs);
|
2020-10-23 12:04:40 +02:00
|
|
|
template void CallbackListReceivers::AddReceiver(
|
Optimize RoboCaller::AddReceiver() for code size
Essentially, instead of having the inlined UntypedFunction::Create(f)
return an UntypedFunction which is then passed as an argument to
non-inlined RoboCallerReceivers::AddReceiverImpl(), we let
UntypedFunction::PrepareArgs(f) return a few different kinds of
trivial structs (depending on what sort of type f has) which are
passed as arguments to non-inlined RoboCallerReceivers::AddReceiver()
(which then converts them to UntypedFunction by calling
UntypedFunction::Create()). These structs are smaller than
UntypedFunction and optimized for argument passing, so many fewer
instructions are needed.
Example code:
struct Foo {
void Receive(int, float, int, float);
void TestAddLambdaReceiver();
webrtc::RoboCaller<int, float, int, float> rc;
};
void Foo::TestAddLambdaReceiver() {
rc.AddReceiver([this](int a, float b, int c, float d){
Receive(a, b, c, d);});
}
On arm32, we get before this CL:
Foo::TestAddLambdaReceiver():
push {r11, lr}
mov r11, sp
sub sp, sp, #24
ldr r1, .LCPI0_0
mov r2, #0
stm sp, {r0, r2}
add r1, pc, r1
str r2, [sp, #20]
str r1, [sp, #16]
mov r1, sp
bl RoboCallerReceivers::AddReceiverImpl
mov sp, r11
pop {r11, pc}
.LCPI0_0:
.long CallInlineStorage<Foo::TestAddLambdaReceiver()::$_0>
CallInlineStorage<Foo::TestAddLambdaReceiver()::$_0>:
ldr r0, [r0]
b Foo::Receive(int, float, int, float)
After this CL:
Foo::TestAddLambdaReceiver():
ldr r3, .LCPI0_0
mov r2, r0
add r3, pc, r3
b RoboCallerReceivers::AddReceiver<1u>
.LCPI0_0:
.long CallInlineStorage<Foo::TestAddLambdaReceiver()::$_0>
CallInlineStorage<Foo::TestAddLambdaReceiver()::$_0>:
ldr r0, [r0]
b Foo::Receive(int, float, int, float)
(Symbol names abbreviated so that they'll fit on one line.)
So a reduction from 64 to 28 bytes. The improvements on arm64 and
x86_64 are similar.
Bug: webrtc:11943
Change-Id: I93fbba083be0235051c3279d3e3f6852a4a9fdad
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/185960
Commit-Queue: Karl Wiberg <kwiberg@webrtc.org>
Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#32244}
2020-09-29 13:55:13 +02:00
|
|
|
UntypedFunction::FunctionPointerUntypedFunctionArgs);
|
|
|
|
|
|
2020-10-23 12:04:40 +02:00
|
|
|
} // namespace callback_list_impl
|
2020-09-11 16:09:46 +02:00
|
|
|
} // namespace webrtc
|