mirror of
https://codeberg.org/redict/redict.git
synced 2025-01-22 16:18:28 -05:00
c01e94a431
Update adds a general source for retrieving a monotonic time. In addition, AE has been updated to utilize the new monotonic clock for timer processing. This performance improvement is **not** enabled in a default build due to various H/W compatibility concerns, see README.md for details. It does however change the default use of gettimeofday with clock_gettime and somewhat improves performance. This update provides the following 1. An interface for retrieving a monotonic clock. getMonotonicUs returns a uint64_t (aka monotime) with the number of micro-seconds from an arbitrary point. No more messing with tv_sec/tv_usec. Simple routines are provided for measuring elapsed milli-seconds or elapsed micro-seconds (the most common use case for a monotonic timer). No worries about time moving backwards. 2. High-speed assembler implementation for x86 and ARM. The standard method for retrieving the monotonic clock is POSIX.1b (1993): clock_gettime(CLOCK_MONOTONIC, timespec*). However, most modern processors provide a constant speed instruction clock which can be retrieved in a fraction of the time that it takes to call clock_gettime. For x86, this is provided by the RDTSC instruction. For ARM, this is provided by the CNTVCT_EL0 instruction. As a compile-time option, these high-speed timers can be chosen. (Default is POSIX clock_gettime.) 3. Refactor of event loop timers. The timer processing in ae.c has been refactored to use the new monotonic clock interface. This results in simpler/cleaner logic and improved performance.
136 lines
5.3 KiB
C
136 lines
5.3 KiB
C
/* A simple event-driven programming library. Originally I wrote this code
|
|
* for the Jim's event-loop (Jim is a Tcl interpreter) but later translated
|
|
* it in form of a library for easy reuse.
|
|
*
|
|
* Copyright (c) 2006-2012, Salvatore Sanfilippo <antirez at gmail dot com>
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
*
|
|
* * Redistributions of source code must retain the above copyright notice,
|
|
* this list of conditions and the following disclaimer.
|
|
* * Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* * Neither the name of Redis nor the names of its contributors may be used
|
|
* to endorse or promote products derived from this software without
|
|
* specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#ifndef __AE_H__
|
|
#define __AE_H__
|
|
|
|
#include "monotonic.h"
|
|
|
|
#define AE_OK 0
|
|
#define AE_ERR -1
|
|
|
|
#define AE_NONE 0 /* No events registered. */
|
|
#define AE_READABLE 1 /* Fire when descriptor is readable. */
|
|
#define AE_WRITABLE 2 /* Fire when descriptor is writable. */
|
|
#define AE_BARRIER 4 /* With WRITABLE, never fire the event if the
|
|
READABLE event already fired in the same event
|
|
loop iteration. Useful when you want to persist
|
|
things to disk before sending replies, and want
|
|
to do that in a group fashion. */
|
|
|
|
#define AE_FILE_EVENTS (1<<0)
|
|
#define AE_TIME_EVENTS (1<<1)
|
|
#define AE_ALL_EVENTS (AE_FILE_EVENTS|AE_TIME_EVENTS)
|
|
#define AE_DONT_WAIT (1<<2)
|
|
#define AE_CALL_BEFORE_SLEEP (1<<3)
|
|
#define AE_CALL_AFTER_SLEEP (1<<4)
|
|
|
|
#define AE_NOMORE -1
|
|
#define AE_DELETED_EVENT_ID -1
|
|
|
|
/* Macros */
|
|
#define AE_NOTUSED(V) ((void) V)
|
|
|
|
struct aeEventLoop;
|
|
|
|
/* Types and data structures */
|
|
typedef void aeFileProc(struct aeEventLoop *eventLoop, int fd, void *clientData, int mask);
|
|
typedef int aeTimeProc(struct aeEventLoop *eventLoop, long long id, void *clientData);
|
|
typedef void aeEventFinalizerProc(struct aeEventLoop *eventLoop, void *clientData);
|
|
typedef void aeBeforeSleepProc(struct aeEventLoop *eventLoop);
|
|
|
|
/* File event structure */
|
|
typedef struct aeFileEvent {
|
|
int mask; /* one of AE_(READABLE|WRITABLE|BARRIER) */
|
|
aeFileProc *rfileProc;
|
|
aeFileProc *wfileProc;
|
|
void *clientData;
|
|
} aeFileEvent;
|
|
|
|
/* Time event structure */
|
|
typedef struct aeTimeEvent {
|
|
long long id; /* time event identifier. */
|
|
monotime when;
|
|
aeTimeProc *timeProc;
|
|
aeEventFinalizerProc *finalizerProc;
|
|
void *clientData;
|
|
struct aeTimeEvent *prev;
|
|
struct aeTimeEvent *next;
|
|
int refcount; /* refcount to prevent timer events from being
|
|
* freed in recursive time event calls. */
|
|
} aeTimeEvent;
|
|
|
|
/* A fired event */
|
|
typedef struct aeFiredEvent {
|
|
int fd;
|
|
int mask;
|
|
} aeFiredEvent;
|
|
|
|
/* State of an event based program */
|
|
typedef struct aeEventLoop {
|
|
int maxfd; /* highest file descriptor currently registered */
|
|
int setsize; /* max number of file descriptors tracked */
|
|
long long timeEventNextId;
|
|
aeFileEvent *events; /* Registered events */
|
|
aeFiredEvent *fired; /* Fired events */
|
|
aeTimeEvent *timeEventHead;
|
|
int stop;
|
|
void *apidata; /* This is used for polling API specific data */
|
|
aeBeforeSleepProc *beforesleep;
|
|
aeBeforeSleepProc *aftersleep;
|
|
int flags;
|
|
} aeEventLoop;
|
|
|
|
/* Prototypes */
|
|
aeEventLoop *aeCreateEventLoop(int setsize);
|
|
void aeDeleteEventLoop(aeEventLoop *eventLoop);
|
|
void aeStop(aeEventLoop *eventLoop);
|
|
int aeCreateFileEvent(aeEventLoop *eventLoop, int fd, int mask,
|
|
aeFileProc *proc, void *clientData);
|
|
void aeDeleteFileEvent(aeEventLoop *eventLoop, int fd, int mask);
|
|
int aeGetFileEvents(aeEventLoop *eventLoop, int fd);
|
|
long long aeCreateTimeEvent(aeEventLoop *eventLoop, long long milliseconds,
|
|
aeTimeProc *proc, void *clientData,
|
|
aeEventFinalizerProc *finalizerProc);
|
|
int aeDeleteTimeEvent(aeEventLoop *eventLoop, long long id);
|
|
int aeProcessEvents(aeEventLoop *eventLoop, int flags);
|
|
int aeWait(int fd, int mask, long long milliseconds);
|
|
void aeMain(aeEventLoop *eventLoop);
|
|
char *aeGetApiName(void);
|
|
void aeSetBeforeSleepProc(aeEventLoop *eventLoop, aeBeforeSleepProc *beforesleep);
|
|
void aeSetAfterSleepProc(aeEventLoop *eventLoop, aeBeforeSleepProc *aftersleep);
|
|
int aeGetSetSize(aeEventLoop *eventLoop);
|
|
int aeResizeSetSize(aeEventLoop *eventLoop, int setsize);
|
|
void aeSetDontWait(aeEventLoop *eventLoop, int noWait);
|
|
|
|
#endif
|