blob: e0b771c6ddb11bdb549a013465a56010a1dbef68 [file] [log] [blame]
Tom Cherryfd44b9f2017-11-08 14:01:00 -08001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
12 * the documentation and/or other materials provided with the
13 * distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
Tom Cherrye275d6d2017-12-11 23:31:33 -080029#include "system_properties/system_properties.h"
30
Tom Cherryfd44b9f2017-11-08 14:01:00 -080031#include <errno.h>
Nate Myrenb8c87b12023-08-28 16:46:39 -070032#include <private/android_filesystem_config.h>
Tom Cherryfd44b9f2017-11-08 14:01:00 -080033#include <stdatomic.h>
Tom Cherryfd44b9f2017-11-08 14:01:00 -080034#include <stdlib.h>
35#include <string.h>
Tom Cherryfd44b9f2017-11-08 14:01:00 -080036#include <sys/stat.h>
37#include <sys/types.h>
Tom Cherryfd44b9f2017-11-08 14:01:00 -080038#include <unistd.h>
39
Tom Cherry8d366a82017-11-30 15:41:32 -080040#include <new>
41
Nate Myrenb8c87b12023-08-28 16:46:39 -070042#include <async_safe/CHECK.h>
Tom Cherryfd44b9f2017-11-08 14:01:00 -080043#include <async_safe/log.h>
44
45#include "private/ErrnoRestorer.h"
Tom Cherryfd44b9f2017-11-08 14:01:00 -080046#include "private/bionic_futex.h"
Tom Cherryfd44b9f2017-11-08 14:01:00 -080047
Tom Cherrye275d6d2017-12-11 23:31:33 -080048#include "system_properties/context_node.h"
49#include "system_properties/prop_area.h"
50#include "system_properties/prop_info.h"
Tom Cherryfd44b9f2017-11-08 14:01:00 -080051
52#define SERIAL_DIRTY(serial) ((serial)&1)
53#define SERIAL_VALUE_LEN(serial) ((serial) >> 24)
Nate Myrenb8c87b12023-08-28 16:46:39 -070054#define APPCOMPAT_PREFIX "ro.appcompat_override."
Tom Cherryfd44b9f2017-11-08 14:01:00 -080055
Tom Cherryfd44b9f2017-11-08 14:01:00 -080056static bool is_dir(const char* pathname) {
57 struct stat info;
58 if (stat(pathname, &info) == -1) {
59 return false;
60 }
61 return S_ISDIR(info.st_mode);
62}
63
Tom Cherrye275d6d2017-12-11 23:31:33 -080064bool SystemProperties::Init(const char* filename) {
Tom Cherryfd44b9f2017-11-08 14:01:00 -080065 // This is called from __libc_init_common, and should leave errno at 0 (http://b/37248982).
66 ErrnoRestorer errno_restorer;
67
Tom Cherrye275d6d2017-12-11 23:31:33 -080068 if (initialized_) {
Tom Cherryee8e3dd2018-02-21 15:01:22 -080069 contexts_->ResetAccess();
Tom Cherrye275d6d2017-12-11 23:31:33 -080070 return true;
Tom Cherryfd44b9f2017-11-08 14:01:00 -080071 }
Tom Cherrye275d6d2017-12-11 23:31:33 -080072
Elliott Hughesd19f7b12023-08-30 21:19:55 +000073 properties_filename_ = filename;
Tom Cherrye275d6d2017-12-11 23:31:33 -080074
Nate Myrenb8c87b12023-08-28 16:46:39 -070075 if (!InitContexts(false)) {
76 return false;
77 }
78
79 initialized_ = true;
80 return true;
81}
82
83bool SystemProperties::InitContexts(bool load_default_path) {
Elliott Hughesd19f7b12023-08-30 21:19:55 +000084 if (is_dir(properties_filename_.c_str())) {
Nate Myrenb8c87b12023-08-28 16:46:39 -070085 if (access(PROP_TREE_FILE, R_OK) == 0) {
86 auto serial_contexts = new (contexts_data_) ContextsSerialized();
87 contexts_ = serial_contexts;
88 if (!serial_contexts->Initialize(false, properties_filename_.c_str(), nullptr,
89 load_default_path)) {
Tom Cherrye275d6d2017-12-11 23:31:33 -080090 return false;
Tom Cherry8be995b2017-12-14 01:57:37 +000091 }
Tom Cherry8be995b2017-12-14 01:57:37 +000092 } else {
Tom Cherryee8e3dd2018-02-21 15:01:22 -080093 contexts_ = new (contexts_data_) ContextsSplit();
Elliott Hughesd19f7b12023-08-30 21:19:55 +000094 if (!contexts_->Initialize(false, properties_filename_.c_str(), nullptr)) {
Tom Cherrye275d6d2017-12-11 23:31:33 -080095 return false;
Tom Cherry8be995b2017-12-14 01:57:37 +000096 }
Tom Cherryfd44b9f2017-11-08 14:01:00 -080097 }
Tom Cherryfd44b9f2017-11-08 14:01:00 -080098 } else {
Tom Cherryee8e3dd2018-02-21 15:01:22 -080099 contexts_ = new (contexts_data_) ContextsPreSplit();
Elliott Hughesd19f7b12023-08-30 21:19:55 +0000100 if (!contexts_->Initialize(false, properties_filename_.c_str(), nullptr)) {
Tom Cherrye275d6d2017-12-11 23:31:33 -0800101 return false;
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800102 }
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800103 }
Tom Cherrye275d6d2017-12-11 23:31:33 -0800104 return true;
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800105}
106
Tom Cherrye275d6d2017-12-11 23:31:33 -0800107bool SystemProperties::AreaInit(const char* filename, bool* fsetxattr_failed) {
Nate Myrenb8c87b12023-08-28 16:46:39 -0700108 return AreaInit(filename, fsetxattr_failed, false);
109}
110
111// Note: load_default_path is only used for testing, as it will cause properties to be loaded from
112// one file (specified by PropertyInfoAreaFile.LoadDefaultPath), but be written to "filename".
113bool SystemProperties::AreaInit(const char* filename, bool* fsetxattr_failed,
114 bool load_default_path) {
Elliott Hughesd19f7b12023-08-30 21:19:55 +0000115 properties_filename_ = filename;
Nate Myrenb8c87b12023-08-28 16:46:39 -0700116 auto serial_contexts = new (contexts_data_) ContextsSerialized();
117 contexts_ = serial_contexts;
118 if (!serial_contexts->Initialize(true, properties_filename_.c_str(), fsetxattr_failed,
119 load_default_path)) {
Tom Cherrye275d6d2017-12-11 23:31:33 -0800120 return false;
121 }
Nate Myrenb8c87b12023-08-28 16:46:39 -0700122
123 auto* appcompat_contexts = new (appcompat_override_contexts_data_) ContextsSerialized();
124 appcompat_filename_ = PropertiesFilename(properties_filename_.c_str(), "appcompat_override");
125 if (!appcompat_contexts->Initialize(true, appcompat_filename_.c_str(), fsetxattr_failed,
126 load_default_path)) {
127 appcompat_override_contexts_ = nullptr;
128 return false;
129 }
130 appcompat_override_contexts_ = appcompat_contexts;
131
Tom Cherrye275d6d2017-12-11 23:31:33 -0800132 initialized_ = true;
133 return true;
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800134}
135
Nate Myrenb8c87b12023-08-28 16:46:39 -0700136bool SystemProperties::Reload(bool load_default_path) {
137 if (!initialized_) {
138 return true;
139 }
140
141 return InitContexts(load_default_path);
142}
143
Tom Cherrye275d6d2017-12-11 23:31:33 -0800144uint32_t SystemProperties::AreaSerial() {
145 if (!initialized_) {
Tom Cherryf76bbf52017-11-08 14:01:00 -0800146 return -1;
147 }
148
Tom Cherryee8e3dd2018-02-21 15:01:22 -0800149 prop_area* pa = contexts_->GetSerialPropArea();
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800150 if (!pa) {
151 return -1;
152 }
Tom Cherryf76bbf52017-11-08 14:01:00 -0800153
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800154 // Make sure this read fulfilled before __system_property_serial
155 return atomic_load_explicit(pa->serial(), memory_order_acquire);
156}
157
Tom Cherrye275d6d2017-12-11 23:31:33 -0800158const prop_info* SystemProperties::Find(const char* name) {
159 if (!initialized_) {
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800160 return nullptr;
161 }
162
Tom Cherryee8e3dd2018-02-21 15:01:22 -0800163 prop_area* pa = contexts_->GetPropAreaForName(name);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800164 if (!pa) {
Tom Cherry8f11c5f2021-04-01 15:07:40 -0700165 async_safe_format_log(ANDROID_LOG_WARN, "libc", "Access denied finding property \"%s\"", name);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800166 return nullptr;
167 }
168
169 return pa->find(name);
170}
171
Nate Myrenb8c87b12023-08-28 16:46:39 -0700172static bool is_appcompat_override(const char* name) {
173 return strncmp(name, APPCOMPAT_PREFIX, strlen(APPCOMPAT_PREFIX)) == 0;
174}
175
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800176static bool is_read_only(const char* name) {
177 return strncmp(name, "ro.", 3) == 0;
178}
179
Raman Tennetib481a2e2019-11-12 20:41:55 +0000180uint32_t SystemProperties::ReadMutablePropertyValue(const prop_info* pi, char* value) {
181 // We assume the memcpy below gets serialized by the acquire fence.
182 uint32_t new_serial = load_const_atomic(&pi->serial, memory_order_acquire);
183 uint32_t serial;
184 unsigned int len;
185 for (;;) {
186 serial = new_serial;
187 len = SERIAL_VALUE_LEN(serial);
188 if (__predict_false(SERIAL_DIRTY(serial))) {
189 // See the comment in the prop_area constructor.
190 prop_area* pa = contexts_->GetPropAreaForName(pi->name);
191 memcpy(value, pa->dirty_backup_area(), len + 1);
192 } else {
193 memcpy(value, pi->value, len + 1);
194 }
Raman Tennetide39d922019-11-12 18:24:06 +0000195 atomic_thread_fence(memory_order_acquire);
Raman Tennetib481a2e2019-11-12 20:41:55 +0000196 new_serial = load_const_atomic(&pi->serial, memory_order_relaxed);
197 if (__predict_true(serial == new_serial)) {
198 break;
199 }
200 // We need another fence here because we want to ensure that the memcpy in the
201 // next iteration of the loop occurs after the load of new_serial above. We could
202 // get this guarantee by making the load_const_atomic of new_serial
203 // memory_order_acquire instead of memory_order_relaxed, but then we'd pay the
204 // penalty of the memory_order_acquire even in the overwhelmingly common case
205 // that the serial number didn't change.
206 atomic_thread_fence(memory_order_acquire);
207 }
208 return serial;
209}
210
211int SystemProperties::Read(const prop_info* pi, char* name, char* value) {
212 uint32_t serial = ReadMutablePropertyValue(pi, value);
213 if (name != nullptr) {
214 size_t namelen = strlcpy(name, pi->name, PROP_NAME_MAX);
215 if (namelen >= PROP_NAME_MAX) {
216 async_safe_format_log(ANDROID_LOG_ERROR, "libc",
217 "The property name length for \"%s\" is >= %d;"
218 " please use __system_property_read_callback"
219 " to read this property. (the name is truncated to \"%s\")",
220 pi->name, PROP_NAME_MAX - 1, name);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800221 }
222 }
Raman Tennetib481a2e2019-11-12 20:41:55 +0000223 if (is_read_only(pi->name) && pi->is_long()) {
224 async_safe_format_log(
225 ANDROID_LOG_ERROR, "libc",
226 "The property \"%s\" has a value with length %zu that is too large for"
227 " __system_property_get()/__system_property_read(); use"
228 " __system_property_read_callback() instead.",
229 pi->name, strlen(pi->long_value()));
230 }
231 return SERIAL_VALUE_LEN(serial);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800232}
233
Tom Cherrye275d6d2017-12-11 23:31:33 -0800234void SystemProperties::ReadCallback(const prop_info* pi,
235 void (*callback)(void* cookie, const char* name,
236 const char* value, uint32_t serial),
237 void* cookie) {
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800238 // Read only properties don't need to copy the value to a temporary buffer, since it can never
Raman Tennetib481a2e2019-11-12 20:41:55 +0000239 // change. We use relaxed memory order on the serial load for the same reason.
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800240 if (is_read_only(pi->name)) {
Raman Tennetib481a2e2019-11-12 20:41:55 +0000241 uint32_t serial = load_const_atomic(&pi->serial, memory_order_relaxed);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800242 if (pi->is_long()) {
243 callback(cookie, pi->name, pi->long_value(), serial);
244 } else {
245 callback(cookie, pi->name, pi->value, serial);
246 }
247 return;
248 }
249
Raman Tennetib481a2e2019-11-12 20:41:55 +0000250 char value_buf[PROP_VALUE_MAX];
251 uint32_t serial = ReadMutablePropertyValue(pi, value_buf);
252 callback(cookie, pi->name, value_buf, serial);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800253}
254
Tom Cherrye275d6d2017-12-11 23:31:33 -0800255int SystemProperties::Get(const char* name, char* value) {
256 const prop_info* pi = Find(name);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800257
Yi Kong32bc0fc2018-08-02 17:31:13 -0700258 if (pi != nullptr) {
Tom Cherrye275d6d2017-12-11 23:31:33 -0800259 return Read(pi, nullptr, value);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800260 } else {
261 value[0] = 0;
262 return 0;
263 }
264}
265
Tom Cherrye275d6d2017-12-11 23:31:33 -0800266int SystemProperties::Update(prop_info* pi, const char* value, unsigned int len) {
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800267 if (len >= PROP_VALUE_MAX) {
268 return -1;
269 }
270
Tom Cherrye275d6d2017-12-11 23:31:33 -0800271 if (!initialized_) {
Tom Cherryf76bbf52017-11-08 14:01:00 -0800272 return -1;
273 }
Nate Myrenb8c87b12023-08-28 16:46:39 -0700274 bool have_override = appcompat_override_contexts_ != nullptr;
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800275
Raman Tennetib481a2e2019-11-12 20:41:55 +0000276 prop_area* serial_pa = contexts_->GetSerialPropArea();
Nate Myrenb8c87b12023-08-28 16:46:39 -0700277 prop_area* override_serial_pa =
278 have_override ? appcompat_override_contexts_->GetSerialPropArea() : nullptr;
Raman Tennetib481a2e2019-11-12 20:41:55 +0000279 if (!serial_pa) {
280 return -1;
281 }
282 prop_area* pa = contexts_->GetPropAreaForName(pi->name);
Nate Myrenb8c87b12023-08-28 16:46:39 -0700283 prop_area* override_pa =
284 have_override ? appcompat_override_contexts_->GetPropAreaForName(pi->name) : nullptr;
Raman Tennetib481a2e2019-11-12 20:41:55 +0000285 if (__predict_false(!pa)) {
286 async_safe_format_log(ANDROID_LOG_ERROR, "libc", "Could not find area for \"%s\"", pi->name);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800287 return -1;
288 }
Nate Myrenb8c87b12023-08-28 16:46:39 -0700289 CHECK(!have_override || (override_pa && override_serial_pa));
290
291 auto* override_pi = const_cast<prop_info*>(have_override ? override_pa->find(pi->name) : nullptr);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800292
293 uint32_t serial = atomic_load_explicit(&pi->serial, memory_order_relaxed);
Raman Tennetib481a2e2019-11-12 20:41:55 +0000294 unsigned int old_len = SERIAL_VALUE_LEN(serial);
295
296 // The contract with readers is that whenever the dirty bit is set, an undamaged copy
297 // of the pre-dirty value is available in the dirty backup area. The fence ensures
298 // that we publish our dirty area update before allowing readers to see a
299 // dirty serial.
300 memcpy(pa->dirty_backup_area(), pi->value, old_len + 1);
Nate Myrenb8c87b12023-08-28 16:46:39 -0700301 if (have_override) {
302 memcpy(override_pa->dirty_backup_area(), override_pi->value, old_len + 1);
303 }
Raman Tennetib481a2e2019-11-12 20:41:55 +0000304 atomic_thread_fence(memory_order_release);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800305 serial |= 1;
306 atomic_store_explicit(&pi->serial, serial, memory_order_relaxed);
Raman Tennetide39d922019-11-12 18:24:06 +0000307 strlcpy(pi->value, value, len + 1);
Nate Myrenb8c87b12023-08-28 16:46:39 -0700308 if (have_override) {
309 atomic_store_explicit(&override_pi->serial, serial, memory_order_relaxed);
310 strlcpy(override_pi->value, value, len + 1);
311 }
Raman Tennetib481a2e2019-11-12 20:41:55 +0000312 // Now the primary value property area is up-to-date. Let readers know that they should
313 // look at the property value instead of the backup area.
314 atomic_thread_fence(memory_order_release);
Nate Myrenb8c87b12023-08-28 16:46:39 -0700315 int new_serial = (len << 24) | ((serial + 1) & 0xffffff);
316 atomic_store_explicit(&pi->serial, new_serial, memory_order_relaxed);
317 if (have_override) {
318 atomic_store_explicit(&override_pi->serial, new_serial, memory_order_relaxed);
319 }
Raman Tennetib481a2e2019-11-12 20:41:55 +0000320 __futex_wake(&pi->serial, INT32_MAX); // Fence by side effect
321 atomic_store_explicit(serial_pa->serial(),
322 atomic_load_explicit(serial_pa->serial(), memory_order_relaxed) + 1,
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800323 memory_order_release);
Nate Myrenb8c87b12023-08-28 16:46:39 -0700324 if (have_override) {
325 atomic_store_explicit(override_serial_pa->serial(),
326 atomic_load_explicit(serial_pa->serial(), memory_order_relaxed) + 1,
327 memory_order_release);
328 }
Raman Tennetib481a2e2019-11-12 20:41:55 +0000329 __futex_wake(serial_pa->serial(), INT32_MAX);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800330
331 return 0;
332}
333
Tom Cherrye275d6d2017-12-11 23:31:33 -0800334int SystemProperties::Add(const char* name, unsigned int namelen, const char* value,
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800335 unsigned int valuelen) {
336 if (valuelen >= PROP_VALUE_MAX && !is_read_only(name)) {
337 return -1;
338 }
339
340 if (namelen < 1) {
341 return -1;
342 }
343
Tom Cherrye275d6d2017-12-11 23:31:33 -0800344 if (!initialized_) {
Tom Cherryf76bbf52017-11-08 14:01:00 -0800345 return -1;
346 }
347
Tom Cherryee8e3dd2018-02-21 15:01:22 -0800348 prop_area* serial_pa = contexts_->GetSerialPropArea();
Tom Cherryf76bbf52017-11-08 14:01:00 -0800349 if (serial_pa == nullptr) {
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800350 return -1;
351 }
352
Tom Cherryee8e3dd2018-02-21 15:01:22 -0800353 prop_area* pa = contexts_->GetPropAreaForName(name);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800354 if (!pa) {
355 async_safe_format_log(ANDROID_LOG_ERROR, "libc", "Access denied adding property \"%s\"", name);
356 return -1;
357 }
358
359 bool ret = pa->add(name, namelen, value, valuelen);
360 if (!ret) {
361 return -1;
362 }
363
Nate Myrenb8c87b12023-08-28 16:46:39 -0700364 if (appcompat_override_contexts_ != nullptr) {
365 bool is_override = is_appcompat_override(name);
366 const char* override_name = name;
367 if (is_override) override_name += strlen(APPCOMPAT_PREFIX);
368 prop_area* other_pa = appcompat_override_contexts_->GetPropAreaForName(override_name);
369 prop_area* other_serial_pa = appcompat_override_contexts_->GetSerialPropArea();
370 CHECK(other_pa && other_serial_pa);
371 // We may write a property twice to overrides, once for the ro.*, and again for the
372 // ro.appcompat_override.ro.* property. If we've already written, then we should essentially
373 // perform an Update, not an Add.
374 auto other_pi = const_cast<prop_info*>(other_pa->find(override_name));
375 if (!other_pi) {
376 if (other_pa->add(override_name, strlen(override_name), value, valuelen)) {
377 atomic_store_explicit(
378 other_serial_pa->serial(),
379 atomic_load_explicit(other_serial_pa->serial(), memory_order_relaxed) + 1,
380 memory_order_release);
381 }
382 } else if (is_override) {
383 // We already wrote the ro.*, but appcompat_override.ro.* should override that. We don't
384 // need to do the usual dirty bit setting, as this only happens during the init process,
385 // before any readers are started.
386 CHECK(getpid() == 1);
387 atomic_thread_fence(memory_order_release);
388 strlcpy(other_pi->value, value, valuelen + 1);
389 }
390 }
391
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800392 // There is only a single mutator, but we want to make sure that
393 // updates are visible to a reader waiting for the update.
Tom Cherryf76bbf52017-11-08 14:01:00 -0800394 atomic_store_explicit(serial_pa->serial(),
395 atomic_load_explicit(serial_pa->serial(), memory_order_relaxed) + 1,
396 memory_order_release);
397 __futex_wake(serial_pa->serial(), INT32_MAX);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800398 return 0;
399}
400
Tom Cherrye275d6d2017-12-11 23:31:33 -0800401uint32_t SystemProperties::WaitAny(uint32_t old_serial) {
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800402 uint32_t new_serial;
Tom Cherrye275d6d2017-12-11 23:31:33 -0800403 Wait(nullptr, old_serial, &new_serial, nullptr);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800404 return new_serial;
405}
406
Tom Cherrye275d6d2017-12-11 23:31:33 -0800407bool SystemProperties::Wait(const prop_info* pi, uint32_t old_serial, uint32_t* new_serial_ptr,
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800408 const timespec* relative_timeout) {
409 // Are we waiting on the global serial or a specific serial?
410 atomic_uint_least32_t* serial_ptr;
411 if (pi == nullptr) {
Tom Cherrye275d6d2017-12-11 23:31:33 -0800412 if (!initialized_) {
Tom Cherryf76bbf52017-11-08 14:01:00 -0800413 return -1;
414 }
415
Tom Cherryee8e3dd2018-02-21 15:01:22 -0800416 prop_area* serial_pa = contexts_->GetSerialPropArea();
Tom Cherryf76bbf52017-11-08 14:01:00 -0800417 if (serial_pa == nullptr) {
418 return -1;
419 }
420
421 serial_ptr = serial_pa->serial();
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800422 } else {
423 serial_ptr = const_cast<atomic_uint_least32_t*>(&pi->serial);
424 }
425
426 uint32_t new_serial;
427 do {
428 int rc;
429 if ((rc = __futex_wait(serial_ptr, old_serial, relative_timeout)) != 0 && rc == -ETIMEDOUT) {
430 return false;
431 }
432 new_serial = load_const_atomic(serial_ptr, memory_order_acquire);
433 } while (new_serial == old_serial);
434
435 *new_serial_ptr = new_serial;
436 return true;
437}
438
Tom Cherrye275d6d2017-12-11 23:31:33 -0800439const prop_info* SystemProperties::FindNth(unsigned n) {
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800440 struct find_nth {
441 const uint32_t sought;
442 uint32_t current;
443 const prop_info* result;
444
445 explicit find_nth(uint32_t n) : sought(n), current(0), result(nullptr) {
446 }
447 static void fn(const prop_info* pi, void* ptr) {
448 find_nth* self = reinterpret_cast<find_nth*>(ptr);
449 if (self->current++ == self->sought) self->result = pi;
450 }
451 } state(n);
Tom Cherrye275d6d2017-12-11 23:31:33 -0800452 Foreach(find_nth::fn, &state);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800453 return state.result;
454}
455
Tom Cherrye275d6d2017-12-11 23:31:33 -0800456int SystemProperties::Foreach(void (*propfn)(const prop_info* pi, void* cookie), void* cookie) {
457 if (!initialized_) {
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800458 return -1;
459 }
460
Tom Cherryee8e3dd2018-02-21 15:01:22 -0800461 contexts_->ForEach(propfn, cookie);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800462
463 return 0;
464}