00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "absl/flags/internal/commandlineflag.h"
00017
00018 #include <cassert>
00019
00020 #include "absl/base/internal/raw_logging.h"
00021 #include "absl/base/optimization.h"
00022 #include "absl/flags/config.h"
00023 #include "absl/flags/usage_config.h"
00024 #include "absl/strings/str_cat.h"
00025 #include "absl/synchronization/mutex.h"
00026
00027 namespace absl {
00028 namespace flags_internal {
00029
00030
00031
00032
00033
00034
00035
00036 const char kStrippedFlagHelp[] = "\001\002\003\004 (unknown) \004\003\002\001";
00037
00038 namespace {
00039
00040 void StoreAtomic(CommandLineFlag* flag, const void* data, size_t size) {
00041 int64_t t = 0;
00042 assert(size <= sizeof(int64_t));
00043 memcpy(&t, data, size);
00044 flag->atomic.store(t, std::memory_order_release);
00045 }
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058 void InvokeCallback(CommandLineFlag* flag, absl::Mutex* primary_lock)
00059 EXCLUSIVE_LOCKS_REQUIRED(primary_lock) {
00060 if (!flag->callback) return;
00061
00062
00063 absl::Mutex* callback_mu = &flag->locks->callback_mu;
00064
00065
00066
00067 primary_lock->Unlock();
00068
00069 {
00070 absl::MutexLock lock(callback_mu);
00071
00072 flag->callback();
00073 }
00074
00075 primary_lock->Lock();
00076 }
00077
00078
00079 bool ShouldValidateFlagValue(const CommandLineFlag& flag) {
00080 #define DONT_VALIDATE(T) \
00081 if (flag.IsOfType<T>()) return false;
00082 ABSL_FLAGS_INTERNAL_FOR_EACH_LOCK_FREE(DONT_VALIDATE)
00083 DONT_VALIDATE(std::string)
00084 DONT_VALIDATE(std::vector<std::string>)
00085 #undef DONT_VALIDATE
00086
00087 return true;
00088 }
00089
00090 }
00091
00092
00093
00094 void UpdateCopy(CommandLineFlag* flag, absl::Mutex* primary_lock)
00095 EXCLUSIVE_LOCKS_REQUIRED(primary_lock) {
00096 #define STORE_ATOMIC(T) \
00097 else if (flag->IsOfType<T>()) { \
00098 StoreAtomic(flag, flag->cur, sizeof(T)); \
00099 }
00100
00101 if (false) {
00102 }
00103 ABSL_FLAGS_INTERNAL_FOR_EACH_LOCK_FREE(STORE_ATOMIC)
00104 #undef STORE_ATOMIC
00105
00106 InvokeCallback(flag, primary_lock);
00107 }
00108
00109
00110
00111 absl::Mutex* InitFlagIfNecessary(CommandLineFlag* flag)
00112 LOCK_RETURNED(flag->locks->primary_mu) {
00113 absl::Mutex* mu;
00114 if (!flag->inited.load(std::memory_order_acquire)) {
00115
00116 ABSL_CONST_INIT static absl::Mutex init_lock(absl::kConstInit);
00117 init_lock.Lock();
00118 if (flag->locks == nullptr) {
00119 flag->locks = new flags_internal::CommandLineFlagLocks;
00120 }
00121 mu = &flag->locks->primary_mu;
00122 init_lock.Unlock();
00123 mu->Lock();
00124 if (!flag->retired &&
00125 flag->def == nullptr) {
00126 flag->def = (*flag->make_init_value)();
00127 flag->cur = Clone(flag->op, flag->def);
00128 UpdateCopy(flag, mu);
00129 }
00130 mu->Unlock();
00131 flag->inited.store(true, std::memory_order_release);
00132 } else {
00133 mu = &flag->locks->primary_mu;
00134 }
00135 return mu;
00136 }
00137
00138
00139 bool ChangedDirectly(CommandLineFlag* flag, const void* a, const void* b) {
00140 if (!flag->IsAbseilFlag()) {
00141
00142 #define CHANGED_FOR_TYPE(T) \
00143 if (flag->IsOfType<T>()) { \
00144 return *reinterpret_cast<const T*>(a) != *reinterpret_cast<const T*>(b); \
00145 }
00146
00147 CHANGED_FOR_TYPE(bool);
00148 CHANGED_FOR_TYPE(int32_t);
00149 CHANGED_FOR_TYPE(int64_t);
00150 CHANGED_FOR_TYPE(uint64_t);
00151 CHANGED_FOR_TYPE(double);
00152 CHANGED_FOR_TYPE(std::string);
00153 #undef CHANGED_FOR_TYPE
00154 }
00155 return false;
00156 }
00157
00158
00159
00160 void UpdateModifiedBit(CommandLineFlag* flag) {
00161 if (!flag->IsAbseilFlag()) {
00162 absl::MutexLock l(InitFlagIfNecessary(flag));
00163 if (!flag->modified && ChangedDirectly(flag, flag->cur, flag->def)) {
00164 flag->modified = true;
00165 }
00166 }
00167 }
00168
00169 bool Validate(CommandLineFlag*, const void*) {
00170 return true;
00171 }
00172
00173 std::string HelpText::GetHelpText() const {
00174 if (help_function_) return help_function_();
00175 if (help_message_) return help_message_;
00176
00177 return {};
00178 }
00179
00180 const int64_t CommandLineFlag::kAtomicInit;
00181
00182 void CommandLineFlag::Read(void* dst,
00183 const flags_internal::FlagOpFn dst_op) const {
00184 absl::ReaderMutexLock l(
00185 InitFlagIfNecessary(const_cast<CommandLineFlag*>(this)));
00186
00187
00188
00189
00190 if (ABSL_PREDICT_FALSE(dst_op != op)) {
00191 ABSL_INTERNAL_LOG(
00192 ERROR,
00193 absl::StrCat("Flag '", name,
00194 "' is defined as one type and declared as another"));
00195 }
00196 CopyConstruct(op, cur, dst);
00197 }
00198
00199 void CommandLineFlag::Write(const void* src,
00200 const flags_internal::FlagOpFn src_op) {
00201 absl::Mutex* mu = InitFlagIfNecessary(this);
00202 absl::MutexLock l(mu);
00203
00204
00205
00206
00207 if (ABSL_PREDICT_FALSE(src_op != op)) {
00208 ABSL_INTERNAL_LOG(
00209 ERROR,
00210 absl::StrCat("Flag '", name,
00211 "' is defined as one type and declared as another"));
00212 }
00213
00214 if (ShouldValidateFlagValue(*this)) {
00215 void* obj = Clone(op, src);
00216 std::string ignored_error;
00217 std::string src_as_str = Unparse(marshalling_op, src);
00218 if (!Parse(marshalling_op, src_as_str, obj, &ignored_error) ||
00219 !Validate(this, obj)) {
00220 ABSL_INTERNAL_LOG(ERROR, absl::StrCat("Attempt to set flag '", name,
00221 "' to invalid value ", src_as_str));
00222 }
00223 Delete(op, obj);
00224 }
00225
00226 modified = true;
00227 counter++;
00228 Copy(op, src, cur);
00229
00230 UpdateCopy(this, mu);
00231 }
00232
00233 absl::string_view CommandLineFlag::Typename() const {
00234
00235
00236 if (IsAbseilFlag() || IsRetired()) return "";
00237
00238 #define HANDLE_V1_BUILTIN_TYPE(t) \
00239 if (IsOfType<t>()) { \
00240 return #t; \
00241 }
00242
00243 HANDLE_V1_BUILTIN_TYPE(bool);
00244 HANDLE_V1_BUILTIN_TYPE(int32_t);
00245 HANDLE_V1_BUILTIN_TYPE(int64_t);
00246 HANDLE_V1_BUILTIN_TYPE(uint64_t);
00247 HANDLE_V1_BUILTIN_TYPE(double);
00248 #undef HANDLE_V1_BUILTIN_TYPE
00249
00250 if (IsOfType<std::string>()) {
00251 return "string";
00252 }
00253
00254 return "";
00255 }
00256
00257 std::string CommandLineFlag::Filename() const {
00258 return flags_internal::GetUsageConfig().normalize_filename(this->filename);
00259 }
00260
00261 std::string CommandLineFlag::DefaultValue() const {
00262 return Unparse(this->marshalling_op, this->def);
00263 }
00264
00265 std::string CommandLineFlag::CurrentValue() const {
00266 return Unparse(this->marshalling_op, this->cur);
00267 }
00268
00269 void CommandLineFlag::SetCallback(
00270 const flags_internal::FlagCallback mutation_callback) {
00271 absl::Mutex* mu = InitFlagIfNecessary(this);
00272 absl::MutexLock l(mu);
00273
00274 callback = mutation_callback;
00275
00276 InvokeCallback(this, mu);
00277 }
00278
00279
00280
00281
00282
00283
00284
00285 static bool TryParseLocked(CommandLineFlag* flag, void* dst,
00286 absl::string_view value, std::string* err) {
00287 void* tentative_value = Clone(flag->op, flag->def);
00288 std::string parse_err;
00289 if (!Parse(flag->marshalling_op, value, tentative_value, &parse_err)) {
00290 auto type_name = flag->Typename();
00291 absl::string_view err_sep = parse_err.empty() ? "" : "; ";
00292 absl::string_view typename_sep = type_name.empty() ? "" : " ";
00293 *err = absl::StrCat("Illegal value '", value, "' specified for",
00294 typename_sep, type_name, " flag '", flag->Name(), "'",
00295 err_sep, parse_err);
00296 Delete(flag->op, tentative_value);
00297 return false;
00298 }
00299
00300 if (!Validate(flag, tentative_value)) {
00301 *err = absl::StrCat("Failed validation of new value '",
00302 Unparse(flag->marshalling_op, tentative_value),
00303 "' for flag '", flag->Name(), "'");
00304 Delete(flag->op, tentative_value);
00305 return false;
00306 }
00307
00308 flag->counter++;
00309 Copy(flag->op, tentative_value, dst);
00310 Delete(flag->op, tentative_value);
00311 return true;
00312 }
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322 bool CommandLineFlag::SetFromString(absl::string_view value,
00323 FlagSettingMode set_mode,
00324 ValueSource source, std::string* err) {
00325 if (IsRetired()) return false;
00326
00327 UpdateModifiedBit(this);
00328
00329 absl::Mutex* mu = InitFlagIfNecessary(this);
00330 absl::MutexLock l(mu);
00331
00332 switch (set_mode) {
00333 case SET_FLAGS_VALUE: {
00334
00335 if (!TryParseLocked(this, this->cur, value, err)) return false;
00336 this->modified = true;
00337 UpdateCopy(this, mu);
00338
00339 if (source == kCommandLine) {
00340 this->on_command_line = true;
00341 }
00342 break;
00343 }
00344 case SET_FLAG_IF_DEFAULT: {
00345
00346 if (!this->modified) {
00347 if (!TryParseLocked(this, this->cur, value, err)) return false;
00348 this->modified = true;
00349 UpdateCopy(this, mu);
00350 } else {
00351
00352
00353
00354
00355
00356
00357 return true;
00358 }
00359 break;
00360 }
00361 case SET_FLAGS_DEFAULT: {
00362
00363 if (!TryParseLocked(this, this->def, value, err)) return false;
00364
00365 if (!this->modified) {
00366
00367 Copy(this->op, this->def, this->cur);
00368 UpdateCopy(this, mu);
00369 }
00370 break;
00371 }
00372 default: {
00373
00374 assert(false);
00375 return false;
00376 }
00377 }
00378
00379 return true;
00380 }
00381
00382 }
00383 }