Linux Multi-timer implementation of the second __linux

Source: Internet
Author: User
Tags event timer hash prefetch prev set time
Linux Multi-timer implementation of the second

In this paper, the implementation of the multi timer in the industrial level, the realization of the second-level timer, time complexity of approximately o (1). Has the following characteristics: The time complexity of the new timer drop is approximately O (1). According to the timer timeout, the new timer is hashed into the hash bucket . The time complexity of the timer is approximately O (1) , which can be used in the C language code of multiple timers for multithreaded environments:

/*********************************************************************** * Copyright (c) 2018 Pepstack, pepstack.com  * This software are provided ' as-is ', without any express or implied * warranty.
In no event would the authors be held liable to any damages * arising from the ' use of ' this software. * Permission is granted to anyone to the use of this software for all purpose, * including commercial, and to alter It and redistribute it * freely, subject to the following restrictions: * * 1. The origin of this software must is not misrepresented; You are must not * claim this you wrote the original software. If you use this software * to a product, an acknowledgment in the product documentation would being * appreciated but is
Not required. * * 2. 
Altered source versions must is plainly marked as such, and must not * is misrepresented as being the original. * * 3.
This notice may is removed or altered from any source distribution. ************************************//** * Mul_wheel_timer.h * Multi wheel timer for Linux * * Second-level Multi-timer industrial-level implementation * Refer: * http://blog.csdn.net/zhangxinrun/article/details/5914191 * https://linux.die.net/man/2/setitimer * * * AUT 
hor:master@pepstack.com * * create:2018-02-03 11:00 * update:2018-02-03 22:09/#ifndef mul_wheel_timer_h_included #define MUL_WHEEL_TIMER_H_INCLUDED #if defined (__cplusplus) extern "C" {#endif #include "dhlist.h" #include <pthre ad.h> #include <unistd.h> #include <time.h> #include <sys/time.h>/** * Whether to use a double linked list: If you do not need to traverse the timer in order do not enable   it * * mul_wheel_timer_has_dlist = 1 * Use Dlist to traversing by sequence * * mul_wheel_timer_has_dlist = 0 * DONOT use dlist since we need not traversing by sequence/#define MUL_WHEEL_TIMER_HAS_DLIST 0/** * Mul_wheel_tim Er_hashlen_max * * Defines the size of the hash bucket (2^n-1) = [255, 1023, 4095, 8191] * can be specified at compile time as needed.
 The larger the bucket, the faster the lookup rate. * * #ifndef Mul_wheel_timer_hashlen_max # define Mul_wheel_timer_hashlen_max 1023 #endif/** * mul_wheel_timer_timeunit_sec * * Defines the time unit for multiple timers: that is, the minimum time interval. The system will trigger the timer callback function according to the time interval: Sigalarm_handler/#ifndef mul_wheel_timer_timeunit_sec # define Mul_wheel_timer_timeunit_s

EC 1 #endif #define MUL_WHEEL_TIMER_TIMEUNIT_DEFAULT ( -1) typedef int64_t mul_eventid_t;


typedef mul_eventid_t * MUL_EVENT_HANDLE;

    typedef struct MUL_TIMER_EVENT_T {mul_eventid_t EventID;

    /* Reference count: 0 Delete, 1 reserved */int REFC;
    void *eventarg;

    Int (*TIMER_EVENT_CB) (Mul_event_handle eventhdl, void *eventarg);

    int64_t On_counter;

    /* Specify the timer first excitation time and after each interval excitation time * * struct itimerval value;

    unsigned int timeout;

    int hash;
/** dhlist node */#if Mul_wheel_timer_has_dlist = = 1 struct list_head i_list;
#endif struct Hlist_node i_hash;


} mul_timer_event_t;

    typedef struct MUL_WHEEL_TIMER_T {pthread_mutex_t lock;

    /** * Timer Status: * 1: Start * 0: Suspend */int status; VolatileMul_eventid_t EventID;

    Volatile int64_t counter;
    void (* old_sigalarm) (int);

    void (* new_sigalarm) (int);

    unsigned int timeunit;

    struct Itimerval value, ovalue;
/** Dhlist for Timer entry */#if mul_wheel_timer_has_dlist = = 1 struct list_head;
#endif struct Hlist_head Hlist[mul_wheel_timer_hashlen_max + 1];


} mul_wheel_timer_t;


/* Global timer variable for one Linux process/__attribute__ (used) static struct mul_wheel_timer_t mulwheeltimer;


__ATTRIBUTE__ ((used)) static void Sigalarm_handler (int signo);  __ATTRIBUTE__ ((used)) static inline void free_timer_event (struct mul_timer_event_t * event) {printf ("\033[32m-delete
    Event_%llu\033[0m\n ", (unsigned long) event->eventid);
Free (event);  } __attribute__ ((used)) static inline mul_timer_event_t * Mul_handle_cast_event (mul_event_handle eventhdl) {struct
    mul_timer_event_t * Event = container_of (EVENTHDL, struct mul_timer_event_t, EventID);
return event; } __atTRIBUTE__ ((used)) static int64_t Timer_on_counter_hash (mul_wheel_timer_t * mwtr, unsigned int tv_sec, int *hash) {in
    t64_t On_counter = (int64_t) (Tv_sec/mwtr->timeunit + mwtr->counter);

    *hash = (On_counter & Mul_wheel_timer_hashlen_max);
    printf ("* \033[36mon_counter=%lld, hash=%d\033[0m\n", (Long Long) On_counter, (*hash));
return on_counter;  } __attribute__ ((used)) static int Timer_select_sleep (int sec, int ms) {if (sec | | ms) {struct Timeval TV

        = {0};
        Tv.tv_sec = sec;

        Tv.tv_usec =ms*1000;
    Return Select (0, NULL, NULL, NULL, &AMP;TV);
    else {return 0; }/** * Mul_wheel_timer_create * * Initializes multiple timers based on the given value.
 This procedure does not provide the timer below the second, if need to ask the user to expand. * * Params: * start-1: Start timer immediately; 0: Do not start timer * * 1 multiple timers that initialize the minimum time unit (= mul_wheel_timer_timeunit_sec) Second: * * Mul_wheel_timer_create (mul_wheel_timer_t
 Imeunit_default, 0);    * * 2 Initializes a multiple timer for the minimum time unit (= 10) seconds, and starts after 60 seconds to activate 1 times every 10 seconds: *  Mul_wheel_timer_create (10, 60);
 * * Returns: * 0:success * -1:failed.
 * Use Strerror (errno) for the error message.  */__attribute__ ((used)) static int mul_wheel_timer_create (long timeunit_sec, long timedelay_sec, int start) {int I,

    Err

    Bzero (&mulwheeltimer, sizeof (struct mul_wheel_timer_t));

Mulwheeltimer.eventid = 1;
#if mul_wheel_timer_has_dlist = = 1 Init_list_head (&mulwheeltimer.dlist);
    #endif for (i = 0; I <= mul_wheel_timer_hashlen_max i++) {init_hlist_head (&mulwheeltimer.hlist[i]);
    Err = Pthread_mutex_init (&mulwheeltimer.lock, 0);
    if (err) {/* Nerver run to this! */return (-1);
    Err = Pthread_mutex_lock (&mulwheeltimer.lock);
        if (err) {printf ("[MWt] Pthread_mutex_lock error (%d):%s\n", err, strerror (err));
    Return (-1); } if ((Mulwheeltimer.old_sigalarm = Signal (SIGALRM, sigalarm_handler)) = = Sig_err) {Pthread_mutex_destroy (&mulwheeltimer.lock);
    Return (-1);

    } mulwheeltimer.new_sigalarm = Sigalarm_handler;
     /** * Set time interval for the it_interval timer. * It_interval should be set to be the minimum time interval for late-added timers. Default is seconds: * mul_wheel_timer_timeunit_sec */if (timeunit_sec = = mul_wheel_timer_timeunit_default) {mu
        Lwheeltimer.value.it_interval.tv_sec = mul_wheel_timer_timeunit_sec;
    mulwheeltimer.value.it_interval.tv_usec = 0;
        else {mulwheeltimer.value.it_interval.tv_sec = timeunit_sec;
    mulwheeltimer.value.it_interval.tv_usec = 0; /** set time interval, in seconds: This program does not provide the timer below the seconds, if necessary, please expand their own users.

    * * Mulwheeltimer.timeunit = mulwheeltimer.value.it_interval.tv_sec; /** set the timer with the expiration time of It_value, once the time reaches It_value, the kernel uses the It_interval restart Timer/if (timedelay_sec <= 0) {Mulwheeltimer
        . value.it_value.tv_sec = mulwheeltimer.value.it_interval.tv_sec;
    mulwheeltimer.value.it_value.tv_usec = 0; else {mulwheeltimer.value.it_value.tv_sec = Timedelay_seC
    mulwheeltimer.value.it_value.tv_usec = 0;
        } if (start) {err = Setitimer (Itimer_real, &mulwheeltimer.value, &mulwheeltimer.ovalue);
            if (! Err) {/** Timer was successfully created and started/mulwheeltimer.status = 1;
            Pthread_mutex_unlock (&mulwheeltimer.lock);
            printf ("[MWt] Create success.\n");
        return 0;
            else {/** timer created but failed to start/mulwheeltimer.status = 0;
            Pthread_mutex_destroy (&mulwheeltimer.lock);
            printf ("[MWt] Create failed.\n");
        Return (-1);
        } else {/** timer successfully created, but does not require start/mulwheeltimer.status = 0;
        Pthread_mutex_unlock (&mulwheeltimer.lock);
        printf ("[MWT] Create success with no start.\n");
    return 0;    }/** * Mul_wheel_timer_start * Start Timer * * Returns: * 0:success successfully started * 1:sfalse has started * -1:error Start Failure/__attribute__ ((used)) static int mul_wheel_Timer_start (void) {int err;
    Err = Pthread_mutex_trylock (&mulwheeltimer.lock);
        if (err) {/** multithreaded lock failed/printf ("[MWt] Pthread_mutex_trylock error (%d):%s\n", err, strerror (err));
    Return (-1);
        } if (mulwheeltimer.status = = 1) {/** has started */Pthread_mutex_unlock (&mulwheeltimer.lock);
        printf ("[MWt] already start.\n");
    return 1;
    Err = Setitimer (Itimer_real, &mulwheeltimer.value, &mulwheeltimer.ovalue);
        if (! Err) {/** timer successfully started/mulwheeltimer.status = 1;
        Pthread_mutex_unlock (&mulwheeltimer.lock);
        printf ("[MWt] Start success.\n");
    return 0;
        else {/** timer failed to start/mulwheeltimer.status = 0;
        Pthread_mutex_unlock (&mulwheeltimer.lock);
        printf ("[MWt] Start error.\n");
    Return (-1);
 }/** * Mul_wheel_timer_destroy * * Returns: * 0:success * -1:failed. * Use Strerror (errno) For the error message.

    */__attribute__ ((used)) static int Mul_wheel_timer_destroy (void) {int err;
    Err = Pthread_mutex_lock (&mulwheeltimer.lock);
        if (err) {printf ("[MWt] Pthread_mutex_lock error (%d):%s\n", err, strerror (err));
    Return (-1); } if ((Signal (SIGALRM, mulwheeltimer.new_sigalarm)) = = Sig_err) {Pthread_mutex_unlock (&mulwheeltimer.loc
        k); printf ("[MWt] Destroy failed."
        Signal error.\n ");
    Return (-1);
    /** recovery Process The original timer */err = Setitimer (Itimer_real, &mulwheeltimer.ovalue, &mulwheeltimer.value);
        if (Err < 0) {Pthread_mutex_unlock (&mulwheeltimer.lock); printf ("[MWt] Destroy failed."
        Setitimer error (%d):%s.\n ", errno, Strerror (errno));
    Return (-1);

        /** Empty Timer list/#if mul_wheel_timer_has_dlist = = 1 do {struct list_head *list, *node; List_for_each_safe (list, node, &mulwheeltimer.dlist) {struct mul_timer_event_t * Event = list_entry (list, struct mul_timer_event_t, i_list);
            Hlist_del (&event->i_hash);

            List_del (&event->i_list);
        Free_timer_event (event);
} while (0);
        #else do {int hash;

        struct Hlist_node *hp, *hn; for (hash = 0; hash <= mul_wheel_timer_hashlen_max; hash++) {Hlist_for_each_safe (HP, HN, &mulwheeltime

                R.hlist[hash]) {struct mul_timer_event_t * event = hlist_entry (HP, struct mul_timer_event_t, i_hash);

                Hlist_del (&event->i_hash);
            Free_timer_event (event);
}} while (0);

    #endif Pthread_mutex_destroy (&mulwheeltimer.lock);

    Bzero (&mulwheeltimer, sizeof (struct mul_wheel_timer_t));
    printf ("[MWt] Destroy success.\n");
return (0); /** * Mul_wheel_timer_set_event * Set Event Timer * * Params: * timedelay_sec-Specifies the time of the first fire: how many seconds after the current timer first starts to fire E
 Vent * 0: Immediate excitation
 * > 0: Delay Time (SEC) * timeinterval_sec-How many seconds after the first event is fired. * 0: does not excite * > 0: Interval How many seconds time fires * Returns: * > 0:mul_eventid_t, Success * < 0:failed/__a TTRIBUTE__ ((used)) static mul_eventid_t mul_wheel_timer_set_event (unsigned int timedelay_sec, unsigned int
    timeinterval_sec, Int (*ON_EVENT_CB) (Mul_event_handle eventhdl, void *eventarg), void *eventarg) {int err, hash;
    int64_t On_counter;

    mul_timer_event_t *new_event;
    if (timedelay_sec = = 1 | | timeinterval_sec = = 1) {/** Invalid timer */return (-2);
    Err = Pthread_mutex_trylock (&mulwheeltimer.lock);
        if (err) {/** multithreaded lock failed/printf ("[MWt] Pthread_mutex_trylock error (%d):%s\n", err, strerror (err));
    Return (-1); /** when mulwheeltimer.counter = = On_counter is fired * therefore set to On_counter for the hash key save Event */On_counter = Tim

    Er_on_counter_hash (&mulwheeltimer, timedelay_sec, &hash); New_event= (mul_timer_event_t *) malloc (sizeof (mul_timer_event_t));
        if (! new_event) {/** out of memory */Pthread_mutex_unlock (&mulwheeltimer.lock);
    Return (-4);

    } bzero (New_event, sizeof (mul_timer_event_t));

    New_event->eventid = mulwheeltimer.eventid++;

    New_event->on_counter = On_counter;

    /** Current Time * * new_event->value.it_value.tv_sec = timedelay_sec;

    /** Next time * * new_event->value.it_interval.tv_sec = timeinterval_sec;

    New_event->hash = hash;
    /** set callback parameters and functions, the callback function is implemented by the user himself/new_event->eventarg = EventArg;

    NEW_EVENT-&GT;TIMER_EVENT_CB = ON_EVENT_CB; printf ("\033[31m+create event_%lld. (%d:%d) \033[0m\n ", (Long Long) New_event->eventid, (int) new_event->value.it_value.tv_sec, (int) new_event-&

GT;VALUE.IT_INTERVAL.TV_SEC);
#if mul_wheel_timer_has_dlist = = 1/** string into long string/List_add (&new_event->i_list, &mulwheeltimer.dlist); #endif/** Hash Short String */Hlist_adD_head (&new_event->i_hash, &mulwheeltimer.hlist[hash]);

    /** set Reference count to 1 */NEW_EVENT-&GT;REFC = 1;
    Demonstrates how to delete itself:////hlist_del (&new_event->i_hash);
    List_del (&new_event->i_list);

    Free_timer_event (new_event);

    Pthread_mutex_unlock (&mulwheeltimer.lock);
Return new_event->eventid; /** * mul_wheel_timer_remove_event * Deletes events from multiple timers. The call simply marks the event to be deleted.
 The behavior of the real deletion is determined by the system.
 * * Returns: * 0:success * -1:failed. */__attribute__ ((used)) static int mul_wheel_timer_remove_event (Mul_event_handle eventhdl) {mul_timer_event_t * Eve

    NT = mul_handle_cast_event (EVENTHDL);

    printf ("Remove event-%lld\n", (Long Long) event->eventid);

    /** set reference count of 0, automatically remove/__sync_lock_release (&AMP;EVENT-&GT;REFC) When an event is triggered;
return 0; /** * Mul_wheel_timer_fire_event * finds event * * Params based on currently fired counter: * On_counter-Currently fired counter * * returns : */__attribute__ ((used)) Static mul_timer_event_t * Mul_wheel_timer_fiRe_event (int64_t fire_counter) {struct Hlist_node *hp;

    struct Hlist_node *hn;

    int hash = (int) (Fire_counter & Mul_wheel_timer_hashlen_max); Hlist_for_each_safe (HP, HN, &mulwheeltimer.hlist[hash]) {struct mul_timer_event_t * event = Hlist_entry (HP, S

        Truct mul_timer_event_t, I_hash);

        if (Event->on_counter = = fire_counter) {/** First removes itself from the list */Hlist_del (&event->i_hash);
        #if mul_wheel_timer_has_dlist = = 1 List_del (&event->i_list);
                #endif if (__sync_lock_test_and_set (&AMP;EVENT-&GT;REFC, 1) = = 0) {/** request to delete the event * *
            Free_timer_event (event); else {/** Fire event callback function/EVENT-&GT;TIMER_EVENT_CB (&event->eventid, Event->eventa

                RG); if (event->value.it_interval.tv_sec = = 0) {/* Use only once, next time no longer fires, delete event/Free_timer
        _event (event);        else {event->on_counter = Timer_on_counter_hash (&mulwheeltimer, event->value.it_i

                Nterval.tv_sec, &event->hash); #if mul_wheel_timer_has_dlist = = 1/** string into long string/List_add (&event->i_list, &am
                P;mulwheeltimer.dlist); #endif/** Hash Short string/Hlist_add_head (&event->i_hash, &AMP;MULWHEELTIMER.HL
                Ist[event->hash]);
return 0;
    } __attribute__ ((used)) static void Sigalarm_handler (int signo) {int err;

    int64_t On_counter;
    Err = Pthread_mutex_trylock (&mulwheeltimer.lock); if (err) {/** multithreaded lock failed/printf ("[mwt]\033[33m Lock Error:%llu\033[0m\n", (unsigned long long) mulwheelt
        Imer.counter);
    Return

    /** the current fired counter/on_counter = mulwheeltimer.counter++; /** * Fire Event: This event invokes a user-supplied callback function in a locked state: * On_timer_eveNT * *!!
     Therefore, it is not possible to perform a long operation in On_timer_event!!

    * * Mul_wheel_timer_fire_event (On_counter);

    Pthread_mutex_unlock (&mulwheeltimer.lock);
printf ("* Alarm:%llu\n", (unsigned long) on_counter);
 #if defined (__cplusplus)} #endif #endif/* mul_wheel_timer_h_included * *
C code for double-linked lists:
/** * dhlist.h *-deque list and hash list from Linux Kernel * * to Linux Kernel * for Windows and Linux * * mo Dified by Cheungmine * 2013-4, 2018-02-03/#ifndef _dh_list_h #define _DH_LIST_H #if defined (__cplusplus) extern "C"  {#endif #include <assert.h> #include <stdio.h> #include <string.h> #include <memory.h> #include <malloc.h>/** * BKDR Hash Function * http://www.cnblogs.com/-clq/archive/2012/05/31/2528153.html/static
    inline unsigned int bkdrhash (char *str) {/* seed:31 131 1313 13131 131313 etc. */unsigned int seed = 131;

    unsigned int hash = 0;
    while (*STR) {hash = hash * seed + (*str++);
Return (hash & 0x7fffffff); static inline unsigned int BKDRHash2 (char *str, int hashlen) {/* seed:31 131 1313 13131-131313 etc. * * uns
    igned int seed = 131;

    unsigned int hash = 0;
    while (*STR) {hash = hash * seed + (*str++); Return (Hash & 0x7FFFFFFF) & Hashlen); #ifdef Config_illegal_pointer_value # define Poison_pointer_delta _ac (Config_illegal_pointer_value, UL) #else # def Ine Poison_pointer_delta 0 #endif/** * are non-null pointers that'll result in page faults * under normal CIR
 Cumstances, used to verify that nobody uses * non-initialized list entries. * * #define LIST_POISON1 ((void *) 0x00100100 + poison_pointer_delta) #define List_poison2 (void *) 0x00200200 + poison_  Pointer_delta) #ifdef typeof static inline void prefetch (const void *x) {;} static inline void Prefetchw (const void *x)

{;} /** * filename:linux-2.6.7/include/linux/stddef.h/#define OFFSET_OF (Type, member) ((size_t) & ((type *) 0)->mem BER) #define CONTAINER_OF (PTR, type, member) ({\ Const typeof ((type *) 0)->member) *__mptr = (ptr); \ (Typ E *) ((char *) __mptr-offset_of (type,member)); #else static inline int prefetch (const void *x) {; return 1;} static inline int prefetchw (const void *x) {; return 1;} #define OFFSET_OF (Type, field) (unsigned int) (uintptr_t) (void*) & ((type *) 0)->field) #define CONTAINER_OF (AD 
    Dress, type, field) \ ((Type *) ((char *) (address)-offset_of (Type, field)) #endif/* typeof/* struct List_head {
struct List_head *next, *prev;

}; #define LIST_HEAD_INIT (name) {& (name), & (name)} #define LIST_HEAD (name) \ struct List_head name = List_head _init (name) #define INIT_LIST_HEAD (PTR) do {(PTR)->next = (PTR); (PTR)->prev = (PTR);
 \} while (0)/* Insert A new entry between two known consecutive entries.
 * * This is a for internal list manipulation where we know * the Prev/next entries already! */static inline void __list_add (struct list_head *_new, struct list_head,

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.