Move GLog/GFlags to extern/
[blender.git] / extern / glog / src / vlog_is_on.cc
1 // Copyright (c) 1999, 2007, Google Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
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
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
13 // distribution.
14 //     * Neither the name of Google Inc. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 //
30 // Author: Ray Sidney and many others
31 //
32 // Broken out from logging.cc by Soren Lassen
33 // logging_unittest.cc covers the functionality herein
34
35 #include "utilities.h"
36
37 #include <string.h>
38 #include <stdlib.h>
39 #include <errno.h>
40 #include <cstdio>
41 #include <string>
42 #include "base/commandlineflags.h"
43 #include "glog/logging.h"
44 #include "glog/raw_logging.h"
45 #include "base/googleinit.h"
46
47 // glog doesn't have annotation
48 #define ANNOTATE_BENIGN_RACE(address, description)
49
50 using std::string;
51
52 GLOG_DEFINE_int32(v, 0, "Show all VLOG(m) messages for m <= this."
53 " Overridable by --vmodule.");
54
55 GLOG_DEFINE_string(vmodule, "", "per-module verbose level."
56 " Argument is a comma-separated list of <module name>=<log level>."
57 " <module name> is a glob pattern, matched against the filename base"
58 " (that is, name ignoring .cc/.h./-inl.h)."
59 " <log level> overrides any value given by --v.");
60
61 _START_GOOGLE_NAMESPACE_
62
63 namespace glog_internal_namespace_ {
64
65 // Used by logging_unittests.cc so can't make it static here.
66 GOOGLE_GLOG_DLL_DECL bool SafeFNMatch_(const char* pattern,
67                                        size_t patt_len,
68                                        const char* str,
69                                        size_t str_len);
70
71 // Implementation of fnmatch that does not need 0-termination
72 // of arguments and does not allocate any memory,
73 // but we only support "*" and "?" wildcards, not the "[...]" patterns.
74 // It's not a static function for the unittest.
75 GOOGLE_GLOG_DLL_DECL bool SafeFNMatch_(const char* pattern,
76                                        size_t patt_len,
77                                        const char* str,
78                                        size_t str_len) {
79   size_t p = 0;
80   size_t s = 0;
81   while (1) {
82     if (p == patt_len  &&  s == str_len) return true;
83     if (p == patt_len) return false;
84     if (s == str_len) return p+1 == patt_len  &&  pattern[p] == '*';
85     if (pattern[p] == str[s]  ||  pattern[p] == '?') {
86       p += 1;
87       s += 1;
88       continue;
89     }
90     if (pattern[p] == '*') {
91       if (p+1 == patt_len) return true;
92       do {
93         if (SafeFNMatch_(pattern+(p+1), patt_len-(p+1), str+s, str_len-s)) {
94           return true;
95         }
96         s += 1;
97       } while (s != str_len);
98       return false;
99     }
100     return false;
101   }
102 }
103
104 }  // namespace glog_internal_namespace_
105
106 using glog_internal_namespace_::SafeFNMatch_;
107
108 int32 kLogSiteUninitialized = 1000;
109
110 // List of per-module log levels from FLAGS_vmodule.
111 // Once created each element is never deleted/modified
112 // except for the vlog_level: other threads will read VModuleInfo blobs
113 // w/o locks and we'll store pointers to vlog_level at VLOG locations
114 // that will never go away.
115 // We can't use an STL struct here as we wouldn't know
116 // when it's safe to delete/update it: other threads need to use it w/o locks.
117 struct VModuleInfo {
118   string module_pattern;
119   mutable int32 vlog_level;  // Conceptually this is an AtomicWord, but it's
120                              // too much work to use AtomicWord type here
121                              // w/o much actual benefit.
122   const VModuleInfo* next;
123 };
124
125 // This protects the following global variables.
126 static Mutex vmodule_lock;
127 // Pointer to head of the VModuleInfo list.
128 // It's a map from module pattern to logging level for those module(s).
129 static VModuleInfo* vmodule_list = 0;
130 // Boolean initialization flag.
131 static bool inited_vmodule = false;
132
133 // L >= vmodule_lock.
134 static void VLOG2Initializer() {
135   vmodule_lock.AssertHeld();
136   // Can now parse --vmodule flag and initialize mapping of module-specific
137   // logging levels.
138   inited_vmodule = false;
139   const char* vmodule = FLAGS_vmodule.c_str();
140   const char* sep;
141   VModuleInfo* head = NULL;
142   VModuleInfo* tail = NULL;
143   while ((sep = strchr(vmodule, '=')) != NULL) {
144     string pattern(vmodule, sep - vmodule);
145     int module_level;
146     if (sscanf(sep, "=%d", &module_level) == 1) {
147       VModuleInfo* info = new VModuleInfo;
148       info->module_pattern = pattern;
149       info->vlog_level = module_level;
150       if (head)  tail->next = info;
151       else  head = info;
152       tail = info;
153     }
154     // Skip past this entry
155     vmodule = strchr(sep, ',');
156     if (vmodule == NULL) break;
157     vmodule++;  // Skip past ","
158   }
159   if (head) {  // Put them into the list at the head:
160     tail->next = vmodule_list;
161     vmodule_list = head;
162   }
163   inited_vmodule = true;
164 }
165
166 // This can be called very early, so we use SpinLock and RAW_VLOG here.
167 int SetVLOGLevel(const char* module_pattern, int log_level) {
168   int result = FLAGS_v;
169   int const pattern_len = strlen(module_pattern);
170   bool found = false;
171   {
172     MutexLock l(&vmodule_lock);  // protect whole read-modify-write
173     for (const VModuleInfo* info = vmodule_list;
174          info != NULL; info = info->next) {
175       if (info->module_pattern == module_pattern) {
176         if (!found) {
177           result = info->vlog_level;
178           found = true;
179         }
180         info->vlog_level = log_level;
181       } else if (!found  &&
182                  SafeFNMatch_(info->module_pattern.c_str(),
183                               info->module_pattern.size(),
184                               module_pattern, pattern_len)) {
185         result = info->vlog_level;
186         found = true;
187       }
188     }
189     if (!found) {
190       VModuleInfo* info = new VModuleInfo;
191       info->module_pattern = module_pattern;
192       info->vlog_level = log_level;
193       info->next = vmodule_list;
194       vmodule_list = info;
195     }
196   }
197   RAW_VLOG(1, "Set VLOG level for \"%s\" to %d", module_pattern, log_level);
198   return result;
199 }
200
201 // NOTE: Individual VLOG statements cache the integer log level pointers.
202 // NOTE: This function must not allocate memory or require any locks.
203 bool InitVLOG3__(int32** site_flag, int32* site_default,
204                  const char* fname, int32 verbose_level) {
205   MutexLock l(&vmodule_lock);
206   bool read_vmodule_flag = inited_vmodule;
207   if (!read_vmodule_flag) {
208     VLOG2Initializer();
209   }
210
211   // protect the errno global in case someone writes:
212   // VLOG(..) << "The last error was " << strerror(errno)
213   int old_errno = errno;
214
215   // site_default normally points to FLAGS_v
216   int32* site_flag_value = site_default;
217
218   // Get basename for file
219   const char* base = strrchr(fname, '/');
220   base = base ? (base+1) : fname;
221   const char* base_end = strchr(base, '.');
222   size_t base_length = base_end ? size_t(base_end - base) : strlen(base);
223
224   // Trim out trailing "-inl" if any
225   if (base_length >= 4 && (memcmp(base+base_length-4, "-inl", 4) == 0)) {
226     base_length -= 4;
227   }
228
229   // TODO: Trim out _unittest suffix?  Perhaps it is better to have
230   // the extra control and just leave it there.
231
232   // find target in vector of modules, replace site_flag_value with
233   // a module-specific verbose level, if any.
234   for (const VModuleInfo* info = vmodule_list;
235        info != NULL; info = info->next) {
236     if (SafeFNMatch_(info->module_pattern.c_str(), info->module_pattern.size(),
237                      base, base_length)) {
238       site_flag_value = &info->vlog_level;
239         // value at info->vlog_level is now what controls
240         // the VLOG at the caller site forever
241       break;
242     }
243   }
244
245   // Cache the vlog value pointer if --vmodule flag has been parsed.
246   ANNOTATE_BENIGN_RACE(site_flag,
247                        "*site_flag may be written by several threads,"
248                        " but the value will be the same");
249   if (read_vmodule_flag) *site_flag = site_flag_value;
250
251   // restore the errno in case something recoverable went wrong during
252   // the initialization of the VLOG mechanism (see above note "protect the..")
253   errno = old_errno;
254   return *site_flag_value >= verbose_level;
255 }
256
257 _END_GOOGLE_NAMESPACE_