blob: 4f8c23f7f8ff4b4440e17e14836c49d078aadfa5 [file] [log] [blame]
/*
* include/haproxy/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 __HAPROXY_SHCTX_H
#define __HAPROXY_SHCTX_H
#include <haproxy/api.h>
#include <haproxy/list.h>
#include <haproxy/shctx-t.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 <haproxy/thread.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_DELETE(&s->list);
LIST_INSERT(head, &s->list);
}
static inline void shctx_block_set_hot(struct shared_context *shctx,
struct shared_block *s)
{
shctx->nbav--;
LIST_DELETE(&s->list);
LIST_APPEND(&shctx->hot, &s->list);
}
static inline void shctx_block_set_avail(struct shared_context *shctx,
struct shared_block *s)
{
shctx->nbav++;
LIST_DELETE(&s->list);
LIST_APPEND(&shctx->avail, &s->list);
}
#endif /* __HAPROXY_SHCTX_H */