1 2 /* 3 * Copyright (C) Igor Sysoev 4 * Copyright (C) NGINX, Inc. 5 */ 6 7 #include <nxt_main.h> 8 9 10 static void nxt_log_moderate_timer_handler(nxt_thread_t *thr, void *obj, 11 void *data); 12 13 14 nxt_bool_t 15 nxt_log_moderate_allow(nxt_log_moderation_t *mod) 16 { 17 nxt_uint_t n; 18 nxt_time_t now; 19 nxt_bool_t allow, timer; 20 nxt_thread_t *thr; 21 22 thr = nxt_thread(); 23 now = nxt_thread_time(thr); 24 25 allow = 0; 26 timer = 0; 27 28 nxt_thread_spin_lock(&mod->lock); 29 30 n = mod->count++; 31 32 if (now != mod->last) { 33 34 if (n <= mod->limit) { 35 mod->last = now; 36 mod->count = 1; 37 allow = 1; 38 } 39 40 /* "n > mod->limit" means that timer has already been set. */ 41 42 } else { 43 44 if (n < mod->limit) { 45 allow = 1; 46 47 } else if (n == mod->limit) { 48 /* 49 * There is a race condition on 32-bit many core system 50 * capable to fail an operation 2^32 times per second. 51 * This can be fixed by storing mod->count as uint64_t. 52 */ 53 timer = 1; 54 mod->pid = nxt_pid; 55 } 56 } 57 58 nxt_thread_spin_unlock(&mod->lock); 59 60 if (timer) { 61 mod->timer.work_queue = &thr->work_queue.main; 62 mod->timer.handler = nxt_log_moderate_timer_handler; 63 mod->timer.log = &nxt_main_log; 64 65 nxt_event_timer_add(thr->engine, &mod->timer, 1000); 66 } 67 68 return allow; 69 } 70 71 72 static void 73 nxt_log_moderate_timer_handler(nxt_thread_t *thr, void *obj, void *data) 74 { 75 nxt_bool_t msg; 76 nxt_atomic_uint_t n; 77 nxt_event_timer_t *ev; 78 nxt_log_moderation_t *mod; 79 80 ev = obj; 81 mod = nxt_event_timer_data(ev, nxt_log_moderation_t, timer); 82 83 nxt_thread_spin_lock(&mod->lock); 84 85 mod->last = nxt_thread_time(thr); 86 n = mod->count; 87 mod->count = 0; 88 msg = (mod->pid == nxt_pid); 89 90 nxt_thread_spin_unlock(&mod->lock); 91 92 if (msg) { 93 nxt_log_error(mod->level, &nxt_main_log, "%s %uA times", 94 mod->msg, n - mod->limit); 95 } 96 } 97