| /* | 
 | ** Copyright 2016, The Android Open Source Project | 
 | ** | 
 | ** Licensed under the Apache License, Version 2.0 (the "License"); | 
 | ** you may not use this file except in compliance with the License. | 
 | ** You may obtain a copy of the License at | 
 | ** | 
 | **     http://www.apache.org/licenses/LICENSE-2.0 | 
 | ** | 
 | ** Unless required by applicable law or agreed to in writing, software | 
 | ** distributed under the License is distributed on an "AS IS" BASIS, | 
 | ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 | ** See the License for the specific language governing permissions and | 
 | ** limitations under the License. | 
 | */ | 
 |  | 
 | #include <errno.h> | 
 | #include <pthread.h> | 
 | #include <time.h> | 
 |  | 
 | #include <log/log.h> | 
 |  | 
 | #include "log_portability.h" | 
 |  | 
 | // Global default if 'last' argument in __android_log_ratelimit is NULL | 
 | static time_t g_last_clock; | 
 | // Global above can not deal well with callers playing games with the | 
 | // seconds argument, so we will also hold on to the maximum value | 
 | // ever provided and use that to gain consistency.  If the caller | 
 | // provides their own 'last' argument, then they can play such games | 
 | // of varying the 'seconds' argument to their pleasure. | 
 | static time_t g_last_seconds; | 
 | static const time_t last_seconds_default = 10; | 
 | static const time_t last_seconds_max = 24 * 60 * 60;  // maximum of a day | 
 | static const time_t last_seconds_min = 2;             // granularity | 
 | // Lock to protect last_clock and last_seconds, but also 'last' | 
 | // argument (not NULL) as supplied to __android_log_ratelimit. | 
 | static pthread_mutex_t lock_ratelimit = PTHREAD_MUTEX_INITIALIZER; | 
 |  | 
 | // if last is NULL, caller _must_ provide a consistent value for | 
 | // seconds, otherwise we will take the maximum ever issued and hold | 
 | // on to that.  Preserves value of non-zero errno.  Return -1 if we | 
 | // can not acquire a lock, 0 if we are not to log a message, and 1 | 
 | // if we are ok to log a message.  Caller should check > 0 for true. | 
 | LIBLOG_ABI_PUBLIC int __android_log_ratelimit(time_t seconds, time_t* last) { | 
 |   int save_errno = errno; | 
 |  | 
 |   // Two reasons for trylock failure: | 
 |   //   1. In a signal handler. Must prevent deadlock | 
 |   //   2. Too many threads calling __android_log_ratelimit. | 
 |   //      Bonus to not print if they race here because that | 
 |   //      dovetails the goal of ratelimiting. One may print | 
 |   //      and the others will wait their turn ... | 
 |   if (pthread_mutex_trylock(&lock_ratelimit)) { | 
 |     if (save_errno) errno = save_errno; | 
 |     return -1; | 
 |   } | 
 |  | 
 |   if (seconds == 0) { | 
 |     seconds = last_seconds_default; | 
 |   } else if (seconds < last_seconds_min) { | 
 |     seconds = last_seconds_min; | 
 |   } else if (seconds > last_seconds_max) { | 
 |     seconds = last_seconds_max; | 
 |   } | 
 |  | 
 |   if (!last) { | 
 |     if (g_last_seconds > seconds) { | 
 |       seconds = g_last_seconds; | 
 |     } else if (g_last_seconds < seconds) { | 
 |       g_last_seconds = seconds; | 
 |     } | 
 |     last = &g_last_clock; | 
 |   } | 
 |  | 
 |   time_t now = time(NULL); | 
 |   if ((now == (time_t)-1) || ((*last + seconds) > now)) { | 
 |     pthread_mutex_unlock(&lock_ratelimit); | 
 |     if (save_errno) errno = save_errno; | 
 |     return 0; | 
 |   } | 
 |   *last = now; | 
 |   pthread_mutex_unlock(&lock_ratelimit); | 
 |   if (save_errno) errno = save_errno; | 
 |   return 1; | 
 | } |