* MP-friendly version of ppsratecheck(). * * Returns non-negative if we are in the rate, negative otherwise. * 0 - rate limit not reached. * -1 - rate limit reached. * >0 - rate limit was reached before, and was just reset. The return value * is number of events since last reset. */
| 127 | * is number of events since last reset. |
| 128 | */ |
| 129 | int64_t |
| 130 | counter_ratecheck(struct counter_rate *cr, int64_t limit) |
| 131 | { |
| 132 | int64_t val; |
| 133 | int now; |
| 134 | |
| 135 | val = cr->cr_over; |
| 136 | now = ticks; |
| 137 | |
| 138 | if ((u_int)(now - cr->cr_ticks) >= hz) { |
| 139 | /* |
| 140 | * Time to clear the structure, we are in the next second. |
| 141 | * First try unlocked read, and then proceed with atomic. |
| 142 | */ |
| 143 | if ((cr->cr_lock == 0) && |
| 144 | atomic_cmpset_acq_int(&cr->cr_lock, 0, 1)) { |
| 145 | /* |
| 146 | * Check if other thread has just went through the |
| 147 | * reset sequence before us. |
| 148 | */ |
| 149 | if ((u_int)(now - cr->cr_ticks) >= hz) { |
| 150 | val = counter_u64_fetch(cr->cr_rate); |
| 151 | counter_u64_zero(cr->cr_rate); |
| 152 | cr->cr_over = 0; |
| 153 | cr->cr_ticks = now; |
| 154 | if (val <= limit) |
| 155 | val = 0; |
| 156 | } |
| 157 | atomic_store_rel_int(&cr->cr_lock, 0); |
| 158 | } else |
| 159 | /* |
| 160 | * We failed to lock, in this case other thread may |
| 161 | * be running counter_u64_zero(), so it is not safe |
| 162 | * to do an update, we skip it. |
| 163 | */ |
| 164 | return (val); |
| 165 | } |
| 166 | |
| 167 | counter_u64_add(cr->cr_rate, 1); |
| 168 | if (cr->cr_over != 0) |
| 169 | return (-1); |
| 170 | if (counter_u64_fetch(cr->cr_rate) > limit) |
| 171 | val = cr->cr_over = -1; |
| 172 | |
| 173 | return (val); |
| 174 | } |
| 175 | |
| 176 | void |
| 177 | counter_u64_sysinit(void *arg) |
no test coverage detected