Mark Salyzyn | fc148f7 | 2016-12-14 12:52:50 -0800 | [diff] [blame] | 1 | /* |
| 2 | ** Copyright 2016, The Android Open Source Project |
| 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 | ** http://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 | */ |
| 16 | |
| 17 | #include <errno.h> |
| 18 | #include <pthread.h> |
| 19 | #include <time.h> |
| 20 | |
| 21 | #include <log/log.h> |
| 22 | |
| 23 | #include "log_portability.h" |
| 24 | |
| 25 | // Global default if 'last' argument in __android_log_ratelimit is NULL |
| 26 | static time_t g_last_clock; |
| 27 | // Global above can not deal well with callers playing games with the |
| 28 | // seconds argument, so we will also hold on to the maximum value |
| 29 | // ever provided and use that to gain consistency. If the caller |
| 30 | // provides their own 'last' argument, then they can play such games |
| 31 | // of varying the 'seconds' argument to their pleasure. |
| 32 | static time_t g_last_seconds; |
| 33 | static const time_t last_seconds_default = 10; |
Mark Salyzyn | 2ed51d7 | 2017-03-09 08:09:43 -0800 | [diff] [blame^] | 34 | static const time_t last_seconds_max = 24 * 60 * 60; // maximum of a day |
| 35 | static const time_t last_seconds_min = 2; // granularity |
Mark Salyzyn | fc148f7 | 2016-12-14 12:52:50 -0800 | [diff] [blame] | 36 | // Lock to protect last_clock and last_seconds, but also 'last' |
| 37 | // argument (not NULL) as supplied to __android_log_ratelimit. |
| 38 | static pthread_mutex_t lock_ratelimit = PTHREAD_MUTEX_INITIALIZER; |
| 39 | |
| 40 | // if last is NULL, caller _must_ provide a consistent value for |
| 41 | // seconds, otherwise we will take the maximum ever issued and hold |
| 42 | // on to that. Preserves value of non-zero errno. Return -1 if we |
| 43 | // can not acquire a lock, 0 if we are not to log a message, and 1 |
| 44 | // if we are ok to log a message. Caller should check > 0 for true. |
| 45 | LIBLOG_ABI_PUBLIC int __android_log_ratelimit(time_t seconds, time_t* last) { |
Mark Salyzyn | 2ed51d7 | 2017-03-09 08:09:43 -0800 | [diff] [blame^] | 46 | int save_errno = errno; |
Mark Salyzyn | fc148f7 | 2016-12-14 12:52:50 -0800 | [diff] [blame] | 47 | |
Mark Salyzyn | 2ed51d7 | 2017-03-09 08:09:43 -0800 | [diff] [blame^] | 48 | // Two reasons for trylock failure: |
| 49 | // 1. In a signal handler. Must prevent deadlock |
| 50 | // 2. Too many threads calling __android_log_ratelimit. |
| 51 | // Bonus to not print if they race here because that |
| 52 | // dovetails the goal of ratelimiting. One may print |
| 53 | // and the others will wait their turn ... |
| 54 | if (pthread_mutex_trylock(&lock_ratelimit)) { |
| 55 | if (save_errno) errno = save_errno; |
| 56 | return -1; |
| 57 | } |
Mark Salyzyn | fc148f7 | 2016-12-14 12:52:50 -0800 | [diff] [blame] | 58 | |
Mark Salyzyn | 2ed51d7 | 2017-03-09 08:09:43 -0800 | [diff] [blame^] | 59 | if (seconds == 0) { |
| 60 | seconds = last_seconds_default; |
| 61 | } else if (seconds < last_seconds_min) { |
| 62 | seconds = last_seconds_min; |
| 63 | } else if (seconds > last_seconds_max) { |
| 64 | seconds = last_seconds_max; |
| 65 | } |
Mark Salyzyn | fc148f7 | 2016-12-14 12:52:50 -0800 | [diff] [blame] | 66 | |
Mark Salyzyn | 2ed51d7 | 2017-03-09 08:09:43 -0800 | [diff] [blame^] | 67 | if (!last) { |
| 68 | if (g_last_seconds > seconds) { |
| 69 | seconds = g_last_seconds; |
| 70 | } else if (g_last_seconds < seconds) { |
| 71 | g_last_seconds = seconds; |
Mark Salyzyn | fc148f7 | 2016-12-14 12:52:50 -0800 | [diff] [blame] | 72 | } |
Mark Salyzyn | 2ed51d7 | 2017-03-09 08:09:43 -0800 | [diff] [blame^] | 73 | last = &g_last_clock; |
| 74 | } |
Mark Salyzyn | fc148f7 | 2016-12-14 12:52:50 -0800 | [diff] [blame] | 75 | |
Mark Salyzyn | 2ed51d7 | 2017-03-09 08:09:43 -0800 | [diff] [blame^] | 76 | time_t now = time(NULL); |
| 77 | if ((now == (time_t)-1) || ((*last + seconds) > now)) { |
Mark Salyzyn | fc148f7 | 2016-12-14 12:52:50 -0800 | [diff] [blame] | 78 | pthread_mutex_unlock(&lock_ratelimit); |
| 79 | if (save_errno) errno = save_errno; |
Mark Salyzyn | 2ed51d7 | 2017-03-09 08:09:43 -0800 | [diff] [blame^] | 80 | return 0; |
| 81 | } |
| 82 | *last = now; |
| 83 | pthread_mutex_unlock(&lock_ratelimit); |
| 84 | if (save_errno) errno = save_errno; |
| 85 | return 1; |
Mark Salyzyn | fc148f7 | 2016-12-14 12:52:50 -0800 | [diff] [blame] | 86 | } |