Skip to content

Conversation

@tczz88888
Copy link

The core goal of this code change is to introduce the high-performance epoll IO event-driven mechanism, refactor the channel event management logic, achieve high efficiency and stability in server-side IO event processing, and complete the adaptation of all components to the new mechanism.

1. Header File Changes (lib.channel.h, lsf.h, lim.h)

1.1 lib.channel.h: Interface Definition for Channel and epoll Mechanism

(1) New Event Type Enumeration

Define the standardized channel ready event enumeration epoll_events_t to achieve unified management of event states

(2) Structure Field Extension

struct chanData: Add the listenEvents (recording the listening event mask registered by the channel in epoll) and readyEvents (marking the current ready event status of the channel) fields to realize decoupled management of listening events and ready states.

(3) New Error Code

Add the CHANE_EPOLLFAIL error code (value 12) to specifically identify the execution failure of epoll-related system calls.

(4) Core Function Declarations

  • epoll Environment Initialization and Destruction:

    • chanEpollInit(): Initialize the epoll instance, event array and channel status, which must be called before creating listening sockets.

    • chanCloseEpoll(): Close the epoll file descriptor and reset the running state to avoid resource conflicts between processes.

  • epoll Event Loop: chanEpoll_(int **, struct timeval *timeout): Implement epoll event monitoring and ready channel filtering, return the number of ready channels and output the channel index array.

  • Channel Event Registration and Update:

    • chanRegisterEpoll_(int, uint32_t): Register the channel to epoll and bind listening events.

    • chanUpdateListenEvents(int, uint32_t): Dynamically update the epoll listening event mask of the channel.

    • chanUnRegisterEpoll_(int): Deregister the channel from epoll and clean up invalid listening.

  • Ready Event Query and Management:

    • chanEventsReady(int chfd, int events): Verify whether the specified channel has target ready events.

    • chanQuitReadyEvents(int chfd, int events): Clear the specified ready event status of the channel.

  • Data Enqueue Interface Adjustment: chanEnqueue_(int chfd, struct Buffer *buf, int needUpdateEvent) adds the needUpdateEvent parameter to control whether to trigger dynamic registration of epoll write events after data enqueuing.

1.2 lsf.h: Basic Dependency Supplement

Include the <sys/epoll.h> header file to provide interface support for epoll-related system calls and ensure compilation compatibility.

1.3 lim.h: LIM Service Interface Adaptation

Adjust the clientIO function signature to void clientIO(int *, int), with parameters being the ready channel index array and the number of channels, adapting to the event traversal logic under the epoll mechanism.

2. Source File Changes (lib.channel.c, mbd.main.c, sbd.main.c, lim.main.c, etc.)

2.1 lib.channel.c: Core Implementation of the epoll Mechanism

(1) Global Resources and Initialization

  • Add global variables such as epollfd (epoll instance file descriptor), epoll_events (epoll event array), readyChans (ready channel index array), and chanEpollListenEventUpdateOn (epoll function switch) to realize global management of epoll resources.

  • Implement the chanEpollInit function: Create an epoll instance through epoll_create1(EPOLL_CLOEXEC), allocate event array memory, initialize the listenEvents and readyEvents states of all channels, and enable the epoll function switch.

(2) epoll Event Loop Logic

Implement the chanEpoll_ function to complete event monitoring, ready state conversion and ready channel filtering:

  1. Clear historical ready events through chanClearReadyEvents before calling to avoid state residue;

  2. Call epoll_wait to obtain ready events and convert system events into the readyEvents state of the channel;

  3. Automatically trigger doreadEpoll/dowriteEpoll for channels with buffers to complete data reading and writing;

  4. Filter out ready channels that need upper-layer processing, fill the readyChans array and return the number of channels.

(3) Channel Event Registration and Management

  • chanRegisterEpoll_: Called in scenarios such as chanServSocket_ (listening socket creation) and chanOpenSock_ (connected socket encapsulation), register the channel socket to epoll through epoll_ctl(EPOLL_CTL_ADD) and bind the channel index.

  • chanUpdateListenEvents: Called in scenarios such as chanEnqueue_ (needing to monitor write events after data enqueuing) and dowriteEpoll (canceling write events after sending is completed), dynamically update the listening event mask through epoll_ctl(EPOLL_CTL_MOD).

  • chanUnRegisterEpoll_: Called in the chanClose_ (channel closing) scenario, deregister the channel from epoll through epoll_ctl(EPOLL_CTL_DEL) and clean up invalid listening.

(4) Socket Read/Write Logic Adaptation

  • doreadEpoll: Implement socket read logic based on epoll, complete buffer allocation, protocol header parsing, data reception and buffer expansion, and mark the channel read-ready state after data reception is completed.

  • dowriteEpoll: Implement socket write logic based on epoll, complete data sending, automatically cancel write event monitoring according to the buffer state after sending.

(5) Channel Status and Resource Cleanup Optimization

  • CLOSEIT macro enhancement: Reset the channel readyEvents state synchronously when closing the socket to ensure a clean channel state.

  • chanClose_ function extension: Automatically deregister the channel from epoll when closing the channel to avoid invalid resource occupation.

2.2 mbd.main.c and sbd.main.c: Server Main Process Adaptation

(1) Initialization Process Enhancement

In the business initialization phase of the main function main (before minit/sinit), add a call to chanEpollInit() to complete the pre-initialization of the epoll environment.

(2) Event Loop Reconstruction

  • Remove variables related to the old event mechanism such as fd_set and struct Masks, and replace them with chanEpoll_ calls to obtain the ready channel array;

(3) clientIO Function Adaptation

  • Simplify the function signature to the parameterless form clientIO(), no longer relying on event mask parameter passing;

  • Event judgment logic: Use chanEventsReady instead of FD_ISSET to judge the channel ready state, exception events (EPOLL_EVENTS_ERROR) trigger client connection closing, and read events (EPOLL_EVENTS_READ) trigger request processing;

  • Call chanQuitReadyEvents to clear the read-ready state after read event processing to avoid repeated processing.

2.3 lim.main.c and lim.cluster.c: LIM Service Adaptation

(1) Event Acquisition in the Main Loop

Remove variables related to struct Masks, obtain the readyChans ready channel array through chanEpoll_, replacing the traditional event mask mechanism.

(2) clientIO Function Logic Adjustment

  • Receive the readyChans array and the number of ready channels as parameters, traverse ready channels instead of all channels to improve processing efficiency;

  • Judge the channel event state through chanEventsReady, exception events trigger shutDownChan to clean up the channel, and read events trigger processMsg to process requests.

(3) Parent-Child Process Resource Isolation

After forking a child process (such as a request processing child process), call chanCloseEpoll() to close the inherited epoll file descriptor to prevent epoll operations of the child process from affecting the parent process's listening logic.

@qinan-cn
Copy link
Collaborator

review意见,供参看

  1. chanEpollInit 在minit/sinit() 这前,对吗??
    chanEpollInit()位置在minit()中是不是更合适,而不是之前?
    是不是应该在minit()->chanInit_() 之后?chanMaxSize赋值在chanInit_(),但是chanEpollInit()有使用。

  2. 命名:epoll_events_t 是不是去掉s更符合实际意义
    typedef enum {
    EPOLL_EVENTS_NONE = 0,
    EPOLL_EVENTS_READ = 1,
    EPOLL_EVENTS_WRITE = 2,
    EPOLL_EVENTS_ERROR = 4
    } epoll_events_t;

bit mask可考虑#define xxxx 0x1

struct chanData {
int handle;
enum chanType type;
enum chanState state;
enum chanState prestate;
int chanerr;
struct Buffer *send;
struct Buffer *recv;

int listenEvents;
epoll_events_t readyEvents;                /*Ready events reported by the channel to the upper layer*/

};
listenEvents 好像没啥用??

  1. chanMaxSize = sysconf(_SC_OPEN_MAX);
    sysconf(_SC_OPEN_MAX) = 65535
    RLIMIT_NOFILE 软限制:65535
    RLIMIT_NOFILE 硬限制:65535

会不会太大了?? 1024/2048??

  1. chanEpollListenEventUpdateOn 变量啥用??
  2. readyChansNum: 名字命名和意思不够贴合: epoll 中有event不代表 chan ready,chan中ready一般是指数据都拿到或者都发走了
  3. chanUpdateListenEvents(int chfd, uint32_t mask): 变量声明要在开头
  4. chanOpenSock_() 不要在这里面加 regist epoll
  5. chanepoll_()里面能不能循环nready时就同步创建readychan?
  6. lib.channel.c 中创建的socket,建议创建出来后,需要时,再用函数添加到epoll监控事件里

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants