| /* |
| * shctx.h - shared context management functions for SSL |
| * |
| * Copyright (C) 2011-2012 EXCELIANCE |
| * |
| * Author: Emeric Brun - emeric@exceliance.fr |
| * |
| * This program is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU General Public License |
| * as published by the Free Software Foundation; either version |
| * 2 of the License, or (at your option) any later version. |
| */ |
| |
| #ifndef SHCTX_H |
| #define SHCTX_H |
| |
| #include <common/mini-clist.h> |
| #include <types/shctx.h> |
| |
| #include <inttypes.h> |
| |
| #ifndef USE_PRIVATE_CACHE |
| #ifdef USE_PTHREAD_PSHARED |
| #include <pthread.h> |
| #else |
| #ifdef USE_SYSCALL_FUTEX |
| #include <unistd.h> |
| #include <linux/futex.h> |
| #include <sys/syscall.h> |
| #endif |
| #endif |
| #else |
| #include <common/hathreads.h> |
| #endif |
| |
| int shctx_init(struct shared_context **orig_shctx, |
| int maxblocks, int blocksize, unsigned int maxobjsz, |
| int extra, int shared); |
| struct shared_block *shctx_row_reserve_hot(struct shared_context *shctx, |
| struct shared_block *last, int data_len); |
| void shctx_row_inc_hot(struct shared_context *shctx, struct shared_block *first); |
| void shctx_row_dec_hot(struct shared_context *shctx, struct shared_block *first); |
| int shctx_row_data_append(struct shared_context *shctx, |
| struct shared_block *first, struct shared_block *from, |
| unsigned char *data, int len); |
| int shctx_row_data_get(struct shared_context *shctx, struct shared_block *first, |
| unsigned char *dst, int offset, int len); |
| |
| |
| /* Lock functions */ |
| |
| #if defined (USE_PRIVATE_CACHE) |
| extern int use_shared_mem; |
| |
| #define shctx_lock(shctx) if (use_shared_mem) HA_SPIN_LOCK(SHCTX_LOCK, &shctx->lock) |
| #define shctx_unlock(shctx) if (use_shared_mem) HA_SPIN_UNLOCK(SHCTX_LOCK, &shctx->lock) |
| |
| #elif defined (USE_PTHREAD_PSHARED) |
| extern int use_shared_mem; |
| |
| #define shctx_lock(shctx) if (use_shared_mem) pthread_mutex_lock(&shctx->mutex) |
| #define shctx_unlock(shctx) if (use_shared_mem) pthread_mutex_unlock(&shctx->mutex) |
| |
| #else |
| extern int use_shared_mem; |
| |
| #ifdef USE_SYSCALL_FUTEX |
| static inline void _shctx_wait4lock(unsigned int *count, unsigned int *uaddr, int value) |
| { |
| syscall(SYS_futex, uaddr, FUTEX_WAIT, value, NULL, 0, 0); |
| } |
| |
| static inline void _shctx_awakelocker(unsigned int *uaddr) |
| { |
| syscall(SYS_futex, uaddr, FUTEX_WAKE, 1, NULL, 0, 0); |
| } |
| |
| #else /* internal spin lock */ |
| |
| #if defined (__i486__) || defined (__i586__) || defined (__i686__) || defined (__x86_64__) |
| static inline void relax() |
| { |
| __asm volatile("rep;nop\n" ::: "memory"); |
| } |
| #else /* if no x86_64 or i586 arch: use less optimized but generic asm */ |
| static inline void relax() |
| { |
| __asm volatile("" ::: "memory"); |
| } |
| #endif |
| |
| static inline void _shctx_wait4lock(unsigned int *count, unsigned int *uaddr, int value) |
| { |
| int i; |
| |
| for (i = 0; i < *count; i++) { |
| relax(); |
| relax(); |
| if (*uaddr != value) |
| return; |
| } |
| *count = (unsigned char)((*count << 1) + 1); |
| } |
| |
| #define _shctx_awakelocker(a) |
| |
| #endif |
| |
| #if defined (__i486__) || defined (__i586__) || defined (__i686__) || defined (__x86_64__) |
| static inline unsigned int xchg(unsigned int *ptr, unsigned int x) |
| { |
| __asm volatile("lock xchgl %0,%1" |
| : "=r" (x), "+m" (*ptr) |
| : "0" (x) |
| : "memory"); |
| return x; |
| } |
| |
| static inline unsigned int cmpxchg(unsigned int *ptr, unsigned int old, unsigned int new) |
| { |
| unsigned int ret; |
| |
| __asm volatile("lock cmpxchgl %2,%1" |
| : "=a" (ret), "+m" (*ptr) |
| : "r" (new), "0" (old) |
| : "memory"); |
| return ret; |
| } |
| |
| static inline unsigned char atomic_dec(unsigned int *ptr) |
| { |
| unsigned char ret; |
| __asm volatile("lock decl %0\n" |
| "setne %1\n" |
| : "+m" (*ptr), "=qm" (ret) |
| : |
| : "memory"); |
| return ret; |
| } |
| |
| #else /* if no x86_64 or i586 arch: use less optimized gcc >= 4.1 built-ins */ |
| static inline unsigned int xchg(unsigned int *ptr, unsigned int x) |
| { |
| return __sync_lock_test_and_set(ptr, x); |
| } |
| |
| static inline unsigned int cmpxchg(unsigned int *ptr, unsigned int old, unsigned int new) |
| { |
| return __sync_val_compare_and_swap(ptr, old, new); |
| } |
| |
| static inline unsigned char atomic_dec(unsigned int *ptr) |
| { |
| return __sync_sub_and_fetch(ptr, 1) ? 1 : 0; |
| } |
| |
| #endif |
| |
| static inline void _shctx_lock(struct shared_context *shctx) |
| { |
| unsigned int x; |
| unsigned int count = 3; |
| |
| x = cmpxchg(&shctx->waiters, 0, 1); |
| if (x) { |
| if (x != 2) |
| x = xchg(&shctx->waiters, 2); |
| |
| while (x) { |
| _shctx_wait4lock(&count, &shctx->waiters, 2); |
| x = xchg(&shctx->waiters, 2); |
| } |
| } |
| } |
| |
| static inline void _shctx_unlock(struct shared_context *shctx) |
| { |
| if (atomic_dec(&shctx->waiters)) { |
| shctx->waiters = 0; |
| _shctx_awakelocker(&shctx->waiters); |
| } |
| } |
| |
| #define shctx_lock(shctx) if (use_shared_mem) _shctx_lock(shctx) |
| |
| #define shctx_unlock(shctx) if (use_shared_mem) _shctx_unlock(shctx) |
| |
| #endif |
| |
| /* List Macros */ |
| |
| /* |
| * Insert <s> block after <head> which is not necessarily the head of a list, |
| * so between <head> and the next element after <head>. |
| */ |
| static inline void shctx_block_append_hot(struct shared_context *shctx, |
| struct list *head, |
| struct shared_block *s) |
| { |
| shctx->nbav--; |
| LIST_DEL(&s->list); |
| LIST_ADD(head, &s->list); |
| } |
| |
| static inline void shctx_block_set_hot(struct shared_context *shctx, |
| struct shared_block *s) |
| { |
| shctx->nbav--; |
| LIST_DEL(&s->list); |
| LIST_ADDQ(&shctx->hot, &s->list); |
| } |
| |
| static inline void shctx_block_set_avail(struct shared_context *shctx, |
| struct shared_block *s) |
| { |
| shctx->nbav++; |
| LIST_DEL(&s->list); |
| LIST_ADDQ(&shctx->avail, &s->list); |
| } |
| |
| #endif /* SHCTX_H */ |
| |