/src/rt/rust_log.cpp

http://github.com/jruderman/rust · C++ · 332 lines · 250 code · 40 blank · 42 comment · 50 complexity · a27ae3830b5a3df11dc27b22092c3b57 MD5 · raw file

  1. /*
  2. * Logging infrastructure that aims to support multi-threading
  3. */
  4. #include "rust_log.h"
  5. #include "util/array_list.h"
  6. #include "rust_util.h"
  7. #include "rust_task.h"
  8. /**
  9. * Synchronizes access to the underlying logging mechanism.
  10. */
  11. static lock_and_signal _log_lock;
  12. /**
  13. * Indicates whether we are outputing to the console.
  14. * Protected by _log_lock;
  15. */
  16. static bool _log_to_console = true;
  17. /*
  18. * Request that console logging be turned on.
  19. */
  20. void
  21. log_console_on() {
  22. scoped_lock with(_log_lock);
  23. _log_to_console = true;
  24. }
  25. /*
  26. * Request that console logging be turned off. Can be
  27. * overridden by the environment.
  28. */
  29. void
  30. log_console_off(rust_env *env) {
  31. scoped_lock with(_log_lock);
  32. if (env->logspec == NULL) {
  33. _log_to_console = false;
  34. }
  35. }
  36. rust_log::rust_log(rust_sched_loop *sched_loop) :
  37. _sched_loop(sched_loop) {
  38. }
  39. rust_log::~rust_log() {
  40. }
  41. const uint16_t
  42. hash(uintptr_t ptr) {
  43. # if(ULONG_MAX == 0xFFFFFFFF)
  44. // Robert Jenkins' 32 bit integer hash function
  45. ptr = (ptr + 0x7ed55d16) + (ptr << 12);
  46. ptr = (ptr ^ 0xc761c23c) ^ (ptr >> 19);
  47. ptr = (ptr + 0x165667b1) + (ptr << 5);
  48. ptr = (ptr + 0xd3a2646c) ^ (ptr << 9);
  49. ptr = (ptr + 0xfd7046c5) + (ptr << 3);
  50. ptr = (ptr ^ 0xb55a4f09) ^ (ptr >> 16);
  51. # elif(ULONG_MAX == 0xFFFFFFFFFFFFFFFF)
  52. // "hash64shift()" from http://www.concentric.net/~Ttwang/tech/inthash.htm
  53. ptr = (~ptr) + (ptr << 21); // ptr = (ptr << 21) - ptr - 1;
  54. ptr = ptr ^ (ptr >> 24);
  55. ptr = (ptr + (ptr << 3)) + (ptr << 8); // ptr * 265
  56. ptr = ptr ^ (ptr >> 14);
  57. ptr = (ptr + (ptr << 2)) + (ptr << 4); // ptr * 21
  58. ptr = ptr ^ (ptr >> 28);
  59. ptr = ptr + (ptr << 31);
  60. # else
  61. # error "hash() not defined for this pointer size"
  62. # endif
  63. return (uint16_t) ptr;
  64. }
  65. char *
  66. copy_string(char *dst, const char *src, size_t length) {
  67. return strncpy(dst, src, length) + length;
  68. }
  69. char *
  70. append_string(char *buffer, const char *format, ...) {
  71. if (buffer != NULL && format) {
  72. va_list args;
  73. va_start(args, format);
  74. size_t off = strlen(buffer);
  75. vsnprintf(buffer + off, BUF_BYTES - off, format, args);
  76. va_end(args);
  77. }
  78. return buffer;
  79. }
  80. void
  81. rust_log::log(rust_task* task, uint32_t level, char const *fmt, ...) {
  82. char buf[BUF_BYTES];
  83. va_list args;
  84. va_start(args, fmt);
  85. int formattedbytes = vsnprintf(buf, sizeof(buf), fmt, args);
  86. if( formattedbytes and (unsigned)formattedbytes > BUF_BYTES ){
  87. const char truncatedstr[] = "[...]";
  88. memcpy( &buf[BUF_BYTES-sizeof(truncatedstr)],
  89. truncatedstr,
  90. sizeof(truncatedstr));
  91. }
  92. trace_ln(task, level, buf);
  93. va_end(args);
  94. }
  95. void
  96. rust_log::trace_ln(char *prefix, char *message) {
  97. char buffer[BUF_BYTES] = "";
  98. _log_lock.lock();
  99. append_string(buffer, "%s", prefix);
  100. append_string(buffer, "%s", message);
  101. if (_log_to_console) {
  102. fprintf(stderr, "rust: %s\n", buffer);
  103. fflush(stderr);
  104. }
  105. _log_lock.unlock();
  106. }
  107. void
  108. rust_log::trace_ln(rust_task *task, uint32_t level, char *message) {
  109. if (task) {
  110. // There is not enough room to be logging on the rust stack
  111. assert(!task->on_rust_stack() && "logging on rust stack");
  112. }
  113. // FIXME (#2672): The scheduler and task names used to have meaning,
  114. // but they are always equal to 'main' currently
  115. #if 0
  116. #if defined(__WIN32__)
  117. uint32_t thread_id = 0;
  118. #else
  119. uint32_t thread_id = hash((uintptr_t) pthread_self());
  120. #endif
  121. char prefix[BUF_BYTES] = "";
  122. if (_sched_loop && _sched_loop-.name) {
  123. append_string(prefix, "%04" PRIxPTR ":%.10s:",
  124. thread_id, _sched_loop->name);
  125. } else {
  126. append_string(prefix, "%04" PRIxPTR ":0x%08" PRIxPTR ":",
  127. thread_id, (uintptr_t) _sched_loop);
  128. }
  129. if (task) {
  130. if (task->name) {
  131. append_string(prefix, "%.10s:", task->name);
  132. } else {
  133. append_string(prefix, "0x%08" PRIxPTR ":", (uintptr_t) task);
  134. }
  135. }
  136. #else
  137. char prefix[BUF_BYTES] = "";
  138. #endif
  139. trace_ln(prefix, message);
  140. }
  141. // Reading log directives and setting log level vars
  142. struct mod_entry {
  143. const char* name;
  144. uint32_t* state;
  145. };
  146. struct cratemap {
  147. const mod_entry* entries;
  148. const cratemap* children[1];
  149. };
  150. struct log_directive {
  151. char* name;
  152. size_t level;
  153. };
  154. const size_t max_log_directives = 255;
  155. const size_t max_log_level = 255;
  156. const size_t default_log_level = 0;
  157. // This is a rather ugly parser for strings in the form
  158. // "crate1,crate2.mod3,crate3.x=1". Log levels are 0-255,
  159. // with the most likely ones being 0-3 (defined in core::).
  160. size_t parse_logging_spec(char* spec, log_directive* dirs) {
  161. size_t dir = 0;
  162. while (dir < max_log_directives && *spec) {
  163. char* start = spec;
  164. char cur;
  165. while (true) {
  166. cur = *spec;
  167. if (cur == ',' || cur == '=' || cur == '\0') {
  168. if (start == spec) {spec++; break;}
  169. if (*spec != '\0') {
  170. *spec = '\0';
  171. spec++;
  172. }
  173. size_t level = max_log_level;
  174. if (cur == '=' && *spec != '\0') {
  175. level = *spec - '0';
  176. if (level > max_log_level) level = max_log_level;
  177. if (*spec) ++spec;
  178. }
  179. dirs[dir].name = start;
  180. dirs[dir++].level = level;
  181. break;
  182. } else {
  183. spec++;
  184. }
  185. }
  186. }
  187. return dir;
  188. }
  189. void update_module_map(const mod_entry* map, log_directive* dirs,
  190. size_t n_dirs, size_t *n_matches) {
  191. for (const mod_entry* cur = map; cur->name; cur++) {
  192. size_t level = default_log_level, longest_match = 0;
  193. for (size_t d = 0; d < n_dirs; d++) {
  194. if (strstr(cur->name, dirs[d].name) == cur->name &&
  195. strlen(dirs[d].name) > longest_match) {
  196. longest_match = strlen(dirs[d].name);
  197. level = dirs[d].level;
  198. }
  199. }
  200. *cur->state = level;
  201. (*n_matches)++;
  202. }
  203. }
  204. void update_crate_map(const cratemap* map, log_directive* dirs,
  205. size_t n_dirs, size_t *n_matches) {
  206. // First update log levels for this crate
  207. update_module_map(map->entries, dirs, n_dirs, n_matches);
  208. // Then recurse on linked crates
  209. // FIXME (#2673) this does double work in diamond-shaped deps. could
  210. // keep a set of visited addresses, if it turns out to be actually
  211. // slow
  212. for (size_t i = 0; map->children[i]; i++) {
  213. update_crate_map(map->children[i], dirs, n_dirs, n_matches);
  214. }
  215. }
  216. void print_crate_log_map(const cratemap* map) {
  217. for (const mod_entry* cur = map->entries; cur->name; cur++) {
  218. printf(" %s\n", cur->name);
  219. }
  220. for (size_t i = 0; map->children[i]; i++) {
  221. print_crate_log_map(map->children[i]);
  222. }
  223. }
  224. // These are pseudo-modules used to control logging in the runtime.
  225. uint32_t log_rt_mem;
  226. uint32_t log_rt_box;
  227. uint32_t log_rt_comm;
  228. uint32_t log_rt_task;
  229. uint32_t log_rt_dom;
  230. uint32_t log_rt_trace;
  231. uint32_t log_rt_cache;
  232. uint32_t log_rt_upcall;
  233. uint32_t log_rt_timer;
  234. uint32_t log_rt_gc;
  235. uint32_t log_rt_stdlib;
  236. uint32_t log_rt_kern;
  237. uint32_t log_rt_backtrace;
  238. uint32_t log_rt_callback;
  239. static const mod_entry _rt_module_map[] =
  240. {{"::rt::mem", &log_rt_mem},
  241. {"::rt::box", &log_rt_box},
  242. {"::rt::comm", &log_rt_comm},
  243. {"::rt::task", &log_rt_task},
  244. {"::rt::dom", &log_rt_dom},
  245. {"::rt::trace", &log_rt_trace},
  246. {"::rt::cache", &log_rt_cache},
  247. {"::rt::upcall", &log_rt_upcall},
  248. {"::rt::timer", &log_rt_timer},
  249. {"::rt::gc", &log_rt_gc},
  250. {"::rt::stdlib", &log_rt_stdlib},
  251. {"::rt::kern", &log_rt_kern},
  252. {"::rt::backtrace", &log_rt_backtrace},
  253. {"::rt::callback", &log_rt_callback},
  254. {NULL, NULL}};
  255. void update_log_settings(void* crate_map, char* settings) {
  256. char* buffer = NULL;
  257. log_directive dirs[256];
  258. size_t n_dirs = 0;
  259. if (settings) {
  260. if (strcmp(settings, "::help") == 0 ||
  261. strcmp(settings, "?") == 0) {
  262. printf("\nCrate log map:\n\n");
  263. print_crate_log_map((const cratemap*)crate_map);
  264. printf("\n");
  265. exit(1);
  266. }
  267. size_t buflen = strlen(settings) + 1;
  268. buffer = (char*)malloc(buflen);
  269. strncpy(buffer, settings, buflen);
  270. n_dirs = parse_logging_spec(buffer, &dirs[0]);
  271. }
  272. size_t n_matches = 0;
  273. update_module_map(_rt_module_map, &dirs[0], n_dirs, &n_matches);
  274. update_crate_map((const cratemap*)crate_map, &dirs[0],
  275. n_dirs, &n_matches);
  276. if (n_matches < n_dirs) {
  277. printf("warning: got %" PRIdPTR " RUST_LOG specs, "
  278. "enabled %" PRIdPTR " flags.",
  279. (uintptr_t)n_dirs, (uintptr_t)n_matches);
  280. }
  281. free(buffer);
  282. }
  283. //
  284. // Local Variables:
  285. // mode: C++
  286. // fill-column: 78;
  287. // indent-tabs-mode: nil
  288. // c-basic-offset: 4
  289. // buffer-file-coding-system: utf-8-unix
  290. // compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
  291. // End:
  292. //