Seastar
High performance C++ framework for concurrent servers
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Modules Pages
scheduling_specific.hh
1/*
2 * This file is open source software, licensed to you under the terms
3 * of the Apache License, Version 2.0 (the "License"). See the NOTICE file
4 * distributed with this work for additional information regarding copyright
5 * ownership. You may not use this file except in compliance with the License.
6 *
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing,
12 * software distributed under the License is distributed on an
13 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 * KIND, either express or implied. See the License for the
15 * specific language governing permissions and limitations
16 * under the License.
17 */
18/*
19 * Copyright (C) 2019 Scylla DB Ltd
20 */
21
22#ifndef SEASTAR_MODULE
24#include <seastar/core/map_reduce.hh>
25#include <seastar/util/assert.hh>
26#include <seastar/util/modules.hh>
27#include <array>
28#include <cstdlib>
29#include <map>
30#include <typeindex>
31#include <vector>
32#include <ranges>
33#endif
34
35#pragma once
36
37namespace seastar {
38
39namespace internal {
40
41struct scheduling_group_specific_thread_local_data {
42 using val_ptr = std::unique_ptr<void, void (*)(void*) noexcept>;
43 using cfg_ptr = lw_shared_ptr<scheduling_group_key_config>;
44
45 struct specific_val {
46 val_ptr valp;
47 cfg_ptr cfg;
48
49 static void free(void* ptr) noexcept {
50 std::free(ptr);
51 }
52
53 specific_val() : valp(nullptr, &free), cfg(nullptr) {}
54
55 specific_val(val_ptr&& valp_, const cfg_ptr& cfg_) : valp(std::move(valp_)), cfg(cfg_) {
56 if (valp && cfg->constructor) {
57 cfg->constructor(valp.get());
58 }
59 }
60
61 ~specific_val() {
62 if (valp && cfg->destructor) {
63 cfg->destructor(valp.get());
64 }
65 }
66
67 specific_val(const specific_val& other) = delete;
68 specific_val& operator=(const specific_val& other) = delete;
69
70 specific_val(specific_val&& other) : valp(std::move(other.valp)), cfg(std::move(other.cfg)) {}
71
72 specific_val& operator=(specific_val&& other) {
73 if (this != &other) {
74 valp = std::move(other.valp);
75 cfg = std::move(other.cfg);
76 }
77 return *this;
78 }
79
80 void* get() { return valp.get(); }
81
82 void rename() {
83 if (valp && cfg->rename) {
84 cfg->rename(valp.get());
85 }
86 }
87 };
88
89 struct per_scheduling_group {
90 bool queue_is_initialized = false;
96 std::vector<specific_val> specific_vals;
97
98 void rename() {
99 for (auto& v : specific_vals) {
100 v.rename();
101 }
102 }
103 };
104 std::array<per_scheduling_group, max_scheduling_groups()> per_scheduling_group_data;
105 std::map<unsigned long, cfg_ptr> scheduling_group_key_configs;
106};
107
108#ifdef SEASTAR_BUILD_SHARED_LIBS
109scheduling_group_specific_thread_local_data** get_scheduling_group_specific_thread_local_data_ptr() noexcept;
110#else
111inline
112scheduling_group_specific_thread_local_data** get_scheduling_group_specific_thread_local_data_ptr() noexcept {
113 static thread_local scheduling_group_specific_thread_local_data* data;
114 return &data;
115}
116#endif
117inline
118scheduling_group_specific_thread_local_data& get_scheduling_group_specific_thread_local_data() noexcept {
119 return **get_scheduling_group_specific_thread_local_data_ptr();
120}
121
122[[noreturn]] void no_such_scheduling_group(scheduling_group sg);
123
132template<typename T>
133T* scheduling_group_get_specific_ptr(scheduling_group sg, scheduling_group_key key) noexcept {
134 auto& data = internal::get_scheduling_group_specific_thread_local_data();
135#ifdef SEASTAR_DEBUG
136 SEASTAR_ASSERT(std::type_index(typeid(T)) == data.scheduling_group_key_configs[key.id()]->type_index);
137#endif
138 auto sg_id = internal::scheduling_group_index(sg);
139 if (__builtin_expect(sg_id < data.per_scheduling_group_data.size() &&
140 data.per_scheduling_group_data[sg_id].queue_is_initialized, true)) {
141 return reinterpret_cast<T*>(data.per_scheduling_group_data[sg_id].specific_vals[key.id()].get());
142 }
143 return nullptr;
144}
145
146}
147
148SEASTAR_MODULE_EXPORT_BEGIN
149
159template<typename T>
161 T* p = internal::scheduling_group_get_specific_ptr<T>(sg, std::move(key));
162 if (!p) {
163 internal::no_such_scheduling_group(sg);
164 }
165 return *p;
166}
167
175template<typename T>
177 // Unlike internal::scheduling_group_get_specific_ptr, this can
178 // return a reference to an element whose queue_is_initialized is
179 // false.
180 auto& data = internal::get_scheduling_group_specific_thread_local_data();
181 SEASTAR_ASSERT(std::type_index(typeid(T)) == data.scheduling_group_key_configs[key.id()]->type_index);
182 auto sg_id = internal::scheduling_group_index(current_scheduling_group());
183 return *reinterpret_cast<T*>(data.per_scheduling_group_data[sg_id].specific_vals[key.id()].get());
184}
185
201template<typename SpecificValType, typename Mapper, typename Reducer, typename Initial>
202requires requires(SpecificValType specific_val, Mapper mapper, Reducer reducer, Initial initial) {
203 {reducer(initial, mapper(specific_val))} -> std::convertible_to<Initial>;
204}
205future<typename function_traits<Reducer>::return_type>
206map_reduce_scheduling_group_specific(Mapper mapper, Reducer reducer,
207 Initial initial_val, scheduling_group_key key) {
208 using per_scheduling_group = internal::scheduling_group_specific_thread_local_data::per_scheduling_group;
209 auto& data = internal::get_scheduling_group_specific_thread_local_data();
210 auto wrapped_mapper = [key, mapper] (per_scheduling_group& psg) {
211 auto id = internal::scheduling_group_key_id(key);
212 return make_ready_future<typename function_traits<Mapper>::return_type>
213 (mapper(*reinterpret_cast<SpecificValType*>(psg.specific_vals[id].get())));
214 };
215
216 return map_reduce(
217 data.per_scheduling_group_data
218 | std::views::filter(std::mem_fn(&per_scheduling_group::queue_is_initialized)),
219 wrapped_mapper, std::move(initial_val), reducer);
220}
221
235template<typename SpecificValType, typename Reducer, typename Initial>
236requires requires(SpecificValType specific_val, Reducer reducer, Initial initial) {
237 {reducer(initial, specific_val)} -> std::convertible_to<Initial>;
238}
239future<typename function_traits<Reducer>::return_type>
240reduce_scheduling_group_specific(Reducer reducer, Initial initial_val, scheduling_group_key key) {
241 using per_scheduling_group = internal::scheduling_group_specific_thread_local_data::per_scheduling_group;
242 auto& data = internal::get_scheduling_group_specific_thread_local_data();
243
244 auto mapper = [key] (per_scheduling_group& psg) {
245 auto id = internal::scheduling_group_key_id(key);
246 return make_ready_future<SpecificValType>(*reinterpret_cast<SpecificValType*>(psg.specific_vals[id].get()));
247 };
248
249 return map_reduce(
250 data.per_scheduling_group_data
251 | std::views::filter(std::mem_fn(&per_scheduling_group::queue_is_initialized)),
252 mapper, std::move(initial_val), reducer);
253}
254
255SEASTAR_MODULE_EXPORT_END
256
257}
Definition: scheduling.hh:183
Identifies function calls that are accounted as a group.
Definition: scheduling.hh:293
auto map_reduce(Iterator begin, Iterator end, Mapper &&mapper, Reducer &&r) -> typename reducer_traits< Reducer >::future_type
Definition: map_reduce.hh:107
Seastar API namespace.
Definition: abort_on_ebadf.hh:26
future< typename function_traits< Reducer >::return_type > map_reduce_scheduling_group_specific(Mapper mapper, Reducer reducer, Initial initial_val, scheduling_group_key key)
Definition: scheduling_specific.hh:206
scheduling_group current_scheduling_group() noexcept
Returns the current scheduling group.
Definition: scheduling.hh:405
T & scheduling_group_get_specific(scheduling_group sg, scheduling_group_key key)
Definition: scheduling_specific.hh:160
future< typename function_traits< Reducer >::return_type > reduce_scheduling_group_specific(Reducer reducer, Initial initial_val, scheduling_group_key key)
Definition: scheduling_specific.hh:240
STL namespace.