diff options
Diffstat (limited to 'src/lib')
| -rw-r--r-- | src/lib/CMakeLists.txt | 106 | ||||
| -rw-r--r-- | src/lib/cacep.c | 3 | ||||
| -rw-r--r-- | src/lib/cdap.c | 3 | ||||
| -rw-r--r-- | src/lib/cdap_req.c | 5 | ||||
| -rw-r--r-- | src/lib/cdap_req.h | 1 | ||||
| -rw-r--r-- | src/lib/config.h.in | 57 | ||||
| -rw-r--r-- | src/lib/dev.c | 478 | ||||
| -rw-r--r-- | src/lib/frct_pci.c | 112 | ||||
| -rw-r--r-- | src/lib/hash.c | 43 | ||||
| -rw-r--r-- | src/lib/irm.c | 3 | ||||
| -rw-r--r-- | src/lib/lockfile.c | 15 | ||||
| -rw-r--r-- | src/lib/md5.c | 2 | ||||
| -rw-r--r-- | src/lib/nsm.c | 55 | ||||
| -rw-r--r-- | src/lib/random.c | 3 | ||||
| -rw-r--r-- | src/lib/rib.c | 5 | ||||
| -rw-r--r-- | src/lib/shm_flow_set.c | 52 | ||||
| -rw-r--r-- | src/lib/shm_rbuff.c | 7 | ||||
| -rw-r--r-- | src/lib/shm_rbuff_ll.c | 15 | ||||
| -rw-r--r-- | src/lib/shm_rbuff_pthr.c | 15 | ||||
| -rw-r--r-- | src/lib/shm_rdrbuff.c | 5 | ||||
| -rw-r--r-- | src/lib/sockets.c | 31 | ||||
| -rw-r--r-- | src/lib/tests/CMakeLists.txt | 7 | ||||
| -rw-r--r-- | src/lib/tests/rib_test.c | 3 | ||||
| -rw-r--r-- | src/lib/tests/timerwheel_test.c | 104 | ||||
| -rw-r--r-- | src/lib/time_utils.c | 3 | ||||
| -rw-r--r-- | src/lib/timerwheel.c | 232 | ||||
| -rw-r--r-- | src/lib/tpm.c | 5 | 
27 files changed, 1128 insertions, 242 deletions
diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index 550bbc08..9d8fbf9c 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -15,7 +15,7 @@ protobuf_generate_c(CACEP_PROTO_SRCS CACEP_PROTO_HDRS cacep.proto)  if (NOT APPLE)    find_library(LIBRT_LIBRARIES rt)    if (NOT LIBRT_LIBRARIES) -    message(FATAL_ERROR "Could not find librt.") +    message(FATAL_ERROR "Could not find librt")    endif ()  else ()    set(LIBRT_LIBRARIES "") @@ -23,7 +23,7 @@ endif ()  find_library(LIBPTHREAD_LIBRARIES pthread)  if (NOT LIBPTHREAD_LIBRARIES) -  message(FATAL_ERROR "Could not find libpthread.") +  message(FATAL_ERROR "Could not find libpthread")  endif ()  include(CheckSymbolExists) @@ -31,30 +31,60 @@ list(APPEND CMAKE_REQUIRED_DEFINITIONS -D_POSIX_C_SOURCE=200809L)  list(APPEND CMAKE_REQUIRED_DEFINITIONS -D__XSI_VISIBLE=500)  list(APPEND CMAKE_REQUIRED_LIBRARIES pthread)  check_symbol_exists(pthread_mutexattr_setrobust pthread.h HAVE_ROBUST_MUTEX) -set(HAVE_ROBUST_MUTEX CACHE STRING "Have robust mutexes") + +if (HAVE_ROBUST_MUTEX) +  set(DISABLE_ROBUST_MUTEXES FALSE CACHE BOOL "Disable robust mutex support") +  if (NOT DISABLE_ROBUST_MUTEXES) +    message(STATUS "Robust mutex support enabled") +    set(HAVE_ROBUST_MUTEX TRUE) +  else () +    message(STATUS "Robust mutex support disabled by user") +    set(HAVE_ROBUST_MUTEX FALSE) +  endif () +endif ()  find_library(LIBGCRYPT_LIBRARIES gcrypt)  if (LIBGCRYPT_LIBRARIES) -  find_path(LIBGCRYPT_INCLUDE_DIR gcrypt.h HINTS /usr/include /usr/local/include) -  if (NOT LIBGCRYPT_INCLUDE_DIR STREQUAL "GRYPT_INCLUDE_DIR-NOTFOUND") +  find_path(LIBGCRYPT_INCLUDE_DIR gcrypt.h +            HINTS /usr/include /usr/local/include) +  if (LIBGCRYPT_INCLUDE_DIR)      file(STRINGS ${LIBGCRYPT_INCLUDE_DIR}/gcrypt.h GCSTR        REGEX "^#define GCRYPT_VERSION ")      string(REGEX REPLACE "^#define GCRYPT_VERSION \"(.*)\".*$" "\\1"        GCVER "${GCSTR}") -    message(STATUS "Found libgcrypt: ${LIBGCRYPT_LIBRARIES} (found version \"${GCVER}\")") +    message(STATUS "Found libgcrypt: ${LIBGCRYPT_LIBRARIES}" +                   "(found version \"${GCVER}\")")      if (NOT GCVER VERSION_LESS "1.7.0") -      set(HAVE_LIBGCRYPT "1" CACHE STRING "Have libgcrypt") +      set (DISABLE_LIBGCRYPT FALSE CACHE BOOL "Disable libgcrypt support") +      if (NOT DISABLE_LIBGCRYPT) +        message(STATUS "libgcrypt support enabled") +        set(HAVE_LIBGCRYPT TRUE) +      else () +        message(STATUS "libgcrpyt support disabled by user") +      endif() +    else () +      message(STATUS "Install version > \"1.7.0\" to enable libgcrypt support")      endif()    endif () -else () +endif () + +if (NOT HAVE_LIBGCRYPT)    set(LIBGCRYPT_LIBRARIES "")    set(LIBGCRYPT_INCLUDE_DIR "")  endif ()  find_package(OpenSSL)  if (OPENSSL_FOUND) -  set(HAVE_OPENSSL "1" CACHE STRING "Have OpenSSL") -else () +  set (DISABLE_OPENSSL FALSE CACHE BOOL "Disable OpenSSL support") +  if (NOT DISABLE_OPENSSL) +    message(STATUS "OpenSSL support enabled") +    set(HAVE_OPENSSL TRUE) +  else() +    message(STATUS "OpenSSL support disabled by user") +  endif() +endif () + +if (NOT HAVE_OPENSSL)    set (OPENSSL_INCLUDE_DIR "")  endif () @@ -62,9 +92,9 @@ if (APPLE OR CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")    set(SYS_RND_HDR "")  else ()    find_path(SYS_RND_HDR sys/random.h PATH /usr/include/ /usr/local/include/) -  if (NOT SYS_RND_HDR STREQUAL "SYS_RND_HDR-NOTFOUND") +  if (SYS_RND_HDR)      message(STATUS "Found sys/random.h in ${SYS_RND_HDR}") -    set(HAVE_SYS_RANDOM "1" CACHE STRING "Have random header") +    set(HAVE_SYS_RANDOM TRUE)    else ()      set(SYS_RND_HDR "")    endif () @@ -73,10 +103,52 @@ endif()  if (NOT ((CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") OR APPLE OR    HAVE_SYS_RANDOM OR HAVE_OPENSSL OR HAVE_LIBGCRYPT))    message(FATAL_ERROR "No secure random generator found, " -                      "please install libgcrypt (> 1.7.0) or OpenSSL" -    ) +                      "please install libgcrypt (> 1.7.0) or OpenSSL")  endif () +mark_as_advanced(LIBRT_LIBRARIES LIBPTHREAD_LIBRARIES +  LIBGCRYPT_LIBRARIES OPENSSL_LIBRARIES SYS_RND_INCLUDE_DIR +  LIBGCRYPT_INCLUDE_DIR SYS_RND_HDR) + +math(EXPR SHM_BUFFER_EXPR "1 << 20") +set(SHM_BUFFER_SIZE ${SHM_BUFFER_EXPR} CACHE STRING +    "Number of blocks in SDU buffer, must be a power of 2") +set(SYS_MAX_FLOWS 4096 CACHE STRING +  "Maximum number of total flows for this system") +set(AP_MAX_FLOWS 1024 CACHE STRING +  "Maximum number of flows in an application") +set(AP_RES_FDS 64 CACHE STRING +  "Number of reserved flow descriptors per application") +set(AP_MAX_FQUEUES 32 CACHE STRING +  "Maximum number of flow sets per application") +set(DU_BUFF_HEADSPACE 128 CACHE STRING +  "Bytes of headspace to reserve for future headers") +set(DU_BUFF_TAILSPACE 16 CACHE STRING +  "Bytes of tailspace to reserve for future tails") +if (NOT APPLE) +  set(PTHREAD_COND_CLOCK "CLOCK_MONOTONIC" CACHE STRING +    "Clock to use for condition variable timing") +else () +  set (PTHREAD_COND_CLOCK "CLOCK_REALTIME" CACHE INTERNAL +    "Clock to use for condition variable timing") +endif () +set(SOCKET_TIMEOUT 1000 CACHE STRING +  "Default timeout for responses from IPCPs (ms)") +set(CDAP_REPLY_TIMEOUT 6000 CACHE STRING +  "Timeout for CDAP to wait for reply") +set(SHM_PREFIX "ouroboros" CACHE STRING +  "String to prepend to POSIX shared memory filenames") +set(SHM_RBUFF_PREFIX "/${SHM_PREFIX}.rbuff." CACHE INTERNAL +  "Prefix for rbuff POSIX shared memory filenames") +set(SHM_LOCKFILE_NAME "/${SHM_PREFIX}.lockfile" CACHE INTERNAL +  "Filename for the POSIX shared memory lockfile") +set(SHM_FLOW_SET_PREFIX "/${SHM_PREFIX}.set." CACHE INTERNAL +  "Prefix for the POSIX shared memory flow set") +set(SHM_RDRB_NAME "/${SHM_PREFIX}.rdrb" CACHE INTERNAL +  "Name for the main POSIX shared memory buffer") +set(SHM_RDRB_BLOCK_SIZE "sysconf(_SC_PAGESIZE)" CACHE STRING +  "SDU buffer block size, multiple of pagesize for performance") +  set(SOURCE_FILES    # Add source files here    bitmap.c @@ -86,6 +158,7 @@ set(SOURCE_FILES    cdap_req.c    crc32.c    dev.c +  frct_pci.c    hash.c    hashtable.c    irm.c @@ -93,7 +166,6 @@ set(SOURCE_FILES    lockfile.c    logs.c    md5.c -  nsm.c    qos.c    qoscube.c    random.c @@ -104,10 +176,14 @@ set(SOURCE_FILES    shm_rdrbuff.c    sockets.c    time_utils.c +  timerwheel.c    tpm.c    utils.c    ) +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/config.h.in" +  "${CMAKE_CURRENT_BINARY_DIR}/config.h" @ONLY) +  add_library(ouroboros SHARED ${SOURCE_FILES} ${IRM_PROTO_SRCS}    ${IPCP_PROTO_SRCS} ${DIF_CONFIG_PROTO_SRCS} ${CDAP_PROTO_SRCS}    ${CACEP_PROTO_SRCS} ${RO_PROTO_SRCS}) diff --git a/src/lib/cacep.c b/src/lib/cacep.c index 55d11b0f..722adca1 100644 --- a/src/lib/cacep.c +++ b/src/lib/cacep.c @@ -20,7 +20,8 @@   * Foundation, Inc., http://www.fsf.org/about/contact/.   */ -#include <ouroboros/config.h> +#define _POSIX_C_SOURCE 199309L +  #include <ouroboros/cacep.h>  #include <ouroboros/dev.h>  #include <ouroboros/errno.h> diff --git a/src/lib/cdap.c b/src/lib/cdap.c index bf8d5816..679771f5 100644 --- a/src/lib/cdap.c +++ b/src/lib/cdap.c @@ -20,7 +20,8 @@   * Foundation, Inc., http://www.fsf.org/about/contact/.   */ -#include <ouroboros/config.h> +#define _POSIX_C_SOURCE 200809L +  #include <ouroboros/cdap.h>  #include <ouroboros/bitmap.h>  #include <ouroboros/dev.h> diff --git a/src/lib/cdap_req.c b/src/lib/cdap_req.c index 7aded62f..a9b85525 100644 --- a/src/lib/cdap_req.c +++ b/src/lib/cdap_req.c @@ -20,7 +20,10 @@   * Foundation, Inc., http://www.fsf.org/about/contact/.   */ -#include <ouroboros/config.h> +#define _POSIX_C_SOURCE 200809L + +#include "config.h" +  #include <ouroboros/time_utils.h>  #include <ouroboros/errno.h> diff --git a/src/lib/cdap_req.h b/src/lib/cdap_req.h index 89f4145a..4c9cd15b 100644 --- a/src/lib/cdap_req.h +++ b/src/lib/cdap_req.h @@ -23,7 +23,6 @@  #ifndef OUROBOROS_CDAP_REQ_H  #define OUROBOROS_CDAP_REQ_H -#include <ouroboros/config.h>  #include <ouroboros/cdap.h>  #include <ouroboros/list.h>  #include <ouroboros/utils.h> diff --git a/src/lib/config.h.in b/src/lib/config.h.in new file mode 100644 index 00000000..e9c43389 --- /dev/null +++ b/src/lib/config.h.in @@ -0,0 +1,57 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2017 + * + * Ouroboros library configuration + * + *    Dimitri Staessens <dimitri.staessens@ugent.be> + *    Sander Vrijders   <sander.vrijders@ugent.be> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * version 2.1 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., http://www.fsf.org/about/contact/. + */ + +#cmakedefine HAVE_SYS_RANDOM +#cmakedefine HAVE_LIBGCRYPT +#cmakedefine HAVE_OPENSSL + +#define SYS_MAX_FLOWS       @SYS_MAX_FLOWS@ + +#cmakedefine                SHM_RBUFF_LOCKLESS + +#define SHM_RBUFF_PREFIX    "@SHM_RBUFF_PREFIX@" +#define SHM_LOCKFILE_NAME   "@SHM_LOCKFILE_NAME@" +#define SHM_FLOW_SET_PREFIX "@SHM_FLOW_SET_PREFIX@" +#define SHM_RDRB_NAME       "@SHM_RDRB_NAME@" +#define SHM_RDRB_BLOCK_SIZE @SHM_RDRB_BLOCK_SIZE@ +#define SHM_BUFFER_SIZE     @SHM_BUFFER_SIZE@ + +#if defined(__linux__) || (defined(__MACH__) && !defined(__APPLE__)) +/* Avoid a bug in robust mutex implementation of glibc 2.25 */ +    #include <features.h> +    #if !defined(__GLIBC__) || !(__GLIBC__ == 2 && __GLIBC_MINOR__ == 25) +    #cmakedefine HAVE_ROBUST_MUTEX +    #endif +#else +#cmakedefine HAVE_ROBUST_MUTEX +#endif + +#define PTHREAD_COND_CLOCK  @PTHREAD_COND_CLOCK@ + +#define AP_MAX_FLOWS        @AP_MAX_FLOWS@ +#define AP_RES_FDS          @AP_RES_FDS@ +#define AP_MAX_FQUEUES      @AP_MAX_FQUEUES@ + +#define DU_BUFF_HEADSPACE   @DU_BUFF_HEADSPACE@ +#define DU_BUFF_TAILSPACE   @DU_BUFF_TAILSPACE@ + +#define CDAP_REPLY_TIMEOUT  @CDAP_REPLY_TIMEOUT@ diff --git a/src/lib/dev.c b/src/lib/dev.c index 9354855b..b6c6087f 100644 --- a/src/lib/dev.c +++ b/src/lib/dev.c @@ -20,7 +20,10 @@   * Foundation, Inc., http://www.fsf.org/about/contact/.   */ -#include <ouroboros/config.h> +#define _POSIX_C_SOURCE 200809L + +#include "config.h" +  #include <ouroboros/errno.h>  #include <ouroboros/dev.h>  #include <ouroboros/ipcp-dev.h> @@ -34,6 +37,8 @@  #include <ouroboros/utils.h>  #include <ouroboros/fqueue.h>  #include <ouroboros/qoscube.h> +#include <ouroboros/timerwheel.h> +#include <ouroboros/frct_pci.h>  #include <stdlib.h>  #include <string.h> @@ -41,8 +46,14 @@  #define BUF_SIZE 1500 +#define TW_ELEMENTS   6000 +#define TW_RESOLUTION 1   /* ms */ + +#define MPL 2000 /* ms */ +  struct flow_set {          size_t idx; +        bool   np1_set;  };  struct fqueue { @@ -59,6 +70,22 @@ enum port_state {          PORT_DESTROY  }; +struct frcti { +        bool          used; + +        struct tw_f * snd_inact; +        bool          snd_drf; +        uint64_t      snd_lwe; +        uint64_t      snd_rwe; + +        struct tw_f * rcv_inact; +        bool          rcv_drf; +        uint64_t      rcv_lwe; +        uint64_t      rcv_rwe; + +        uint8_t       conf_flags; +}; +  struct port {          int             fd; @@ -89,10 +116,13 @@ struct {          struct shm_rdrbuff *  rdrb;          struct shm_flow_set * fqset; +        struct timerwheel *   tw; +          struct bmp *          fds;          struct bmp *          fqueues;          struct flow *         flows;          struct port *         ports; +        struct frcti *        frcti;          pthread_rwlock_t      lock;  } ai; @@ -203,6 +233,268 @@ static int api_announce(char * ap_name)          return ret;  } +/* Call under flows lock */ +static int finalize_write(int    fd, +                          size_t idx) +{ +        if (shm_rbuff_write(ai.flows[fd].tx_rb, idx) < 0) +                return -ENOTALLOC; + +        shm_flow_set_notify(ai.flows[fd].set, ai.flows[fd].port_id); + +        return 0; +} + +static int frcti_init(int fd) +{ +        struct frcti * frcti; + +        frcti = &(ai.frcti[fd]); + +        frcti->used = true; + +        frcti->snd_drf = true; +        frcti->snd_lwe = 0; +        frcti->snd_rwe = 0; + +        frcti->rcv_drf = true; +        frcti->rcv_lwe = 0; +        frcti->rcv_rwe = 0; + +        frcti->conf_flags = CONF_ERROR_CHECK; + +        return 0; +} + +static void frcti_clear(int fd) +{ +        struct frcti * frcti; + +        frcti = &(ai.frcti[fd]); + +        frcti->used = false; +        frcti->snd_inact = NULL; +        frcti->rcv_inact = NULL; +} + +static void frcti_fini(int fd) +{ +        struct frcti * frcti; + +        frcti = &(ai.frcti[fd]); + +        /* FIXME: We actually need to wait until these timers become NULL. */ +        if (frcti->snd_inact != NULL) +                timerwheel_stop(ai.tw, frcti->snd_inact); + +        if (frcti->rcv_inact != NULL) +                timerwheel_stop(ai.tw, frcti->rcv_inact); + +        frcti_clear(fd); +} + +static int frcti_configure(int         fd, +                           qosspec_t * qos) +{ +        /* FIXME: Send configuration message here to other side. */ + +        (void) fd; +        (void) qos; + +        return 0; +} + +static void frcti_snd_inactivity(void * arg) +{ +        struct frcti *  frcti; + +        pthread_rwlock_wrlock(&ai.lock); + +        frcti = (struct frcti * ) arg; + +        frcti->snd_drf = true; +        frcti->snd_inact = NULL; + +        pthread_rwlock_unlock(&ai.lock); +} + +/* Called under flows lock */ +static int frcti_write(int                  fd, +                       struct shm_du_buff * sdb) +{ +        struct frcti *  frcti; +        struct frct_pci pci; + +        memset(&pci, 0, sizeof(pci)); + +        frcti = &(ai.frcti[fd]); + +        pthread_rwlock_unlock(&ai.lock); + +        timerwheel_move(ai.tw); + +        pthread_rwlock_rdlock(&ai.lock); + +        /* +         * Set the DRF in the first packet of a new run of SDUs, +         * otherwise simply recharge the timer. +         */ +        if (frcti->snd_drf) { +                frcti->snd_inact = timerwheel_start(ai.tw, frcti_snd_inactivity, +                                                    frcti, 2 * MPL); +                if (frcti->snd_inact == NULL) +                        return -1; + +                pci.flags |= FLAG_DATA_RUN; +                frcti->snd_drf = false; +        } else { +                if (timerwheel_restart(ai.tw, frcti->snd_inact, 2 * MPL)) +                        return -1; +        } + +        pci.seqno = frcti->snd_lwe++; +        pci.type |= PDU_TYPE_DATA; + +        if (frct_pci_ser(sdb, &pci, frcti->conf_flags & CONF_ERROR_CHECK)) +                return -1; + +        if (finalize_write(fd, shm_du_buff_get_idx(sdb))) +                return -ENOTALLOC; + +        return 0; +} + +static void frcti_rcv_inactivity(void * arg) +{ +        struct frcti *  frcti; + +        pthread_rwlock_wrlock(&ai.lock); + +        frcti = (struct frcti * ) arg; + +        frcti->rcv_drf = true; +        frcti->rcv_inact = NULL; + +        pthread_rwlock_unlock(&ai.lock); +} + +static ssize_t frcti_read(int fd) +{ +        ssize_t              idx = -1; +        struct timespec      abstime; +        struct frcti *       frcti; +        struct frct_pci      pci; +        struct shm_du_buff * sdb; + +        timerwheel_move(ai.tw); + +        pthread_rwlock_rdlock(&ai.lock); + +        if (ai.flows[fd].oflags & FLOW_O_NONBLOCK) { +                idx = shm_rbuff_read(ai.flows[fd].rx_rb); +                pthread_rwlock_unlock(&ai.lock); +        } else { +                struct shm_rbuff * rb   = ai.flows[fd].rx_rb; +                bool timeo = ai.flows[fd].timesout; +                struct timespec timeout = ai.flows[fd].rcv_timeo; + +                pthread_rwlock_unlock(&ai.lock); + +                if (timeo) { +                        clock_gettime(PTHREAD_COND_CLOCK, &abstime); +                        ts_add(&abstime, &timeout, &abstime); +                        idx = shm_rbuff_read_b(rb, &abstime); +                } else { +                        idx = shm_rbuff_read_b(rb, NULL); +                } +        } + +        if (idx < 0) +                return idx; + +        pthread_rwlock_rdlock(&ai.lock); + +        frcti = &(ai.frcti[fd]); + +        sdb = shm_rdrbuff_get(ai.rdrb, idx); + +        /* SDU may be corrupted. */ +        if (frct_pci_des(sdb, &pci, frcti->conf_flags & CONF_ERROR_CHECK)) { +                pthread_rwlock_unlock(&ai.lock); +                shm_rdrbuff_remove(ai.rdrb, idx); +                return -EAGAIN; +        } + +        /* We don't accept packets when there is no inactivity timer. */ +        if (frcti->rcv_drf && !(pci.flags & FLAG_DATA_RUN)) { +                pthread_rwlock_unlock(&ai.lock); +                shm_rdrbuff_remove(ai.rdrb, idx); +                return -EAGAIN; +        } + +        /* +         * If there is an inactivity timer and the DRF is set, +         * reset the state of the connection. +         */ +        if (pci.flags & FLAG_DATA_RUN) { +                frcti->rcv_drf = true; +                if (frcti->rcv_inact != NULL) +                        timerwheel_stop(ai.tw, frcti->rcv_inact); +                frcti->rcv_lwe = pci.seqno; +        } + +        /* +         * Start receiver inactivity if this packet has the DRF, +         * otherwise simply restart it. +         */ +        if (frcti->rcv_drf) { +                frcti->rcv_inact = timerwheel_start(ai.tw, frcti_rcv_inactivity, +                                                    frcti, 3 * MPL); +                if (frcti->rcv_inact == NULL) { +                        pthread_rwlock_unlock(&ai.lock); +                        shm_rdrbuff_remove(ai.rdrb, idx); +                        return -EAGAIN; +                } + +                frcti->rcv_drf = false; +        } else { +                if (timerwheel_restart(ai.tw, frcti->rcv_inact, 3 * MPL)) { +                        pthread_rwlock_unlock(&ai.lock); +                        shm_rdrbuff_remove(ai.rdrb, idx); +                        return -EAGAIN; +                } +        } + +        pthread_rwlock_unlock(&ai.lock); + +        return idx; +} + +static int frcti_event_wait(struct flow_set *       set, +                            struct fqueue *         fq, +                            const struct timespec * timeout) +{ +        int ret; + +        assert(set); +        assert(fq); + +        timerwheel_move(ai.tw); + +        /* +         * FIXME: Return the fq only if a data SDU +         * for the application is available. +         */ + +        ret = shm_flow_set_wait(ai.fqset, set->idx, fq->fqueue, timeout); +        if (ret == -ETIMEDOUT) { +                fq->fqsize = 0; +                return -ETIMEDOUT; +        } + +        return ret; +} +  static void flow_clear(int fd)  {          assert(!(fd < 0)); @@ -230,6 +522,9 @@ static void flow_fini(int fd)          if (ai.flows[fd].set != NULL)                  shm_flow_set_close(ai.flows[fd].set); +        if (ai.frcti[fd].used) +                frcti_fini(fd); +          flow_clear(fd);  } @@ -316,10 +611,16 @@ int ouroboros_init(const char * ap_name)          if (ai.flows == NULL)                  goto fail_flows; -        for (i = 0; i < AP_MAX_FLOWS; ++i) +        ai.frcti = malloc(sizeof(*ai.frcti) * AP_MAX_FLOWS); +        if (ai.frcti == NULL) +                goto fail_frcti; + +        for (i = 0; i < AP_MAX_FLOWS; ++i) {                  flow_clear(i); +                frcti_clear(i); +        } -        ai.ports = malloc(sizeof(*ai.ports) * IRMD_MAX_FLOWS); +        ai.ports = malloc(sizeof(*ai.ports) * SYS_MAX_FLOWS);          if (ai.ports == NULL)                  goto fail_ports; @@ -334,7 +635,7 @@ int ouroboros_init(const char * ap_name)                  }          } -        for (i = 0; i < IRMD_MAX_FLOWS; ++i) { +        for (i = 0; i < SYS_MAX_FLOWS; ++i) {                  ai.ports[i].state = PORT_INIT;                  if (pthread_mutex_init(&ai.ports[i].state_lock, NULL)) {                          int j; @@ -353,24 +654,33 @@ int ouroboros_init(const char * ap_name)          if (pthread_rwlock_init(&ai.lock, NULL))                  goto fail_lock; +        ai.tw = timerwheel_create(TW_RESOLUTION, +                                  TW_RESOLUTION * TW_ELEMENTS); +        if (ai.tw == NULL) +                goto fail_timerwheel; +          return 0; + fail_timerwheel: +        pthread_rwlock_destroy(&ai.lock);   fail_lock: -        for (i = 0; i < IRMD_MAX_FLOWS; ++i) +        for (i = 0; i < SYS_MAX_FLOWS; ++i)                  pthread_cond_destroy(&ai.ports[i].state_cond);   fail_state_cond: -        for (i = 0; i < IRMD_MAX_FLOWS; ++i) +        for (i = 0; i < SYS_MAX_FLOWS; ++i)                  pthread_mutex_destroy(&ai.ports[i].state_lock);   fail_announce:          free(ai.ap_name);   fail_ap_name:          free(ai.ports);   fail_ports: +        free(ai.frcti); + fail_frcti:          free(ai.flows);   fail_flows:          shm_rdrbuff_close(ai.rdrb);   fail_rdrb: -      shm_flow_set_destroy(ai.fqset); +        shm_flow_set_destroy(ai.fqset);   fail_fqset:          bmp_destroy(ai.fqueues);   fail_fqueues: @@ -402,13 +712,16 @@ void ouroboros_fini()                  }          } -        for (i = 0; i < IRMD_MAX_FLOWS; ++i) { +        for (i = 0; i < SYS_MAX_FLOWS; ++i) {                  pthread_mutex_destroy(&ai.ports[i].state_lock);                  pthread_cond_destroy(&ai.ports[i].state_cond);          }          shm_rdrbuff_close(ai.rdrb); +        if (ai.tw != NULL) +                timerwheel_destroy(ai.tw); +          free(ai.flows);          free(ai.ports); @@ -463,9 +776,15 @@ int flow_accept(qosspec_t *             qs,          if (fd < 0)                  return fd; +        pthread_rwlock_wrlock(&ai.lock); + +        frcti_init(fd); +          if (qs != NULL)                  *qs = ai.flows[fd].spec; +        pthread_rwlock_unlock(&ai.lock); +          return fd;  } @@ -505,7 +824,7 @@ int flow_alloc(const char *            dst_name,                  return -EIRMD;          } -        if (recv_msg->result !=  0) { +        if (recv_msg->result != 0) {                  int res =  recv_msg->result;                  irm_msg__free_unpacked(recv_msg, NULL);                  return res; @@ -520,6 +839,22 @@ int flow_alloc(const char *            dst_name,          irm_msg__free_unpacked(recv_msg, NULL); +        if (fd < 0) +                return fd; + +        pthread_rwlock_wrlock(&ai.lock); + +        frcti_init(fd); + +        if (frcti_configure(fd, qs)) { +                flow_fini(fd); +                bmp_release(ai.fds, fd); +                pthread_rwlock_unlock(&ai.lock); +                return -1; +        } + +        pthread_rwlock_unlock(&ai.lock); +          return fd;  } @@ -720,34 +1055,31 @@ ssize_t flow_write(int          fd,                          return idx;                  } -                if (shm_rbuff_write(ai.flows[fd].tx_rb, idx) < 0) { -                        shm_rdrbuff_remove(ai.rdrb, idx); -                        pthread_rwlock_unlock(&ai.lock); -                        return -ENOTALLOC; -                }          } else { /* blocking */ -                struct shm_rdrbuff * rdrb = ai.rdrb; -                struct shm_rbuff * tx_rb  = ai.flows[fd].tx_rb; -                  pthread_rwlock_unlock(&ai.lock); -                assert(tx_rb); - -                idx = shm_rdrbuff_write_b(rdrb, +                idx = shm_rdrbuff_write_b(ai.rdrb,                                            DU_BUFF_HEADSPACE,                                            DU_BUFF_TAILSPACE,                                            buf,                                            count); -                if (shm_rbuff_write(tx_rb, idx) < 0) { -                        shm_rdrbuff_remove(rdrb, idx); -                        return -ENOTALLOC; -                } -                  pthread_rwlock_rdlock(&ai.lock);          } -        shm_flow_set_notify(ai.flows[fd].set, ai.flows[fd].port_id); +        if (!ai.frcti[fd].used) { +                if (finalize_write(fd, idx)) { +                        pthread_rwlock_unlock(&ai.lock); +                        shm_rdrbuff_remove(ai.rdrb, idx); +                        return -ENOTALLOC; +                } +        } else { +                if (frcti_write(fd, shm_rdrbuff_get(ai.rdrb, idx))) { +                        pthread_rwlock_unlock(&ai.lock); +                        shm_rdrbuff_remove(ai.rdrb, idx); +                        return -1; +                } +        }          pthread_rwlock_unlock(&ai.lock); @@ -772,21 +1104,12 @@ ssize_t flow_read(int    fd,                  return -ENOTALLOC;          } -        if (ai.flows[fd].oflags & FLOW_O_NONBLOCK) { -                idx = shm_rbuff_read(ai.flows[fd].rx_rb); -                pthread_rwlock_unlock(&ai.lock); -        } else { -                struct shm_rbuff * rb   = ai.flows[fd].rx_rb; -                bool timeo = ai.flows[fd].timesout; -                struct timespec timeout = ai.flows[fd].rcv_timeo; - -                pthread_rwlock_unlock(&ai.lock); +        pthread_rwlock_unlock(&ai.lock); -                if (timeo) -                        idx = shm_rbuff_read_b(rb, &timeout); -                else -                        idx = shm_rbuff_read_b(rb, NULL); -        } +        if (!ai.frcti[fd].used) +                idx = shm_rbuff_read(ai.flows[fd].rx_rb); +        else +                idx = frcti_read(fd);          if (idx < 0) {                  assert(idx == -EAGAIN || idx == -ETIMEDOUT); @@ -823,6 +1146,8 @@ struct flow_set * flow_set_create()                  return NULL;          } +        set->np1_set = false; +          pthread_rwlock_unlock(&ai.lock);          return set; @@ -891,6 +1216,9 @@ int flow_set_add(struct flow_set * set,          for (i = 0; i < sdus; i++)                  shm_flow_set_notify(ai.fqset, ai.flows[fd].port_id); +        if (ai.frcti[fd].used) +                set->np1_set = true; +          pthread_rwlock_unlock(&ai.lock);          return ret; @@ -960,7 +1288,9 @@ int flow_event_wait(struct flow_set *       set,                      struct fqueue *         fq,                      const struct timespec * timeout)  { -        ssize_t ret; +        ssize_t           ret; +        struct timespec   abstime; +        struct timespec * t = NULL;          if (set == NULL || fq == NULL)                  return -EINVAL; @@ -970,7 +1300,18 @@ int flow_event_wait(struct flow_set *       set,          assert(!fq->next); -        ret = shm_flow_set_wait(ai.fqset, set->idx, fq->fqueue, timeout); +        if (timeout != NULL) { +                clock_gettime(PTHREAD_COND_CLOCK, &abstime); +                ts_add(&abstime, timeout, &abstime); +                t = &abstime; +        } + +        if (set->np1_set) +                ret = frcti_event_wait(set, fq, t); +        else +                ret = shm_flow_set_wait(ai.fqset, set->idx, +                                        fq->fqueue, t); +          if (ret == -ETIMEDOUT) {                  fq->fqsize = 0;                  return -ETIMEDOUT; @@ -1132,9 +1473,8 @@ int ipcp_flow_read(int                   fd,  {          ssize_t idx = -1;          int port_id = -1; -        struct shm_rbuff * rb; -        assert(fd >=0); +        assert(fd >= 0);          assert(sdb);          pthread_rwlock_rdlock(&ai.lock); @@ -1144,11 +1484,13 @@ int ipcp_flow_read(int                   fd,                  return -ENOTALLOC;          } -        rb = ai.flows[fd].rx_rb; -          pthread_rwlock_unlock(&ai.lock); -        idx = shm_rbuff_read(rb); +        if (!ai.frcti[fd].used) +                idx = shm_rbuff_read(ai.flows[fd].rx_rb); +        else +                idx = frcti_read(fd); +          if (idx < 0)                  return idx; @@ -1160,8 +1502,6 @@ int ipcp_flow_read(int                   fd,  int ipcp_flow_write(int                  fd,                      struct shm_du_buff * sdb)  { -        size_t idx; -          if (sdb == NULL)                  return -EINVAL; @@ -1179,10 +1519,17 @@ int ipcp_flow_write(int                  fd,          assert(ai.flows[fd].tx_rb); -        idx = shm_du_buff_get_idx(sdb); - -        shm_rbuff_write(ai.flows[fd].tx_rb, idx); -        shm_flow_set_notify(ai.flows[fd].set, ai.flows[fd].port_id); +        if (!ai.frcti[fd].used) { +                if (finalize_write(fd, shm_du_buff_get_idx(sdb))) { +                        pthread_rwlock_unlock(&ai.lock); +                        return -ENOTALLOC; +                } +        } else { +                if (frcti_write(fd, sdb)) { +                        pthread_rwlock_unlock(&ai.lock); +                        return -1; +                } +        }          pthread_rwlock_unlock(&ai.lock); @@ -1274,32 +1621,11 @@ int local_flow_write(int    fd,                  return -ENOTALLOC;          } -        shm_rbuff_write(ai.flows[fd].tx_rb, idx); - -        shm_flow_set_notify(ai.flows[fd].set, ai.flows[fd].port_id); - -        pthread_rwlock_unlock(&ai.lock); - -        return 0; -} - -int ipcp_read_shim(int                   fd, -                   struct shm_du_buff ** sdb) -{ -        ssize_t idx; - -        pthread_rwlock_rdlock(&ai.lock); - -        assert(ai.flows[fd].rx_rb); - -        idx = shm_rbuff_read(ai.flows[fd].rx_rb); -        if (idx < 0) { +        if (finalize_write(fd, idx)) {                  pthread_rwlock_unlock(&ai.lock); -                return -EAGAIN; +                return -ENOTALLOC;          } -        *sdb = shm_rdrbuff_get(ai.rdrb, idx); -          pthread_rwlock_unlock(&ai.lock);          return 0; diff --git a/src/lib/frct_pci.c b/src/lib/frct_pci.c new file mode 100644 index 00000000..5ee14829 --- /dev/null +++ b/src/lib/frct_pci.c @@ -0,0 +1,112 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2017 + * + * Protocol Control Information of FRCT + * + *    Dimitri Staessens <dimitri.staessens@ugent.be> + *    Sander Vrijders   <sander.vrijders@ugent.be> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * version 2.1 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., http://www.fsf.org/about/contact/. + */ + +#include <ouroboros/frct_pci.h> +#include <ouroboros/hash.h> +#include <ouroboros/errno.h> + +#define OUROBOROS_PREFIX "frct-pci" +#include <ouroboros/logs.h> + +#include <assert.h> +#include <string.h> + +#define TYPE_SIZE  1 +#define SEQNO_SIZE 8 +#define FLAGS_SIZE 1 + +/* FIXME: Head size will differ on type */ +#define HEAD_SIZE TYPE_SIZE + FLAGS_SIZE + SEQNO_SIZE + +int frct_pci_ser(struct shm_du_buff * sdb, +                 struct frct_pci *    pci, +                 bool                 error_check) +{ +        uint8_t * head; +        uint8_t * tail; + +        assert(sdb); +        assert(pci); + +        head = shm_du_buff_head_alloc(sdb, HEAD_SIZE); +        if (head == NULL) +                return -EPERM; + +        memcpy(head, &pci->type, TYPE_SIZE); +        memcpy(head + TYPE_SIZE, &pci->flags, FLAGS_SIZE); +        memcpy(head + TYPE_SIZE + FLAGS_SIZE, &pci->seqno, SEQNO_SIZE); + +        if (error_check) { +                tail = shm_du_buff_tail_alloc(sdb, hash_len(HASH_CRC32)); +                if (tail == NULL) { +                        shm_du_buff_head_release(sdb, HEAD_SIZE); +                        return -EPERM; +                } + +                *((uint32_t *) tail) = 0; +                mem_hash(HASH_CRC32, (uint32_t *) tail, head, tail - head); +        } + +        return 0; +} + +int frct_pci_des(struct shm_du_buff * sdb, +                 struct frct_pci *    pci, +                 bool                 error_check) +{ +        uint8_t * head; +        uint8_t * tail; +        uint32_t  crc; +        uint32_t  crc2; + +        assert(sdb); +        assert(pci); + +        head = shm_du_buff_head(sdb); + +         /* FIXME: Depending on the type a different deserialization */ +        memcpy(&pci->type, head, TYPE_SIZE); +        memcpy(&pci->flags, head + TYPE_SIZE, FLAGS_SIZE); +        memcpy(&pci->seqno, head + TYPE_SIZE + FLAGS_SIZE, SEQNO_SIZE); + +        if (error_check) { +                tail = shm_du_buff_tail(sdb); +                if (tail == NULL) +                        return -EPERM; + +                mem_hash(HASH_CRC32, &crc, head, +                         tail - head - hash_len(HASH_CRC32)); + +                memcpy(&crc2, tail - hash_len(HASH_CRC32), +                       hash_len(HASH_CRC32)); + +                /* Corrupted SDU */ +                if (crc != crc2) +                        return -1; + +                shm_du_buff_tail_release(sdb, hash_len(HASH_CRC32)); +        } + +        shm_du_buff_head_release(sdb, HEAD_SIZE); + +        return 0; +} diff --git a/src/lib/hash.c b/src/lib/hash.c index d8cabfd3..09e5be8c 100644 --- a/src/lib/hash.c +++ b/src/lib/hash.c @@ -23,7 +23,8 @@   * Foundation, Inc., http://www.fsf.org/about/contact/.   */ -#include <ouroboros/config.h> +#include "config.h" +  #include <ouroboros/hash.h>  #ifndef HAVE_LIBGCRYPT @@ -64,45 +65,46 @@ uint16_t hash_len(enum hash_algo algo)  #endif  } -void str_hash(enum hash_algo algo, -              void *         buf, -              const char *   str) +void mem_hash(enum hash_algo  algo, +              void *          dst, +              const uint8_t * buf, +              size_t          len)  {  #ifdef HAVE_LIBGCRYPT -        gcry_md_hash_buffer(algo, buf, str, strlen(str)); +        gcry_md_hash_buffer(algo, dst, buf, len);  #else          struct sha3_ctx sha3_ctx;          struct md5_ctx md5_ctx;          switch (algo) {          case HASH_CRC32: -                memset(buf, 0, CRC32_HASH_LEN); -                crc32((uint32_t *) buf, str, strlen(str)); +                memset(dst, 0, CRC32_HASH_LEN); +                crc32((uint32_t *) dst, buf, len);                  break;          case HASH_MD5:                  rhash_md5_init(&md5_ctx); -                rhash_md5_update(&md5_ctx, str, strlen(str)); -                rhash_md5_final(&md5_ctx, (uint8_t *) buf); +                rhash_md5_update(&md5_ctx, buf, len); +                rhash_md5_final(&md5_ctx, (uint8_t *) dst);                  break;          case HASH_SHA3_224:                  rhash_sha3_224_init(&sha3_ctx); -                rhash_sha3_update(&sha3_ctx, str, strlen(str)); -                rhash_sha3_final(&sha3_ctx, (uint8_t *) buf); +                rhash_sha3_update(&sha3_ctx, buf, len); +                rhash_sha3_final(&sha3_ctx, (uint8_t *) dst);                  break;          case HASH_SHA3_256:                  rhash_sha3_256_init(&sha3_ctx); -                rhash_sha3_update(&sha3_ctx, str, strlen(str)); -                rhash_sha3_final(&sha3_ctx, (uint8_t *) buf); +                rhash_sha3_update(&sha3_ctx, buf, len); +                rhash_sha3_final(&sha3_ctx, (uint8_t *) dst);                  break;          case HASH_SHA3_384:                  rhash_sha3_384_init(&sha3_ctx); -                rhash_sha3_update(&sha3_ctx, str, strlen(str)); -                rhash_sha3_final(&sha3_ctx, (uint8_t *) buf); +                rhash_sha3_update(&sha3_ctx, buf, len); +                rhash_sha3_final(&sha3_ctx, (uint8_t *) dst);                  break;          case HASH_SHA3_512:                  rhash_sha3_512_init(&sha3_ctx); -                rhash_sha3_update(&sha3_ctx, str, strlen(str)); -                rhash_sha3_final(&sha3_ctx, (uint8_t *) buf); +                rhash_sha3_update(&sha3_ctx, buf, len); +                rhash_sha3_final(&sha3_ctx, (uint8_t *) dst);                  break;          default:                  assert(false); @@ -110,3 +112,10 @@ void str_hash(enum hash_algo algo,          }  #endif  } + +void str_hash(enum hash_algo algo, +              void *         dst, +              const char *   str) +{ +        return mem_hash(algo, dst, (const uint8_t *) str, strlen(str)); +} diff --git a/src/lib/irm.c b/src/lib/irm.c index a6075d33..4232cec1 100644 --- a/src/lib/irm.c +++ b/src/lib/irm.c @@ -20,7 +20,8 @@   * Foundation, Inc., http://www.fsf.org/about/contact/.   */ -#include <ouroboros/config.h> +#define _POSIX_C_SOURCE 200809L +  #include <ouroboros/errno.h>  #include <ouroboros/hash.h>  #include <ouroboros/irm.h> diff --git a/src/lib/lockfile.c b/src/lib/lockfile.c index e2e4d289..4a3dcb91 100644 --- a/src/lib/lockfile.c +++ b/src/lib/lockfile.c @@ -20,7 +20,10 @@   * Foundation, Inc., http://www.fsf.org/about/contact/.   */ -#include <ouroboros/config.h> +#define _POSIX_C_SOURCE 200112L + +#include "config.h" +  #include <ouroboros/lockfile.h>  #include <stdlib.h> @@ -47,7 +50,7 @@ struct lockfile * lockfile_create() {          mask = umask(0); -        fd = shm_open(LOCKFILE_NAME, O_CREAT | O_EXCL | O_RDWR, 0666); +        fd = shm_open(SHM_LOCKFILE_NAME, O_CREAT | O_EXCL | O_RDWR, 0666);          if (fd == -1) {                  free(lf);                  return NULL; @@ -69,7 +72,7 @@ struct lockfile * lockfile_create() {          close (fd);          if (lf->api == MAP_FAILED) { -                shm_unlink(LOCKFILE_NAME); +                shm_unlink(SHM_LOCKFILE_NAME);                  free(lf);                  return NULL;          } @@ -85,7 +88,7 @@ struct lockfile * lockfile_open() {          if (lf == NULL)                  return NULL; -        fd = shm_open(LOCKFILE_NAME, O_RDWR, 0666); +        fd = shm_open(SHM_LOCKFILE_NAME, O_RDWR, 0666);          if (fd < 0) {                  free(lf);                  return NULL; @@ -100,7 +103,7 @@ struct lockfile * lockfile_open() {          close(fd);          if (lf->api == MAP_FAILED) { -                shm_unlink(LOCKFILE_NAME); +                shm_unlink(SHM_LOCKFILE_NAME);                  free(lf);                  return NULL;          } @@ -126,7 +129,7 @@ void lockfile_destroy(struct lockfile * lf)          munmap(lf->api, LF_SIZE); -        shm_unlink(LOCKFILE_NAME); +        shm_unlink(SHM_LOCKFILE_NAME);          free(lf);  } diff --git a/src/lib/md5.c b/src/lib/md5.c index a4d92de3..3394f406 100644 --- a/src/lib/md5.c +++ b/src/lib/md5.c @@ -1,7 +1,7 @@  /*   * Ouroboros - Copyright (C) 2016 - 2017   * - * SHA3 algorithm + * MD5 algorithm   *   *    Dimitri Staessens <dimitri.staessens@ugent.be>   *    Sander Vrijders   <sander.vrijders@ugent.be> diff --git a/src/lib/nsm.c b/src/lib/nsm.c deleted file mode 100644 index 2dd5729b..00000000 --- a/src/lib/nsm.c +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Ouroboros - Copyright (C) 2016 - 2017 - * - * The API to instruct the global Namespace Manager - * - *    Dimitri Staessens <dimitri.staessens@ugent.be> - *    Sander Vrijders   <sander.vrijders@ugent.be> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * version 2.1 as published by the Free Software Foundation. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., http://www.fsf.org/about/contact/. - */ - -#include <ouroboros/nsm.h> - -int nsm_reg(char * name, -            char ** dafs, -            size_t dafs_size) -{ -        (void) name; -        (void) dafs; -        (void) dafs_size; - -        return -1; -} - -int nsm_unreg(char * name, -              char ** dafs, -              size_t dafs_size) -{ -        (void) name; -        (void) dafs; -        (void) dafs_size; - - -        return -1; -} - -ssize_t nsm_resolve(char * name, -                    char ** dafs) -{ -        (void) name; -        (void) dafs; - -        return -1; -} diff --git a/src/lib/random.c b/src/lib/random.c index 66aefaa3..27719b26 100644 --- a/src/lib/random.c +++ b/src/lib/random.c @@ -20,7 +20,8 @@   * Foundation, Inc., http://www.fsf.org/about/contact/.   */ -#include <ouroboros/config.h> +#include "config.h" +  #include <ouroboros/random.h>  #if defined(__APPLE__) /* Barf */ diff --git a/src/lib/rib.c b/src/lib/rib.c index e8cf97d4..104dc0cc 100644 --- a/src/lib/rib.c +++ b/src/lib/rib.c @@ -20,7 +20,10 @@   * Foundation, Inc., http://www.fsf.org/about/contact/.   */ -#include <ouroboros/config.h> +#define _POSIX_C_SOURCE 200809L + +#include "config.h" +  #include <ouroboros/errno.h>  #include <ouroboros/list.h>  #include <ouroboros/rib.h> diff --git a/src/lib/shm_flow_set.c b/src/lib/shm_flow_set.c index cd6946d4..78fdce36 100644 --- a/src/lib/shm_flow_set.c +++ b/src/lib/shm_flow_set.c @@ -20,7 +20,10 @@   * Foundation, Inc., http://www.fsf.org/about/contact/.   */ -#include <ouroboros/config.h> +#define _POSIX_C_SOURCE 200809L + +#include "config.h" +  #include <ouroboros/lockfile.h>  #include <ouroboros/time_utils.h>  #include <ouroboros/shm_flow_set.h> @@ -38,11 +41,22 @@  #include <string.h>  #include <assert.h> +/* + * pthread_cond_timedwait has a WONTFIX bug as of glibc 2.25 where it + * doesn't test pthread cancellation when passed an expired timeout + * with the clock set to CLOCK_MONOTONIC. + */ +#if ((defined(__linux__) || (defined(__MACH__) && !defined(__APPLE__)))        \ +     && (defined(__GLIBC__) && ((__GLIBC__ * 1000 + __GLIBC_MINOR__) >= 2025)) \ +     && (PTHREAD_COND_CLOCK == CLOCK_MONOTONIC)) +#define HAVE_CANCEL_BUG +#endif +  #define FN_MAX_CHARS 255  #define FQUEUESIZE ((SHM_BUFFER_SIZE) * sizeof(int)) -#define SHM_FLOW_SET_FILE_SIZE (IRMD_MAX_FLOWS * sizeof(ssize_t)          \ +#define SHM_FLOW_SET_FILE_SIZE (SYS_MAX_FLOWS * sizeof(ssize_t)           \                                  + AP_MAX_FQUEUES * sizeof(size_t)         \                                  + AP_MAX_FQUEUES * sizeof(pthread_cond_t) \                                  + AP_MAX_FQUEUES * FQUEUESIZE             \ @@ -109,7 +123,7 @@ struct shm_flow_set * shm_flow_set_create()          }          set->mtable  = shm_base; -        set->heads   = (size_t *) (set->mtable + IRMD_MAX_FLOWS); +        set->heads   = (size_t *) (set->mtable + SYS_MAX_FLOWS);          set->conds   = (pthread_cond_t *)(set->heads + AP_MAX_FQUEUES);          set->fqueues = (int *) (set->conds + AP_MAX_FQUEUES);          set->lock    = (pthread_mutex_t *) @@ -132,7 +146,7 @@ struct shm_flow_set * shm_flow_set_create()                  pthread_cond_init(&set->conds[i], &cattr);          } -        for (i = 0; i < IRMD_MAX_FLOWS; ++i) +        for (i = 0; i < SYS_MAX_FLOWS; ++i)                  set->mtable[i] = -1;          set->api = getpid(); @@ -175,7 +189,7 @@ struct shm_flow_set * shm_flow_set_open(pid_t api)          }          set->mtable  = shm_base; -        set->heads   = (size_t *) (set->mtable + IRMD_MAX_FLOWS); +        set->heads   = (size_t *) (set->mtable + SYS_MAX_FLOWS);          set->conds   = (pthread_cond_t *)(set->heads + AP_MAX_FQUEUES);          set->fqueues = (int *) (set->conds + AP_MAX_FQUEUES);          set->lock    = (pthread_mutex_t *) @@ -233,7 +247,7 @@ void shm_flow_set_zero(struct shm_flow_set * set,          pthread_mutex_lock(set->lock); -        for (i = 0; i < IRMD_MAX_FLOWS; ++i) +        for (i = 0; i < SYS_MAX_FLOWS; ++i)                  if (set->mtable[i] == (ssize_t) idx)                          set->mtable[i] = -1; @@ -248,7 +262,7 @@ int shm_flow_set_add(struct shm_flow_set * set,                       int                   port_id)  {          assert(set); -        assert(!(port_id < 0) && port_id < IRMD_MAX_FLOWS); +        assert(!(port_id < 0) && port_id < SYS_MAX_FLOWS);          assert(idx < AP_MAX_FQUEUES);          pthread_mutex_lock(set->lock); @@ -270,7 +284,7 @@ void shm_flow_set_del(struct shm_flow_set * set,                        int                   port_id)  {          assert(set); -        assert(!(port_id < 0) && port_id < IRMD_MAX_FLOWS); +        assert(!(port_id < 0) && port_id < SYS_MAX_FLOWS);          assert(idx < AP_MAX_FQUEUES);          pthread_mutex_lock(set->lock); @@ -288,7 +302,7 @@ int shm_flow_set_has(struct shm_flow_set * set,          int ret = 0;          assert(set); -        assert(!(port_id < 0) && port_id < IRMD_MAX_FLOWS); +        assert(!(port_id < 0) && port_id < SYS_MAX_FLOWS);          assert(idx < AP_MAX_FQUEUES);          pthread_mutex_lock(set->lock); @@ -305,7 +319,7 @@ void shm_flow_set_notify(struct shm_flow_set * set,                           int                   port_id)  {          assert(set); -        assert(!(port_id < 0) && port_id < IRMD_MAX_FLOWS); +        assert(!(port_id < 0) && port_id < SYS_MAX_FLOWS);          pthread_mutex_lock(set->lock); @@ -326,10 +340,9 @@ void shm_flow_set_notify(struct shm_flow_set * set,  ssize_t shm_flow_set_wait(const struct shm_flow_set * set,                            size_t                      idx,                            int *                       fqueue, -                          const struct timespec *     timeout) +                          const struct timespec *     abstime)  {          ssize_t ret = 0; -        struct timespec abstime;          assert(set);          assert(idx < AP_MAX_FQUEUES); @@ -341,22 +354,23 @@ ssize_t shm_flow_set_wait(const struct shm_flow_set * set,          if (pthread_mutex_lock(set->lock) == EOWNERDEAD)                  pthread_mutex_consistent(set->lock);  #endif -        if (timeout != NULL) { -                clock_gettime(PTHREAD_COND_CLOCK, &abstime); -                ts_add(&abstime, timeout, &abstime); -        }          pthread_cleanup_push((void(*)(void *))pthread_mutex_unlock,                               (void *) set->lock);          while (set->heads[idx] == 0 && ret != -ETIMEDOUT) { -                if (timeout != NULL) +                if (abstime != NULL) {                          ret = -pthread_cond_timedwait(set->conds + idx,                                                        set->lock, -                                                      &abstime); -                else +                                                      abstime); +#ifdef HAVE_CANCEL_BUG +                        if (ret == -ETIMEDOUT) +                                pthread_testcancel(); +#endif +                } else {                          ret = -pthread_cond_wait(set->conds + idx,                                                   set->lock); +                }  #ifdef HAVE_ROBUST_MUTEX                  if (ret == -EOWNERDEAD)                          pthread_mutex_consistent(set->lock); diff --git a/src/lib/shm_rbuff.c b/src/lib/shm_rbuff.c index 7f8af9f5..93108332 100644 --- a/src/lib/shm_rbuff.c +++ b/src/lib/shm_rbuff.c @@ -19,9 +19,12 @@   * License along with this library; if not, write to the Free Software   * Foundation, Inc., http://www.fsf.org/about/contact/.   */ -#include <ouroboros/config.h> -#if ((SHM_RBUFF_LOCKLESS > 0) &&                        \ +#define _POSIX_C_SOURCE 200809L + +#include "config.h" + +#if (defined(SHM_RBUFF_LOCKLESS) &&                            \       (defined(__GNUC__) || defined (__clang__)))  #include "shm_rbuff_ll.c"  #else diff --git a/src/lib/shm_rbuff_ll.c b/src/lib/shm_rbuff_ll.c index 33e236b0..ec0199c0 100644 --- a/src/lib/shm_rbuff_ll.c +++ b/src/lib/shm_rbuff_ll.c @@ -20,7 +20,8 @@   * Foundation, Inc., http://www.fsf.org/about/contact/.   */ -#include <ouroboros/config.h> +#include "config.h" +  #include <ouroboros/shm_rbuff.h>  #include <ouroboros/lockfile.h>  #include <ouroboros/time_utils.h> @@ -281,9 +282,8 @@ ssize_t shm_rbuff_read(struct shm_rbuff * rb)  }  ssize_t shm_rbuff_read_b(struct shm_rbuff *      rb, -                         const struct timespec * timeout) +                         const struct timespec * abstime)  { -        struct timespec abstime;          ssize_t idx = -1;          assert(rb); @@ -293,11 +293,6 @@ ssize_t shm_rbuff_read_b(struct shm_rbuff *      rb,          if (idx != -EAGAIN)                  return idx; -        if (timeout != NULL) { -                clock_gettime(PTHREAD_COND_CLOCK, &abstime); -                ts_add(&abstime, timeout, &abstime); -        } -  #ifndef HAVE_ROBUST_MUTEX          pthread_mutex_lock(rb->lock);  #else @@ -308,10 +303,10 @@ ssize_t shm_rbuff_read_b(struct shm_rbuff *      rb,                               (void *) rb->lock);          while (shm_rbuff_empty(rb) && (idx != -ETIMEDOUT)) { -                if (timeout != NULL) +                if (abstime != NULL)                          idx = -pthread_cond_timedwait(rb->add,                                                        rb->lock, -                                                      &abstime); +                                                      abstime);                  else                          idx = -pthread_cond_wait(rb->add, rb->lock);  #ifdef HAVE_ROBUST_MUTEX diff --git a/src/lib/shm_rbuff_pthr.c b/src/lib/shm_rbuff_pthr.c index 44001458..9567762f 100644 --- a/src/lib/shm_rbuff_pthr.c +++ b/src/lib/shm_rbuff_pthr.c @@ -20,7 +20,8 @@   * Foundation, Inc., http://www.fsf.org/about/contact/.   */ -#include <ouroboros/config.h> +#define _POSIX_C_SOURCE 200809L +  #include <ouroboros/shm_rbuff.h>  #include <ouroboros/lockfile.h>  #include <ouroboros/time_utils.h> @@ -284,18 +285,12 @@ ssize_t shm_rbuff_read(struct shm_rbuff * rb)  }  ssize_t shm_rbuff_read_b(struct shm_rbuff *      rb, -                         const struct timespec * timeout) +                         const struct timespec * abstime)  { -        struct timespec abstime;          ssize_t idx = -1;          assert(rb); -        if (timeout != NULL) { -                clock_gettime(PTHREAD_COND_CLOCK, &abstime); -                ts_add(&abstime, timeout, &abstime); -        } -  #ifndef HAVE_ROBUST_MUTEX          pthread_mutex_lock(rb->lock);  #else @@ -306,10 +301,10 @@ ssize_t shm_rbuff_read_b(struct shm_rbuff *      rb,                               (void *) rb->lock);          while (shm_rbuff_empty(rb) && (idx != -ETIMEDOUT)) { -                if (timeout != NULL) +                if (abstime != NULL)                          idx = -pthread_cond_timedwait(rb->add,                                                        rb->lock, -                                                      &abstime); +                                                      abstime);                  else                          idx = -pthread_cond_wait(rb->add, rb->lock);  #ifdef HAVE_ROBUST_MUTEX diff --git a/src/lib/shm_rdrbuff.c b/src/lib/shm_rdrbuff.c index 0919b1e0..447f8b35 100644 --- a/src/lib/shm_rdrbuff.c +++ b/src/lib/shm_rdrbuff.c @@ -20,7 +20,10 @@   * Foundation, Inc., http://www.fsf.org/about/contact/.   */ -#include <ouroboros/config.h> +#define _POSIX_C_SOURCE 200809L + +#include "config.h" +  #include <ouroboros/errno.h>  #include <ouroboros/shm_rdrbuff.h>  #include <ouroboros/shm_du_buff.h> diff --git a/src/lib/sockets.c b/src/lib/sockets.c index 7f0c4dd4..9f1b326e 100644 --- a/src/lib/sockets.c +++ b/src/lib/sockets.c @@ -20,7 +20,6 @@   * Foundation, Inc., http://www.fsf.org/about/contact/.   */ -#include <ouroboros/config.h>  #include <ouroboros/errno.h>  #include <ouroboros/sockets.h>  #include <ouroboros/utils.h> @@ -96,40 +95,32 @@ static void close_ptr(void * o)  irm_msg_t * send_recv_irm_msg(irm_msg_t * msg)  { -        int sockfd; -        buffer_t buf; -        ssize_t count = 0; -        irm_msg_t * recv_msg = NULL; +        int         sockfd; +        uint8_t     buf[IRM_MSG_BUF_SIZE]; +        ssize_t     len; +        irm_msg_t * recv_msg;          sockfd = client_socket_open(IRM_SOCK_PATH);          if (sockfd < 0)                  return NULL; -        buf.len = irm_msg__get_packed_size(msg); -        if (buf.len == 0) { -                close(sockfd); -                return NULL; -        } - -        buf.data = malloc(IRM_MSG_BUF_SIZE); -        if (buf.data == NULL) { +        len = irm_msg__get_packed_size(msg); +        if (len == 0) {                  close(sockfd);                  return NULL;          }          pthread_cleanup_push(close_ptr, &sockfd); -        pthread_cleanup_push((void (*)(void *)) free, (void *) buf.data); -        irm_msg__pack(msg, buf.data); +        irm_msg__pack(msg, buf); -        if (write(sockfd, buf.data, buf.len) != -1) -                count = read(sockfd, buf.data, IRM_MSG_BUF_SIZE); +        if (write(sockfd, buf, len) != -1) +                len = read(sockfd, buf, IRM_MSG_BUF_SIZE); -        if (count > 0) -                recv_msg = irm_msg__unpack(NULL, count, buf.data); +        if (len > 0) +                recv_msg = irm_msg__unpack(NULL, len, buf);          pthread_cleanup_pop(true); -        pthread_cleanup_pop(true);          return recv_msg;  } diff --git a/src/lib/tests/CMakeLists.txt b/src/lib/tests/CMakeLists.txt index 41c2074a..0223262a 100644 --- a/src/lib/tests/CMakeLists.txt +++ b/src/lib/tests/CMakeLists.txt @@ -1,6 +1,12 @@  get_filename_component(PARENT_PATH ${CMAKE_CURRENT_SOURCE_DIR} DIRECTORY)  get_filename_component(PARENT_DIR ${PARENT_PATH} NAME) +if (NOT (APPLE OR GNU)) +  set(TIMERWHEEL_TEST "timerwheel_test.c") +else () +  set(TIMERWHEEL_TEST "") +endif () +  create_test_sourcelist(${PARENT_DIR}_tests test_suite.c    # Add new tests here    bitmap_test.c @@ -11,6 +17,7 @@ create_test_sourcelist(${PARENT_DIR}_tests test_suite.c    rib_test.c    sha3_test.c    time_utils_test.c +  ${TIMERWHEEL_TEST}    )  add_executable(${PARENT_DIR}_test EXCLUDE_FROM_ALL ${${PARENT_DIR}_tests}) diff --git a/src/lib/tests/rib_test.c b/src/lib/tests/rib_test.c index e1fa427d..6a2446b9 100644 --- a/src/lib/tests/rib_test.c +++ b/src/lib/tests/rib_test.c @@ -20,7 +20,8 @@   * Foundation, Inc., http://www.fsf.org/about/contact/.   */ -#include <ouroboros/config.h> +#define _POSIX_C_SOURCE 199309L +  #include <ouroboros/time_utils.h>  #include <ouroboros/rib.h>  #include <ouroboros/rqueue.h> diff --git a/src/lib/tests/timerwheel_test.c b/src/lib/tests/timerwheel_test.c new file mode 100644 index 00000000..d7478487 --- /dev/null +++ b/src/lib/tests/timerwheel_test.c @@ -0,0 +1,104 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2017 + * + * Test of the timer wheel + * + *    Dimitri Staessens <dimitri.staessens@ugent.be> + *    Sander Vrijders   <sander.vrijders@ugent.be> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., http://www.fsf.org/about/contact/. + */ + +#include "timerwheel.c" + +#include <pthread.h> +#include <time.h> +#include <stdlib.h> +#include <stdio.h> + +#define MAX_ELEMENTS   100 +#define MAX_RESOLUTION 10  /* ms */ +#define MAX_ADDITIONS  1000 + +int total; + +int add(void * o) +{ +        total += *((int *) o); +        return 0; +} + +int timerwheel_test(int argc, char ** argv) +{ +        struct timerwheel * tw; +        long resolution; +        long elements; +        struct timespec wait; + +        int additions; + +        int check_total = 0; + +        int i; +        int var = 5; + +        struct tw_f * f; + +        (void) argc; +        (void) argv; + +        total = 0; + +        srand(time(NULL)); + +        resolution = rand() % (MAX_RESOLUTION - 1) + 1; +        elements = rand() % (MAX_ELEMENTS - 10) + 10; + +        tw = timerwheel_create(resolution, resolution * elements); +        if (tw == NULL) { +                printf("Failed to create timerwheel.\n"); +                return -1; +        } + +        wait.tv_sec = (resolution * elements) / 1000; +        wait.tv_nsec = ((resolution * elements) % 1000) * MILLION; + +        additions = rand() % MAX_ADDITIONS + 1000; + +        for (i = 0; i < additions; ++i) { +                int delay = rand() % (resolution * elements); +                check_total += var; +                f = timerwheel_start(tw, +                                     (void (*)(void *)) add, +                                     (void *) &var, +                                     delay); +                if (f == NULL) { +                        printf("Failed to add function."); +                        return -1; +                } +        } + +        nanosleep(&wait, NULL); + +        timerwheel_move(tw); + +        timerwheel_destroy(tw); + +        if (total != check_total) { +                printf("Totals do not match: %d and %d.\n", total, check_total); +                return -1; +        } + +        return 0; +} diff --git a/src/lib/time_utils.c b/src/lib/time_utils.c index 2dec4524..22937d4b 100644 --- a/src/lib/time_utils.c +++ b/src/lib/time_utils.c @@ -20,7 +20,8 @@   * Foundation, Inc., http://www.fsf.org/about/contact/.   */ -#include <ouroboros/config.h> +#define _POSIX_C_SOURCE 199309L +  #include <ouroboros/time_utils.h>  #include <stddef.h> diff --git a/src/lib/timerwheel.c b/src/lib/timerwheel.c new file mode 100644 index 00000000..2952c5d3 --- /dev/null +++ b/src/lib/timerwheel.c @@ -0,0 +1,232 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2017 + * + * Timerwheel + * + *    Dimitri Staessens <dimitri.staessens@ugent.be> + *    Sander Vrijders   <sander.vrijders@ugent.be> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * version 2.1 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., http://www.fsf.org/about/contact/. + */ + +#define _POSIX_C_SOURCE 200112L + +#include "config.h" + +#include <ouroboros/time_utils.h> +#include <ouroboros/errno.h> +#include <ouroboros/list.h> + +#include <pthread.h> +#include <stdlib.h> +#include <assert.h> +#include <string.h> + +#define FRAC 10 /* accuracy of the timer */ + +#define tw_used(tw) ((tw->head + tw->elements - tw->tail) & (tw->elements - 1)); +#define tw_free(tw) (tw_used(tw) + 1 < tw->elements) +#define tw_empty(tw) (tw->head == tw->tail) + +struct tw_f { +        struct list_head next; +        void (* func)(void *); +        void * arg; +}; + +struct tw_el { +        struct list_head funcs; +        struct timespec  expiry; +}; + +struct timerwheel { +        struct tw_el *   wheel; + +        struct timespec  intv; + +        size_t           pos; + +        pthread_mutex_t  lock; + +        time_t           resolution; +        unsigned int     elements; +}; + +static void tw_el_fini(struct tw_el * e) +{ +        struct list_head * p; +        struct list_head * h; + +        list_for_each_safe(p, h, &e->funcs) { +                struct tw_f * f = list_entry(p, struct tw_f, next); +                list_del(&f->next); +        } +} + +void timerwheel_move(struct timerwheel * tw) +{ +        struct timespec now = {0, 0}; +        long ms = tw->resolution * tw->elements; +        struct timespec total = {ms / 1000, +                                 (ms % 1000) * MILLION}; +        struct list_head * p; +        struct list_head * h; + +        clock_gettime(CLOCK_MONOTONIC, &now); + +        pthread_mutex_lock(&tw->lock); + +        while (ts_diff_us(&tw->wheel[tw->pos].expiry, &now) > 0) { +                list_for_each_safe(p, h, &tw->wheel[tw->pos].funcs) { +                        struct tw_f * f = list_entry(p, struct tw_f, next); +                        list_del(&f->next); +                        f->func(f->arg); +                        free(f); +                } + +                ts_add(&tw->wheel[tw->pos].expiry, +                       &total, +                       &tw->wheel[tw->pos].expiry); + +                tw->pos = (tw->pos + 1) & (tw->elements - 1); +        } + +        pthread_mutex_unlock(&tw->lock); +} + +struct timerwheel * timerwheel_create(time_t resolution, +                                      time_t max_delay) +{ +        struct timespec now = {0, 0}; +        struct timespec res_ts = {resolution / 1000, +                                  (resolution % 1000) * MILLION}; +        unsigned long i; + +        struct timerwheel * tw; + +        assert(resolution != 0); + +        tw = malloc(sizeof(*tw)); +        if (tw == NULL) +                return NULL; + +        if (pthread_mutex_init(&tw->lock, NULL)) +                return NULL; + +        tw->elements = 1; + +        while (tw->elements < max_delay / resolution) +                tw->elements <<= 1; + +        tw->wheel = malloc(sizeof(*tw->wheel) * tw->elements); +        if (tw->wheel == NULL) +                goto fail_wheel_malloc; + +        tw->resolution = resolution; + +        tw->intv.tv_sec = (tw->resolution / FRAC) / 1000; +        tw->intv.tv_nsec = ((tw->resolution / FRAC) % 1000) * MILLION; + +        if (pthread_mutex_init(&tw->lock, NULL)) +                goto fail_lock_init; + +        tw->pos = 0; + +        clock_gettime(CLOCK_MONOTONIC, &now); +        now.tv_nsec -= (now.tv_nsec % MILLION); + +        for (i = 0; i < tw->elements; ++i) { +                list_head_init(&tw->wheel[i].funcs); +                tw->wheel[i].expiry = now; +                ts_add(&now, &res_ts, &now); +        } + +        return tw; + + fail_lock_init: +         free(tw->wheel); + fail_wheel_malloc: +         free(tw); +         return NULL; +} + +void timerwheel_destroy(struct timerwheel * tw) +{ +        unsigned long i; + +        for (i = 0; i < tw->elements; ++i) +                tw_el_fini(&tw->wheel[i]); + +        pthread_mutex_destroy(&tw->lock); +        free(tw->wheel); +        free(tw); +} + +struct tw_f * timerwheel_start(struct timerwheel * tw, +                               void (* func)(void *), +                               void *              arg, +                               time_t              delay) +{ +        int pos; +        struct tw_f * f = malloc(sizeof(*f)); +        if (f == NULL) +                return NULL; + +        f->func = func; +        f->arg = arg; + +        assert(delay < tw->elements * tw->resolution); + +        pthread_mutex_lock(&tw->lock); + +        pos = (tw->pos + delay / tw->resolution) & (tw->elements - 1); +        list_add(&f->next, &tw->wheel[pos].funcs); + +        pthread_mutex_unlock(&tw->lock); + +        return f; +} + +int timerwheel_restart(struct timerwheel * tw, +                       struct tw_f *       f, +                       time_t              delay) +{ +        int pos; + +        assert(tw); +        assert(delay < tw->elements * tw->resolution); + +        pthread_mutex_lock(&tw->lock); + +        list_del(&f->next); +        pos = (tw->pos + delay / tw->resolution) & (tw->elements - 1); +        list_add(&f->next, &tw->wheel[pos].funcs); + +        pthread_mutex_unlock(&tw->lock); + +        return 0; +} + +void timerwheel_stop(struct timerwheel * tw, +                     struct tw_f *       f) +{ +        assert(tw); + +        pthread_mutex_lock(&tw->lock); + +        list_del(&f->next); +        free(f); + +        pthread_mutex_unlock(&tw->lock); +} diff --git a/src/lib/tpm.c b/src/lib/tpm.c index 739996c4..dd71d276 100644 --- a/src/lib/tpm.c +++ b/src/lib/tpm.c @@ -20,7 +20,10 @@   * Foundation, Inc., http://www.fsf.org/about/contact/.   */ -#include <ouroboros/config.h> +#define _POSIX_C_SOURCE 200112L + +#include "config.h" +  #include <ouroboros/errno.h>  #include <ouroboros/list.h>  #include <ouroboros/time_utils.h>  | 
