├── .travis.yml ├── LICENSE ├── README.md └── src ├── Makefile ├── t_ttimer.c ├── ttimer.c ├── ttimer.h └── utils.h /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | 3 | compiler: 4 | - gcc 5 | - clang 6 | 7 | dist: bionic 8 | 9 | matrix: 10 | include: 11 | - os: linux 12 | arch: amd64 13 | - os: linux 14 | arch: arm64 15 | - os: linux 16 | arch: ppc64le 17 | 18 | addons: 19 | apt: 20 | update: true 21 | packages: 22 | - build-essential 23 | - libtool 24 | - libtool-bin 25 | 26 | script: 27 | - (cd src && make clean && make tests) 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2016 Mindaugas Rasiukevicius 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 | * SUCH DAMAGE. 25 | */ 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Tick-based timer mechanism 2 | 3 | [![Build Status](https://travis-ci.org/rmind/ttimer.svg?branch=master)](https://travis-ci.org/rmind/ttimer) 4 | 5 | Tick-based timer implemented using the hierarchical timing wheel algorithm. 6 | It has amortised O(1) time complexity for all operations (start/stop/tick). 7 | The implementation is written in C99 and distributed under the 2-clause BSD 8 | license. 9 | 10 | Reference: 11 | 12 | G. Varghese, A. Lauck, Hashed and hierarchical timing wheels: 13 | efficient data structures for implementing a timer facility, 14 | IEEE/ACM Transactions on Networking, Vol. 5, No. 6, Dec 1997 15 | http://www.cs.columbia.edu/~nahum/w6998/papers/ton97-timing-wheels.pdf 16 | 17 | ## API 18 | 19 | * `ttimer_t *ttimer_create(time_t maxtimeout, time_t now)` 20 | * Construct a new timer object. The `maxtimeout` parameter specifies the 21 | maximum timeout value which can be used with this timer. Zero should be 22 | used if there is no limit. However, tuning this value to be as small as 23 | possible would allow the implementation to be more efficient. The `now` 24 | parameter indicates the initial time value, e.g. `time(NULL)`. Returns 25 | the timer object on success and `NULL` on failure. 26 | 27 | * `void ttimer_destroy(ttimer_t *timer)` 28 | * Destroy the timer object. 29 | 30 | * `void ttimer_setfunc(ttimer_ref_t *entry, ttimer_func_t handler, void *arg)` 31 | * Setup the timer entry and set a handler function with an arbitrary 32 | argument. This function will be called on timeout event. The timer entry 33 | structure `ttimer_ref_t` is typically embedded in the object associated 34 | with the timer event. It must be treated as an opaque structure. 35 | * This function should only be called when the timer entry is not 36 | activated i.e. before invoking the `ttimer_start()`. 37 | 38 | * `void ttimer_start(ttimer_t *timer, ttimer_ref_t *entry, time_t timeout)` 39 | * Start the timer for a given entry with a specified `timeout` value. 40 | The handler function must be set with `ttimer_setfunc` before activating 41 | the timer for given entry. 42 | 43 | * `bool ttimer_stop(ttimer_t *timer, ttimer_ref_t *enttry)` 44 | * Stop the timer for the given timer entry. It may also be called if 45 | the timer was not activated. Returns `true` if the entry was activate 46 | (i.e. `ttimer_start()` was invoked) and `false` otherwise. 47 | * Stopping the timer will not reset the handler function set up by the 48 | `ttimer_setfunc()` call. However, after the stop, the handler function 49 | may be changed if needed. 50 | 51 | * `void ttimer_run_ticks(ttimer_t *timer, time_t now)` 52 | * Process all expired events and advance the "current time" up to the 53 | new time, specified by the `now` parameter. Note that the processing 54 | includes any previously missed ticks since the last run. This is the 55 | main "tick" operation which shall occur periodically. 56 | 57 | ## Notes 58 | 59 | The timeout values would typically represent seconds. However, other 60 | time units can be used with the API as long as they can be represented by 61 | the `time_t` type. Internally, the mechanism does not assume UNIX time. 62 | 63 | This is a tick-based mechanism and the accuracy, as well as the granularity, 64 | depends on the tick period. Depending on the use case, for an optimal 65 | tick rate, you might want to consider using the 66 | [Nyquist frequency](https://en.wikipedia.org/wiki/Nyquist_frequency). 67 | -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # This file is in the Public Domain. 3 | # 4 | 5 | SYSNAME:= $(shell uname -s) 6 | SYSARCH:= $(shell uname -m) 7 | 8 | CFLAGS= -std=c99 -O2 -g -W -Wextra -Werror 9 | CFLAGS+= -D_POSIX_C_SOURCE=200809L 10 | CFLAGS+= -D_GNU_SOURCE -D_DEFAULT_SOURCE 11 | 12 | # 13 | # Extended warning flags. 14 | # 15 | CFLAGS+= -Wno-unknown-warning-option # gcc vs clang 16 | 17 | CFLAGS+= -Wstrict-prototypes -Wmissing-prototypes -Wpointer-arith 18 | CFLAGS+= -Wmissing-declarations -Wredundant-decls -Wnested-externs 19 | CFLAGS+= -Wshadow -Wcast-qual -Wcast-align -Wwrite-strings 20 | CFLAGS+= -Wold-style-definition 21 | CFLAGS+= -Wsuggest-attribute=noreturn -Wjump-misses-init 22 | CFLAGS+= -Wduplicated-cond -Wmisleading-indentation -Wnull-dereference 23 | CFLAGS+= -Wduplicated-branches -Wrestrict 24 | 25 | ifeq ($(MAKECMDGOALS),tests) 26 | DEBUG= 1 27 | endif 28 | 29 | ifeq ($(DEBUG),1) 30 | CFLAGS+= -Og -DDEBUG -fno-omit-frame-pointer 31 | ifeq ($(SYSARCH),x86_64) 32 | CFLAGS+= -fsanitize=address -fsanitize=undefined 33 | LDFLAGS+= -fsanitize=address -fsanitize=undefined 34 | endif 35 | else 36 | CFLAGS+= -DNDEBUG 37 | endif 38 | 39 | LIB= libttimer 40 | INCS= ttimer.h 41 | 42 | OBJS= ttimer.o 43 | 44 | $(LIB).la: LDFLAGS+= -rpath $(LIBDIR) 45 | install/%.la: ILIBDIR= $(DESTDIR)/$(LIBDIR) 46 | install: IINCDIR= $(DESTDIR)/$(INCDIR)/ 47 | #install: IMANDIR= $(DESTDIR)/$(MANDIR)/man3/ 48 | 49 | obj: $(OBJS) 50 | 51 | lib: $(LIB).la 52 | 53 | %.lo: %.c 54 | libtool --mode=compile --tag CC $(CC) $(CFLAGS) -c $< 55 | 56 | $(LIB).la: $(shell echo $(OBJS) | sed 's/\.o/\.lo/g') 57 | libtool --mode=link --tag CC $(CC) $(LDFLAGS) -o $@ $(notdir $^) 58 | 59 | install/%.la: %.la 60 | mkdir -p $(ILIBDIR) 61 | libtool --mode=install install -c $(notdir $@) $(ILIBDIR)/$(notdir $@) 62 | 63 | install: $(addprefix install/,$(LIB).la) 64 | libtool --mode=finish $(LIBDIR) 65 | mkdir -p $(IINCDIR) && install -c $(INCS) $(IINCDIR) 66 | #mkdir -p $(IMANDIR) && install -c $(MANS) $(IMANDIR) 67 | 68 | tests: $(OBJS) t_ttimer.o 69 | $(CC) $(CFLAGS) $^ -o t_ttimer 70 | ./t_ttimer 71 | 72 | clean: 73 | libtool --mode=clean rm 74 | rm -rf .libs *.o *.lo *.la t_ttimer 75 | 76 | .PHONY: all obj lib install tests clean 77 | -------------------------------------------------------------------------------- /src/t_ttimer.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Mindaugas Rasiukevicius 3 | * All rights reserved. 4 | * 5 | * Use is subject to license terms, as specified in the LICENSE file. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "ttimer.h" 17 | 18 | static unsigned gotval = 0; 19 | static unsigned setval = 0; 20 | 21 | static void 22 | timeout_handler(ttimer_ref_t *ent, void *arg) 23 | { 24 | gotval = *(unsigned *)arg; 25 | (void)ent; 26 | } 27 | 28 | static ttimer_t * 29 | ttimer_setup(time_t maxtimeout, ttimer_ref_t *ent) 30 | { 31 | ttimer_t *timer; 32 | 33 | /* On timeout: gotval = setval. */ 34 | ttimer_setfunc(ent, timeout_handler, &setval); 35 | timer = ttimer_create(maxtimeout, time(NULL)); 36 | assert(timer); 37 | return timer; 38 | } 39 | 40 | static void 41 | ttimer_basic(void) 42 | { 43 | ttimer_t *timer; 44 | ttimer_ref_t ent; 45 | unsigned steps; 46 | 47 | /* 2 levels, basic test */ 48 | timer = ttimer_setup(512, &ent); 49 | 50 | /* Timer after 1 step ("second"). */ 51 | gotval = 0, setval = 1; 52 | ttimer_start(timer, &ent, 1); 53 | 54 | /* Tick and check. */ 55 | ttimer_tick(timer); 56 | assert(gotval == 1); 57 | assert(!ent.scheduled); 58 | 59 | /* Timer after 255 steps (boundary check). */ 60 | gotval = 0, setval = 2, steps = 255; 61 | ttimer_start(timer, &ent, steps); 62 | for (unsigned i = 0; i < steps ; i++) { 63 | assert(gotval == 0); 64 | assert(ent.scheduled); 65 | ttimer_tick(timer); 66 | } 67 | assert(gotval == 2); 68 | 69 | /* After 256 steps (wrap around check). */ 70 | gotval = 0, setval = 2, steps = 256; 71 | ttimer_start(timer, &ent, steps); 72 | for (unsigned i = 0; i < steps; i++) { 73 | assert(gotval == 0); 74 | ttimer_tick(timer); 75 | } 76 | assert(gotval == 2); 77 | 78 | ttimer_destroy(timer); 79 | } 80 | 81 | static void 82 | ttimer_overflow(void) 83 | { 84 | ttimer_t *timer; 85 | ttimer_ref_t ent; 86 | unsigned steps; 87 | 88 | /* 3 levels, exceeding. */ 89 | timer = ttimer_setup(256UL * 256 * 256 * 256, &ent); 90 | 91 | /* After 256^2 + 17 steps: pass two levels. */ 92 | gotval = 0, setval = 2, steps = 256UL * 256 + 17; 93 | ttimer_start(timer, &ent, steps); 94 | for (unsigned i = 0; i < steps; i++) { 95 | assert(gotval == 0); 96 | ttimer_tick(timer); 97 | } 98 | assert(gotval == 2); 99 | 100 | /* After 256^3 + 19 steps: exceed the maximum size. */ 101 | gotval = 0, setval = 2, steps = (256UL * 256 * 256) + 19; 102 | ttimer_start(timer, &ent, steps); 103 | for (unsigned i = 0; i < steps; i++) { 104 | assert(gotval == 0); 105 | ttimer_tick(timer); 106 | } 107 | assert(gotval == 2); 108 | 109 | ttimer_destroy(timer); 110 | } 111 | 112 | static void 113 | ttimer_random(void) 114 | { 115 | const unsigned maxt = 256 * 256; 116 | ttimer_t *timer; 117 | ttimer_ref_t ent; 118 | unsigned steps; 119 | 120 | timer = ttimer_setup(maxt, &ent); 121 | for (unsigned n = 0; n < 10000; n++) { 122 | gotval = 0, setval = 2, steps = (random() % maxt) + 1; 123 | ttimer_start(timer, &ent, steps); 124 | for (unsigned i = 0; i < steps; i++) { 125 | assert(gotval == 0); 126 | ttimer_tick(timer); 127 | } 128 | assert(gotval == 2); 129 | } 130 | ttimer_destroy(timer); 131 | } 132 | 133 | int 134 | main(void) 135 | { 136 | ttimer_basic(); 137 | ttimer_overflow(); 138 | ttimer_random(); 139 | puts("ok"); 140 | return 0; 141 | } 142 | -------------------------------------------------------------------------------- /src/ttimer.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Mindaugas Rasiukevicius 3 | * All rights reserved. 4 | * 5 | * Use is subject to license terms, as specified in the LICENSE file. 6 | */ 7 | 8 | /* 9 | * Hierarchical timing wheel. An efficient mechanism to implement 10 | * timers with frequent timeouts. The mechanism has amortised O(1) 11 | * complexity for all operations (start/stop/tick). 12 | * 13 | * NOTE: This is a tick-based mechanism and the accuracy, as well 14 | * as the granularity, depends on the tick period. Typically, we 15 | * will use an approximate 1 second tick. 16 | * 17 | * Reference: 18 | * 19 | * G. Varghese, A. Lauck, Hashed and hierarchical timing wheels: 20 | * efficient data structures for implementing a timer facility, 21 | * IEEE/ACM Transactions on Networking, Vol. 5, No. 6, Dec 1997 22 | * 23 | * http://www.cs.columbia.edu/~nahum/w6998/papers/ton97-timing-wheels.pdf 24 | */ 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | #include "ttimer.h" 35 | #include "utils.h" 36 | 37 | /* 38 | * Each timing wheel in the hierarchy will be of equal size: 256 slots. 39 | * It is a convenient number for calculations. Three levels of 256-slot 40 | * wheels is 256^3 = ~194 days. Just cap the maximum level at 3 and let 41 | * the re-calculation happen for the greater values. 42 | */ 43 | 44 | #define WHEEL_BUCKETS (256) 45 | #define WHEEL_MAX_LEVELS (3) 46 | #define DIV_BY_BUCKETS(x) ((x) >> 8) 47 | #define MOD_BY_BUCKETS(x) ((x) & 0xff) 48 | 49 | typedef struct { 50 | unsigned hand; 51 | LIST_HEAD(,ttimer_ref) bucket[WHEEL_BUCKETS]; 52 | } twheel_t; 53 | 54 | struct ttimer { 55 | unsigned levels; 56 | time_t lastrun; 57 | twheel_t wheel[]; 58 | }; 59 | 60 | ttimer_t * 61 | ttimer_create(time_t maxtimeout, time_t now) 62 | { 63 | unsigned len, levels = 0; 64 | ttimer_t *timer; 65 | 66 | while (maxtimeout > 0) { 67 | maxtimeout = DIV_BY_BUCKETS(maxtimeout); 68 | levels++; 69 | } 70 | levels = levels ? MIN(levels, WHEEL_MAX_LEVELS) : WHEEL_MAX_LEVELS; 71 | len = offsetof(ttimer_t, wheel[levels]); 72 | 73 | if ((timer = calloc(1, len)) == NULL) { 74 | return NULL; 75 | } 76 | timer->levels = levels; 77 | timer->lastrun = now; 78 | return timer; 79 | } 80 | 81 | void 82 | ttimer_destroy(ttimer_t *timer) 83 | { 84 | free(timer); 85 | } 86 | 87 | void 88 | ttimer_setfunc(ttimer_ref_t *ent, ttimer_func_t handler, void *arg) 89 | { 90 | ent->scheduled = false; 91 | ent->func = handler; 92 | ent->arg = arg; 93 | } 94 | 95 | void 96 | ttimer_start(ttimer_t *timer, ttimer_ref_t *ent, time_t timeout) 97 | { 98 | unsigned level, r, multiplier; 99 | twheel_t *wheel; 100 | 101 | ASSERT(timeout > 0); 102 | ASSERT(!ent->scheduled); 103 | ASSERT(ent->func != NULL); 104 | 105 | /* 106 | * The algorithm to find the target bucket and the remaining 107 | * time is conceptually the same with the digital clock time. 108 | * 109 | * As an example, let the current time be 22:58:57 i.e. 2 min 110 | * and 3 sec before midnight. Now consider adding 192 seconds 111 | * to it. It would result in 23:02:09. The logic being: 112 | * 113 | * L0 (seconds): (57 + 192) div 60 = 4 rem 9 114 | * L1 (minutes): (58 + 4) div 60 = 1 rem 2 115 | * L2 (hours): (22 + 1) div 24 = 0 rem 23 116 | * 117 | * Hence, the level to insert is L2 (because we reached zero) 118 | * and the bucket to insert is 23 (the remainder). The remaining 119 | * time is a sum of the previous remainders: 9 + (2 * 60) = 129. 120 | * In other words, once the clock will reach 23:00:00, there will 121 | * be 129 seconds remaining until 23:02:09. 122 | * 123 | * Our timing wheel has 256 units, therefore the time before 124 | * "midnight" is 255:255:255 and we divide and modulus by 256. 125 | */ 126 | 127 | level = 0; 128 | ent->remaining = 0; 129 | multiplier = 1; 130 | next: 131 | wheel = &timer->wheel[level]; 132 | r = MOD_BY_BUCKETS(wheel->hand + timeout); 133 | timeout = DIV_BY_BUCKETS(wheel->hand + timeout); 134 | 135 | /* Switch to the next level if time exceeds the level. */ 136 | if (__predict_false(timeout > 0)) { 137 | ent->remaining += (r * multiplier); 138 | multiplier *= WHEEL_BUCKETS; 139 | level++; 140 | 141 | if (__predict_true(level < WHEEL_MAX_LEVELS)) { 142 | goto next; 143 | } 144 | 145 | /* 146 | * If we reach the final level, just add the whole 147 | * remaining time. 148 | */ 149 | ent->remaining += multiplier * (timeout - 1); 150 | level--; 151 | } 152 | 153 | /* 154 | * Insert the entry into the wheel bucket and mark as scheduled. 155 | */ 156 | wheel = &timer->wheel[level]; 157 | LIST_INSERT_HEAD(&wheel->bucket[r], ent, entry); 158 | ent->scheduled = true; 159 | } 160 | 161 | bool 162 | ttimer_stop(ttimer_t *timer, ttimer_ref_t *ent) 163 | { 164 | bool stop = ent->scheduled; 165 | 166 | if (stop) { 167 | LIST_REMOVE(ent, entry); 168 | ent->scheduled = false; 169 | } 170 | (void)timer; 171 | return stop; 172 | } 173 | 174 | /* 175 | * ttimer_tick: process any expired events for the given time value. 176 | */ 177 | void 178 | ttimer_tick(ttimer_t *timer) 179 | { 180 | unsigned ntimeouts = 0, level = 0, n; 181 | ttimer_ref_t *ent; 182 | twheel_t *wheel; 183 | 184 | /* 185 | * Process the first level in the hierarchy. We will process 186 | * the next level if the whole level was processed. 187 | */ 188 | next: 189 | wheel = &timer->wheel[level]; 190 | n = MOD_BY_BUCKETS(wheel->hand + 1); 191 | while ((ent = LIST_FIRST(&wheel->bucket[n])) != NULL) { 192 | time_t remaining = ent->remaining; 193 | 194 | /* 195 | * Remove the timer entry and: 196 | * - If there is remaining time, re-schedule it. 197 | * - Otherwise, run the callback function. 198 | */ 199 | ASSERT(ent->scheduled); 200 | LIST_REMOVE(ent, entry); 201 | ent->scheduled = false; 202 | 203 | if (remaining) { 204 | ttimer_start(timer, ent, remaining); 205 | continue; 206 | } 207 | ASSERT(ent->func != NULL); 208 | ent->func(ent, ent->arg); 209 | ntimeouts++; 210 | } 211 | wheel->hand = n; 212 | 213 | /* 214 | * Completed processing the level? Process the next one. 215 | */ 216 | if (n == 0 && ++level < timer->levels) { 217 | goto next; 218 | } 219 | } 220 | 221 | /* 222 | * ttimer_run_ticks: run the tick for the current time ("now"), 223 | * including any previously missed ticks since the last run. 224 | */ 225 | void 226 | ttimer_run_ticks(ttimer_t *timer, time_t now) 227 | { 228 | while (timer->lastrun < now) { 229 | ttimer_tick(timer); 230 | timer->lastrun++; 231 | } 232 | timer->lastrun = now; 233 | } 234 | -------------------------------------------------------------------------------- /src/ttimer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Mindaugas Rasiukevicius 3 | * All rights reserved. 4 | * 5 | * Use is subject to license terms, as specified in the LICENSE file. 6 | */ 7 | 8 | #ifndef _TTIMER_H_ 9 | #define _TTIMER_H_ 10 | 11 | __BEGIN_DECLS 12 | 13 | struct ttimer_ref; 14 | typedef struct ttimer ttimer_t; 15 | typedef void (*ttimer_func_t)(struct ttimer_ref *, void *); 16 | 17 | typedef struct ttimer_ref { 18 | /* Private members: */ 19 | LIST_ENTRY(ttimer_ref) entry; 20 | time_t remaining; 21 | ttimer_func_t func; 22 | void * arg; 23 | bool scheduled; 24 | } ttimer_ref_t; 25 | 26 | ttimer_t * ttimer_create(time_t, time_t); 27 | void ttimer_destroy(ttimer_t *); 28 | 29 | void ttimer_setfunc(ttimer_ref_t *, ttimer_func_t, void *); 30 | void ttimer_start(ttimer_t *, ttimer_ref_t *, time_t); 31 | bool ttimer_stop(ttimer_t *, ttimer_ref_t *); 32 | void ttimer_run_ticks(ttimer_t *, time_t); 33 | void ttimer_tick(ttimer_t *); 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /src/utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Mindaugas Rasiukevicius 3 | * All rights reserved. 4 | * 5 | * Use is subject to license terms, as specified in the LICENSE file. 6 | */ 7 | 8 | #ifndef _UTILS_H_ 9 | #define _UTILS_H_ 10 | 11 | #include 12 | 13 | /* 14 | * A regular assert (debug/diagnostic only). 15 | */ 16 | #if defined(DEBUG) 17 | #define ASSERT assert 18 | #else 19 | #define ASSERT(x) 20 | #endif 21 | 22 | /* 23 | * Minimum/maximum macros. 24 | */ 25 | 26 | #ifndef MIN 27 | #define MIN(x, y) ((x) < (y) ? (x) : (y)) 28 | #endif 29 | 30 | #ifndef MAX 31 | #define MAX(x, y) ((x) > (y) ? (x) : (y)) 32 | #endif 33 | 34 | /* 35 | * Branch prediction macros. 36 | */ 37 | #ifndef __predict_true 38 | #define __predict_true(x) __builtin_expect((x) != 0, 1) 39 | #define __predict_false(x) __builtin_expect((x) != 0, 0) 40 | #endif 41 | 42 | #endif 43 | --------------------------------------------------------------------------------