#sidebar 
RedisInternalsRedis implements its own event library. The event library is implemented in 
ae.c.
The best way to understand how the Redis event library works is to understand how Redis uses it.
initServer function defined in 
redis.c initializes the numerous fields of the 
redisServer structure variable. One such field is the Redis event loop 
el:
 
aeEventLoop *el 
initServer initializes 
server.el field by calling 
aeCreateEventLoop defined in 
ae.c. The definition of 
aeEventLoop is below:
typedef struct aeEventLoop 
{
    int maxfd;
    long long timeEventNextId;
    aeFileEvent events[AE_SETSIZE]; /* Registered events */
    aeFiredEvent fired[AE_SETSIZE]; /* Fired events */
    aeTimeEvent *timeEventHead;
    int stop;
    void *apidata; /* This is used for polling API specific data */
    aeBeforeSleepProc *beforesleep;
} aeEventLoop;
aeCreateEventLoop first mallocs aeEventLoop structure then calls ae_epoll.c:aeApiCreate
.
aeApiCreate
 mallocs aeApiState
 that has two fields - epfd
 that holds the epoll file descriptor returned by a call from [http://man.cx/epoll_create%282%29 epoll_create] and events
 that is of type struct epoll_event
 define by the Linux epoll library. The use of the events
 field will be  described later.
Next is 'ae.c:aeCreateTimeEvent. But before that 
initServer call 
anet.c:anetTcpServer that creates and returns a 
listening descriptor. The descriptor is listens to 
port 6379 by default. The returned  
listening descriptor is stored in 
server.fd field.
aeCreateTimeEvent accepts the following as parameters:
-  eventLoop: This is server.elin redis.c
-  milliseconds: The number of milliseconds from the curent time after which the timer expires.
-  proc: Function pointer. Stores the address of the function that has to be called after the timer expires.
-  clientData: Mostly NULL.
-  finalizerProc: Pointer to the function that has to be called before the timed event is removed from the list of timed events.
initServer calls 
aeCreateTimeEvent to add a timed event to 
timeEventHead field of 
server.el. 
timeEventHead is a pointer to a list of such timed events. The call to 
aeCreateTimeEvent from 
redis.c:initServer function is given below:
aeCreateTimeEvent(server.el /*eventLoop*/, 1 /*milliseconds*/, serverCron /*proc*/, NULL /*clientData*/, NULL /*finalizerProc*/);
redis.c:serverCron performs many operations that helps keep Redis running properly.
The essence of 
aeCreateFileEvent function is to execute 
epoll_ctl system call which adds a watch for 
EPOLLIN event on the 
listening descriptor create by 
anetTcpServer and associate it with the epoll descriptor created by a call to 
aeCreateEventLoop. 
Following is an explanation of what precisely 
aeCreateFileEvent does when called from 
redis.c:initServer.
initServer passes the following arguments to 
aeCreateFileEvent:
-  server.el: The event loop created by aeCreateEventLoop. The epoll descriptor is got from server.el.
-  server.fd: The listening descriptor that also serves as an index to access the relevant file event structure from the eventLoop->eventstable and store extra information like the callback function.
-  AE_READABLE: Signifies that server.fd has to be watched for EPOLLIN event.
-  acceptHandler: The function that has to be executed when the event being watched for is ready. This function pointer is stored in eventLoop->events[server.fd]->rfileProc.
This completes the initialization of Redis event loop.
ae.c:aeMain called from 
redis.c:main does the job of processing the event loop that is initialized in the previous phase.
ae.c:aeMain calls 
ae.c:aeProcessEvents in a while loop that processes pending time and file events.
ae.c:aeProcessEvents looks for the time event that will be pending in the smallest amount of time by calling 
ae.c:aeSearchNearestTimer on the event loop. In our case there is only one timer event in the event loop that was created by 
ae.c:aeCreateTimeEvent. 
Remember, that timer event created by 
aeCreateTimeEvent has by now probably elapsed because it had a expiry time of one millisecond. Since, the timer has already expired the seconds and microseconds fields of the 
tvp timeval structure variable is initialized to zero. 
The 
tvp structure variable along with the event loop variable is passed to 
ae_epoll.c:aeApiPoll.
aeApiPoll functions does a 
epoll_wait on the epoll descriptor and populates the 
eventLoop->fired table with the details:
-  fd: The descriptor that is now ready to do a read/write operation depending on the mask value. The 
-  mask: The read/write event that can now be performed on the corresponding descriptor.
aeApiPoll returns the number of such file events ready for operation. Now to put things in context, if any client has requested for a connection then aeApiPoll would have noticed it and populated the 
eventLoop->fired table with an entry of the descriptor being the 
listening descriptor and mask being 
AE_READABLE.
Now, 
aeProcessEvents calls the 
redis.c:acceptHandler registered as the callback. 
acceptHandler executes [
http://man.cx/accept(2) accept] on the 
listening descriptor returning a 
connected descriptor with the client. 
redis.c:createClient adds a file event on the 
connected descriptor through a call to 
ae.c:aeCreateFileEvent like below:
    if (aeCreateFileEvent(server.el, c->fd, AE_READABLE,
        readQueryFromClient, c) == AE_ERR) {
        freeClient(c);
        return NULL;
    }
c is the 
redisClient structure variable and 
c->fd is the connected descriptor.
Next the 
ae.c:aeProcessEvent calls 
ae.c:processTimeEventsae.processTimeEvents iterates over list of time events starting at 
eventLoop->timeEventHead.
For every timed event that has elapsed 
processTimeEvents calls the registered callback. In this case it calls the only timed event callback registered, that is, 
redis.c:serverCron. The callback returns the time in milliseconds after which the callback must be called again. This change is recorded via a call to 
ae.c:aeAddMilliSeconds and will be handled on the next iteration of 
ae.c:aeMain while loop.
That's all.