flag.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  1. //
  2. // Copyright 2019 The Abseil Authors.
  3. //
  4. // Licensed under the Apache License, Version 2.0 (the "License");
  5. // you may not use this file except in compliance with the License.
  6. // You may obtain a copy of the License at
  7. //
  8. // https://www.apache.org/licenses/LICENSE-2.0
  9. //
  10. // Unless required by applicable law or agreed to in writing, software
  11. // distributed under the License is distributed on an "AS IS" BASIS,
  12. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. // See the License for the specific language governing permissions and
  14. // limitations under the License.
  15. #include "absl/flags/internal/flag.h"
  16. #include <stddef.h>
  17. #include <stdint.h>
  18. #include <string.h>
  19. #include <atomic>
  20. #include <memory>
  21. #include <string>
  22. #include <vector>
  23. #include "absl/base/attributes.h"
  24. #include "absl/base/config.h"
  25. #include "absl/base/const_init.h"
  26. #include "absl/base/optimization.h"
  27. #include "absl/flags/internal/commandlineflag.h"
  28. #include "absl/flags/usage_config.h"
  29. #include "absl/strings/str_cat.h"
  30. #include "absl/strings/string_view.h"
  31. #include "absl/synchronization/mutex.h"
  32. namespace absl {
  33. ABSL_NAMESPACE_BEGIN
  34. namespace flags_internal {
  35. // The help message indicating that the commandline flag has been
  36. // 'stripped'. It will not show up when doing "-help" and its
  37. // variants. The flag is stripped if ABSL_FLAGS_STRIP_HELP is set to 1
  38. // before including absl/flags/flag.h
  39. const char kStrippedFlagHelp[] = "\001\002\003\004 (unknown) \004\003\002\001";
  40. namespace {
  41. // Currently we only validate flag values for user-defined flag types.
  42. bool ShouldValidateFlagValue(FlagStaticTypeId flag_type_id) {
  43. #define DONT_VALIDATE(T) \
  44. if (flag_type_id == &FlagStaticTypeIdGen<T>) return false;
  45. ABSL_FLAGS_INTERNAL_BUILTIN_TYPES(DONT_VALIDATE)
  46. #undef DONT_VALIDATE
  47. return true;
  48. }
  49. // RAII helper used to temporarily unlock and relock `absl::Mutex`.
  50. // This is used when we need to ensure that locks are released while
  51. // invoking user supplied callbacks and then reacquired, since callbacks may
  52. // need to acquire these locks themselves.
  53. class MutexRelock {
  54. public:
  55. explicit MutexRelock(absl::Mutex* mu) : mu_(mu) { mu_->Unlock(); }
  56. ~MutexRelock() { mu_->Lock(); }
  57. MutexRelock(const MutexRelock&) = delete;
  58. MutexRelock& operator=(const MutexRelock&) = delete;
  59. private:
  60. absl::Mutex* mu_;
  61. };
  62. } // namespace
  63. void FlagImpl::Init() {
  64. new (&data_guard_) absl::Mutex;
  65. absl::MutexLock lock(reinterpret_cast<absl::Mutex*>(&data_guard_));
  66. value_.dynamic = MakeInitValue().release();
  67. StoreAtomic();
  68. }
  69. // Ensures that the lazily initialized data is initialized,
  70. // and returns pointer to the mutex guarding flags data.
  71. absl::Mutex* FlagImpl::DataGuard() const {
  72. absl::call_once(const_cast<FlagImpl*>(this)->init_control_, &FlagImpl::Init,
  73. const_cast<FlagImpl*>(this));
  74. // data_guard_ is initialized.
  75. return reinterpret_cast<absl::Mutex*>(&data_guard_);
  76. }
  77. void FlagImpl::AssertValidType(FlagStaticTypeId type_id) const {
  78. FlagStaticTypeId this_type_id = flags_internal::StaticTypeId(op_);
  79. // `type_id` is the type id corresponding to the declaration visibile at the
  80. // call site. `this_type_id` is the type id corresponding to the type stored
  81. // during flag definition. They must match for this operation to be
  82. // well-defined.
  83. if (ABSL_PREDICT_TRUE(type_id == this_type_id)) return;
  84. void* lhs_runtime_type_id = type_id();
  85. void* rhs_runtime_type_id = this_type_id();
  86. if (lhs_runtime_type_id == rhs_runtime_type_id) return;
  87. #if defined(ABSL_FLAGS_INTERNAL_HAS_RTTI)
  88. if (*reinterpret_cast<std::type_info*>(lhs_runtime_type_id) ==
  89. *reinterpret_cast<std::type_info*>(rhs_runtime_type_id))
  90. return;
  91. #endif
  92. ABSL_INTERNAL_LOG(
  93. FATAL, absl::StrCat("Flag '", Name(),
  94. "' is defined as one type and declared as another"));
  95. }
  96. std::unique_ptr<void, DynValueDeleter> FlagImpl::MakeInitValue() const {
  97. void* res = nullptr;
  98. if (DefaultKind() == FlagDefaultKind::kDynamicValue) {
  99. res = flags_internal::Clone(op_, default_src_.dynamic_value);
  100. } else {
  101. res = (*default_src_.gen_func)();
  102. }
  103. return {res, DynValueDeleter{op_}};
  104. }
  105. absl::string_view FlagImpl::Name() const { return name_; }
  106. std::string FlagImpl::Filename() const {
  107. return flags_internal::GetUsageConfig().normalize_filename(filename_);
  108. }
  109. std::string FlagImpl::Help() const {
  110. return HelpSourceKind() == FlagHelpKind::kLiteral ? help_.literal
  111. : help_.gen_func();
  112. }
  113. bool FlagImpl::IsModified() const {
  114. absl::MutexLock l(DataGuard());
  115. return modified_;
  116. }
  117. bool FlagImpl::IsSpecifiedOnCommandLine() const {
  118. absl::MutexLock l(DataGuard());
  119. return on_command_line_;
  120. }
  121. std::string FlagImpl::DefaultValue() const {
  122. absl::MutexLock l(DataGuard());
  123. auto obj = MakeInitValue();
  124. return flags_internal::Unparse(op_, obj.get());
  125. }
  126. std::string FlagImpl::CurrentValue() const {
  127. absl::MutexLock l(DataGuard());
  128. return flags_internal::Unparse(op_, value_.dynamic);
  129. }
  130. void FlagImpl::SetCallback(const FlagCallbackFunc mutation_callback) {
  131. absl::MutexLock l(DataGuard());
  132. if (callback_ == nullptr) {
  133. callback_ = new FlagCallback;
  134. }
  135. callback_->func = mutation_callback;
  136. InvokeCallback();
  137. }
  138. void FlagImpl::InvokeCallback() const {
  139. if (!callback_) return;
  140. // Make a copy of the C-style function pointer that we are about to invoke
  141. // before we release the lock guarding it.
  142. FlagCallbackFunc cb = callback_->func;
  143. // If the flag has a mutation callback this function invokes it. While the
  144. // callback is being invoked the primary flag's mutex is unlocked and it is
  145. // re-locked back after call to callback is completed. Callback invocation is
  146. // guarded by flag's secondary mutex instead which prevents concurrent
  147. // callback invocation. Note that it is possible for other thread to grab the
  148. // primary lock and update flag's value at any time during the callback
  149. // invocation. This is by design. Callback can get a value of the flag if
  150. // necessary, but it might be different from the value initiated the callback
  151. // and it also can be different by the time the callback invocation is
  152. // completed. Requires that *primary_lock be held in exclusive mode; it may be
  153. // released and reacquired by the implementation.
  154. MutexRelock relock(DataGuard());
  155. absl::MutexLock lock(&callback_->guard);
  156. cb();
  157. }
  158. bool FlagImpl::RestoreState(const void* value, bool modified,
  159. bool on_command_line, int64_t counter) {
  160. {
  161. absl::MutexLock l(DataGuard());
  162. if (counter_ == counter) return false;
  163. }
  164. Write(value);
  165. {
  166. absl::MutexLock l(DataGuard());
  167. modified_ = modified;
  168. on_command_line_ = on_command_line;
  169. }
  170. return true;
  171. }
  172. // Attempts to parse supplied `value` string using parsing routine in the `flag`
  173. // argument. If parsing successful, this function replaces the dst with newly
  174. // parsed value. In case if any error is encountered in either step, the error
  175. // message is stored in 'err'
  176. bool FlagImpl::TryParse(void** dst, absl::string_view value,
  177. std::string* err) const {
  178. auto tentative_value = MakeInitValue();
  179. std::string parse_err;
  180. if (!flags_internal::Parse(op_, value, tentative_value.get(), &parse_err)) {
  181. absl::string_view err_sep = parse_err.empty() ? "" : "; ";
  182. *err = absl::StrCat("Illegal value '", value, "' specified for flag '",
  183. Name(), "'", err_sep, parse_err);
  184. return false;
  185. }
  186. void* old_val = *dst;
  187. *dst = tentative_value.release();
  188. tentative_value.reset(old_val);
  189. return true;
  190. }
  191. void FlagImpl::Read(void* dst) const {
  192. absl::ReaderMutexLock l(DataGuard());
  193. flags_internal::CopyConstruct(op_, value_.dynamic, dst);
  194. }
  195. void FlagImpl::StoreAtomic() {
  196. size_t data_size = flags_internal::Sizeof(op_);
  197. if (data_size <= sizeof(int64_t)) {
  198. int64_t t = 0;
  199. std::memcpy(&t, value_.dynamic, data_size);
  200. value_.atomics.small_atomic.store(t, std::memory_order_release);
  201. }
  202. #if defined(ABSL_FLAGS_INTERNAL_ATOMIC_DOUBLE_WORD)
  203. else if (data_size <= sizeof(FlagsInternalTwoWordsType)) {
  204. FlagsInternalTwoWordsType t{0, 0};
  205. std::memcpy(&t, value_.dynamic, data_size);
  206. value_.atomics.big_atomic.store(t, std::memory_order_release);
  207. }
  208. #endif
  209. }
  210. void FlagImpl::Write(const void* src) {
  211. absl::MutexLock l(DataGuard());
  212. if (ShouldValidateFlagValue(flags_internal::StaticTypeId(op_))) {
  213. void* obj = flags_internal::Clone(op_, src);
  214. std::string ignored_error;
  215. std::string src_as_str = flags_internal::Unparse(op_, src);
  216. if (!flags_internal::Parse(op_, src_as_str, obj, &ignored_error)) {
  217. ABSL_INTERNAL_LOG(ERROR, absl::StrCat("Attempt to set flag '", Name(),
  218. "' to invalid value ", src_as_str));
  219. }
  220. flags_internal::Delete(op_, obj);
  221. }
  222. modified_ = true;
  223. counter_++;
  224. flags_internal::Copy(op_, src, value_.dynamic);
  225. StoreAtomic();
  226. InvokeCallback();
  227. }
  228. // Sets the value of the flag based on specified string `value`. If the flag
  229. // was successfully set to new value, it returns true. Otherwise, sets `err`
  230. // to indicate the error, leaves the flag unchanged, and returns false. There
  231. // are three ways to set the flag's value:
  232. // * Update the current flag value
  233. // * Update the flag's default value
  234. // * Update the current flag value if it was never set before
  235. // The mode is selected based on 'set_mode' parameter.
  236. bool FlagImpl::SetFromString(absl::string_view value, FlagSettingMode set_mode,
  237. ValueSource source, std::string* err) {
  238. absl::MutexLock l(DataGuard());
  239. switch (set_mode) {
  240. case SET_FLAGS_VALUE: {
  241. // set or modify the flag's value
  242. if (!TryParse(&value_.dynamic, value, err)) return false;
  243. modified_ = true;
  244. counter_++;
  245. StoreAtomic();
  246. InvokeCallback();
  247. if (source == kCommandLine) {
  248. on_command_line_ = true;
  249. }
  250. break;
  251. }
  252. case SET_FLAG_IF_DEFAULT: {
  253. // set the flag's value, but only if it hasn't been set by someone else
  254. if (!modified_) {
  255. if (!TryParse(&value_.dynamic, value, err)) return false;
  256. modified_ = true;
  257. counter_++;
  258. StoreAtomic();
  259. InvokeCallback();
  260. } else {
  261. // TODO(rogeeff): review and fix this semantic. Currently we do not fail
  262. // in this case if flag is modified. This is misleading since the flag's
  263. // value is not updated even though we return true.
  264. // *err = absl::StrCat(Name(), " is already set to ",
  265. // CurrentValue(), "\n");
  266. // return false;
  267. return true;
  268. }
  269. break;
  270. }
  271. case SET_FLAGS_DEFAULT: {
  272. if (DefaultKind() == FlagDefaultKind::kDynamicValue) {
  273. if (!TryParse(&default_src_.dynamic_value, value, err)) {
  274. return false;
  275. }
  276. } else {
  277. void* new_default_val = nullptr;
  278. if (!TryParse(&new_default_val, value, err)) {
  279. return false;
  280. }
  281. default_src_.dynamic_value = new_default_val;
  282. def_kind_ = static_cast<uint8_t>(FlagDefaultKind::kDynamicValue);
  283. }
  284. if (!modified_) {
  285. // Need to set both default value *and* current, in this case
  286. flags_internal::Copy(op_, default_src_.dynamic_value, value_.dynamic);
  287. StoreAtomic();
  288. InvokeCallback();
  289. }
  290. break;
  291. }
  292. }
  293. return true;
  294. }
  295. void FlagImpl::CheckDefaultValueParsingRoundtrip() const {
  296. std::string v = DefaultValue();
  297. absl::MutexLock lock(DataGuard());
  298. auto dst = MakeInitValue();
  299. std::string error;
  300. if (!flags_internal::Parse(op_, v, dst.get(), &error)) {
  301. ABSL_INTERNAL_LOG(
  302. FATAL,
  303. absl::StrCat("Flag ", Name(), " (from ", Filename(),
  304. "): std::string form of default value '", v,
  305. "' could not be parsed; error=", error));
  306. }
  307. // We do not compare dst to def since parsing/unparsing may make
  308. // small changes, e.g., precision loss for floating point types.
  309. }
  310. bool FlagImpl::ValidateInputValue(absl::string_view value) const {
  311. absl::MutexLock l(DataGuard());
  312. auto obj = MakeInitValue();
  313. std::string ignored_error;
  314. return flags_internal::Parse(op_, value, obj.get(), &ignored_error);
  315. }
  316. } // namespace flags_internal
  317. ABSL_NAMESPACE_END
  318. } // namespace absl