Module: sip-router
Branch: andrei/tcp_tls_changes
Commit: c38de320d864507b38d6f99beb649fef9211a3cf
URL: http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=c38de32…
Author: Andrei Pelinescu-Onciul <andrei(a)iptel.org>
Committer: Andrei Pelinescu-Onciul <andrei(a)iptel.org>
Date: Thu May 20 16:26:22 2010 +0200
tls: clear text write queue implementation
In some cases the not-yet-encrypted data must be queued on write
and the write retried later (e.g. a SSL_write returns WANT_READ
because of an ongoing re-keying or trying to write while the SSL
connection is not yet fully established).
---
modules/tls/tls_ct_q.h | 131 ++++++++++++++++++++++++++++++++++++
modules/tls/tls_ct_wrq.c | 164 ++++++++++++++++++++++++++++++++++++++++++++++
modules/tls/tls_ct_wrq.h | 53 +++++++++++++++
3 files changed, 348 insertions(+), 0 deletions(-)
Diff: http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commitdiff;h=c38…
Module: sip-router
Branch: andrei/tcp_tls_changes
Commit: c914809c9f70fe15d1a2459fa0668d722d83726c
URL: http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=c914809…
Author: Andrei Pelinescu-Onciul <andrei(a)iptel.org>
Committer: Andrei Pelinescu-Onciul <andrei(a)iptel.org>
Date: Thu May 20 16:22:16 2010 +0200
tls: added a minimum overhead shm buffer queue
Minimum overhead buffer queue in shm memory, based on
tcp_wbuffer_queue (tcp_conn.h).
---
modules/tls/sbufq.h | 292 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 292 insertions(+), 0 deletions(-)
diff --git a/modules/tls/sbufq.h b/modules/tls/sbufq.h
new file mode 100644
index 0000000..6b59751
--- /dev/null
+++ b/modules/tls/sbufq.h
@@ -0,0 +1,292 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2010 iptelorg GmbH
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/** minimal overhead buffer queue in shm memory.
+ * @file modules/tls/sbufq.h
+ * @ingroup: tls
+ * Module: @ref tls
+ */
+/*
+ * History:
+ * --------
+ * 2010-03-31 initial version, based on tcp_conn.h tcp_wbuffer_queue (andrei)
+*/
+
+#ifndef __sbufq_h
+#define __sbufq_h
+
+#include "../../compiler_opt.h"
+#include "../../ut.h"
+#include "../../mem/shm_mem.h"
+#include "../../timer_ticks.h"
+#include "../../timer.h"
+#include "../../dprint.h"
+#include <string.h>
+
+
+struct sbuf_elem {
+ struct sbuf_elem* next;
+ unsigned int b_size; /**< buf size */
+ char buf[1]; /**< variable size buffer */
+};
+
+struct sbuffer_queue {
+ struct sbuf_elem* first;
+ struct sbuf_elem* last;
+ ticks_t last_chg; /**< last change (creation time or partial flush)*/
+ unsigned int queued; /**< total size */
+ unsigned int offset; /**< offset in the first buffer where unflushed data
+ starts */
+ unsigned int last_used; /**< how much of the last buffer is used */
+};
+
+
+/* sbufq_flush() output flags */
+#define F_BUFQ_EMPTY 1
+#define F_BUFQ_ERROR_FLUSH 2
+
+
+#define sbufq_empty(bq) ((bq)->first==0)
+#define sbufq_non_empty(bq) ((bq)->first!=0)
+
+
+
+/** adds/appends data to a buffer queue.
+ * WARNING: it does no attempt to synchronize access/lock. If needed it should
+ * be called under lock.
+ * @param q - buffer queue
+ * @param data
+ * @param size
+ * @param min_buf_size - min size to allocate for new buffer elements
+ * @return 0 on success, -1 on error (mem. allocation)
+ */
+inline static int sbufq_add(struct sbuffer_queue* q, const void* data,
+ unsigned int size, unsigned int min_buf_size)
+{
+ struct sbuf_elem* b;
+ unsigned int last_free;
+ unsigned int b_size;
+ unsigned int crt_size;
+ ticks_t t;
+
+ t=get_ticks_raw();
+
+ if (likely(q->last==0)) {
+ b_size=MAX_unsigned(min_buf_size, size);
+ b=shm_malloc(sizeof(*b)+b_size-sizeof(b->buf));
+ if (unlikely(b==0))
+ goto error;
+ b->b_size=b_size;
+ b->next=0;
+ q->last=b;
+ q->first=b;
+ q->last_used=0;
+ q->offset=0;
+ q->last_chg=get_ticks_raw();
+ last_free=b_size;
+ crt_size=size;
+ goto data_cpy;
+ }else{
+ b=q->last;
+ }
+
+ while(size){
+ last_free=b->b_size-q->last_used;
+ if (last_free==0){
+ b_size=MAX_unsigned(min_buf_size, size);
+ b=shm_malloc(sizeof(*b)+b_size-sizeof(b->buf));
+ if (unlikely(b==0))
+ goto error;
+ b->b_size=b_size;
+ b->next=0;
+ q->last->next=b;
+ q->last=b;
+ q->last_used=0;
+ last_free=b->b_size;
+ }
+ crt_size=MIN_unsigned(last_free, size);
+data_cpy:
+ memcpy(b->buf+q->last_used, data, crt_size);
+ q->last_used+=crt_size;
+ size-=crt_size;
+ data+=crt_size;
+ q->queued+=crt_size;
+ }
+ return 0;
+error:
+ return -1;
+}
+
+
+
+/** inserts data (at the beginning) in a buffer queue.
+ * Note: should never be called after sbufq_run().
+ * WARNING: it does no attempt to synchronize access/lock. If needed it should
+ * be called under lock.
+ * @param q - buffer queue
+ * @param data
+ * @param size
+ * @param min_buf_size - min size to allocate for new buffer elements
+ * @return 0 on success, -1 on error (mem. allocation)
+ */
+inline static int sbufq_insert(struct sbuffer_queue* q, const void* data,
+ unsigned int size, unsigned int min_buf_size)
+{
+ struct sbuf_elem* b;
+
+ if (likely(q->first==0)) /* if empty, use sbufq_add */
+ return sbufq_add(q, data, size, min_buf_size);
+
+ if (unlikely(q->offset)){
+ LOG(L_CRIT, "BUG: non-null offset %d (bad call, should"
+ "never be called after sbufq_run())\n", q->offset);
+ goto error;
+ }
+ if ((q->first==q->last) && ((q->last->b_size-q->last_used)>=size)){
+ /* one block with enough space in it for size bytes */
+ memmove(q->first->buf+size, q->first->buf, size);
+ memcpy(q->first->buf, data, size);
+ q->last_used+=size;
+ }else{
+ /* create a size bytes block directly */
+ b=shm_malloc(sizeof(*b)+size-sizeof(b->buf));
+ if (unlikely(b==0))
+ goto error;
+ b->b_size=size;
+ /* insert it */
+ b->next=q->first;
+ q->first=b;
+ memcpy(b->buf, data, size);
+ }
+
+ q->queued+=size;
+ return 0;
+error:
+ return -1;
+}
+
+
+/** destroy a buffer queue.
+ * Only the content is destroyed (shm_free()'d), the queue head is
+ * re-intialized.
+ * WARNING: it does no attempt to synchronize access/lock. If needed it should
+ * be called under lock.
+ * @param q - buffer queue
+ * @return - number of bytes that used to be queued (>=0).
+ */
+inline static unsigned int sbufq_destroy(struct sbuffer_queue* q)
+{
+ struct sbuf_elem* b;
+ struct sbuf_elem* next_b;
+ int unqueued;
+
+ unqueued=0;
+ if (likely(q->first)){
+ b=q->first;
+ do{
+ next_b=b->next;
+ unqueued+=(b==q->last)?q->last_used:b->b_size;
+ if (b==q->first)
+ unqueued-=q->offset;
+ shm_free(b);
+ b=next_b;
+ }while(b);
+ }
+ memset(q, 0, sizeof(*q));
+ return unqueued;
+}
+
+
+
+/** tries to flush the queue.
+ * Tries to flush as much as possible from the given queue, using the
+ * given callback.
+ * WARNING: it does no attempt to synchronize access/lock. If needed it should
+ * be called under lock.
+ * @param q - buffer queue
+ * @param *flags - set to:
+ * F_BUFQ_EMPTY if the queued is completely flushed
+ * F_BUFQ_ERROR_FLUSH if the flush_f callback returned error.
+ * @param flush_f - flush function (callback). modeled after write():
+ * flush_f(param1, param2, const void* buf, unsigned size).
+ * It should return the number of bytes "flushed" on
+ * success, or <0 on error. If the number of bytes
+ * "flushed" is smaller then the requested size, it
+ * would be assumed that no more bytes can be flushed
+ * and sbufq_flush will exit.
+ * @param flush_p1 - parameter for the flush function callback.
+ * @param flush_p2 - parameter for the flush function callback.
+ * @return -1 on internal error, or the number of bytes flushed on
+ * success (>=0). Note that the flags param is
+ * always set and it should be used to check for errors, since
+ * a flush_f() failure will not result in a negative return.
+ */
+inline static int sbufq_flush(struct sbuffer_queue* q, int* flags,
+ int (*flush_f)(void* p1, void* p2,
+ const void* buf,
+ unsigned size),
+ void* flush_p1, void* flush_p2)
+{
+ struct sbuf_elem *b;
+ int n;
+ int ret;
+ int block_size;
+ char* buf;
+
+ *flags=0;
+ ret=0;
+ while(q->first){
+ block_size=((q->first==q->last)?q->last_used:q->first->b_size)-
+ q->offset;
+ buf=q->first->buf+q->offset;
+ n=flush_f(flush_p1, flush_p2, buf, block_size);
+ if (likely(n>0)){
+ ret+=n;
+ if (likely(n==block_size)){
+ b=q->first;
+ q->first=q->first->next;
+ shm_free(b);
+ q->offset=0;
+ q->queued-=block_size;
+ ret+=block_size;
+ }else{
+ q->offset+=n;
+ q->queued-=n;
+ ret+=n;
+ break;
+ }
+ }else{
+ if (unlikely(n<0))
+ *flags|=F_BUFQ_ERROR_FLUSH;
+ break;
+ }
+ }
+ if (likely(q->first==0)){
+ q->last=0;
+ q->last_used=0;
+ q->offset=0;
+ *flags|=F_BUFQ_EMPTY;
+ }
+ return ret;
+}
+
+
+
+
+#endif /*__sbufq_h*/
+
+/* vi: set ts=4 sw=4 tw=79:ai:cindent: */
Module: sip-router
Branch: andrei/tcp_tls_changes
Commit: ce51fbb84e56921030b62d8617db2365ad934b51
URL: http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=ce51fbb…
Author: Andrei Pelinescu-Onciul <andrei(a)iptel.org>
Committer: Andrei Pelinescu-Onciul <andrei(a)iptel.org>
Date: Thu May 20 16:00:29 2010 +0200
tcp: new tls hooks interface and async tls changes
- new tls hooks interface that better accommodates tls async use.
Changed read() (takes an extra flags parameter now), removed
blocking_write() and fix_read_con(), added do_send() and
fst_send() (both of them handle snd_flags now and might return a
command that should be sent to tcp_main).
- more tcp send functions (tcpconn_1st_send(),
tcpconn_send_unsafe()) and more send functions exported
(tls_int_send.h) for use from the tls module.
- split tcp_read() into tcp_read() and tcp_read_data() and
exported tcp_read_data() (tcp_read.h).
- support for repeating a tcp_read() if indicated
(RD_CONN_REPEAT_READ), needed for tls.
---
tcp_int_send.h | 50 +++++
tcp_main.c | 651 ++++++++++++++++++++++++++++++++------------------------
tcp_read.c | 144 ++++++++-----
tcp_read.h | 46 ++++
tls_hooks.h | 31 ++--
5 files changed, 579 insertions(+), 343 deletions(-)
Diff: http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commitdiff;h=ce5…
Module: sip-router
Branch: master
Commit: 7ee950eb3e34dc0cdb3e825fa347dd29e7526afc
URL: http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=7ee950e…
Author: Miklos Tirpak <miklos(a)iptel.org>
Committer: Miklos Tirpak <miklos(a)iptel.org>
Date: Wed May 19 11:53:19 2010 +0200
core: bit conting and testing functions
new functions for bit operations:
- bit_count()
- bit_test()
- bit_test_and_set()
---
bit_count.c | 44 +++++++++++++++++++++
bit_count.h | 101 +++++++++++++++++++++++++++++++++++++++++++++++++
bit_test.h | 121 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 266 insertions(+), 0 deletions(-)
diff --git a/bit_count.c b/bit_count.c
new file mode 100644
index 0000000..faef43c
--- /dev/null
+++ b/bit_count.c
@@ -0,0 +1,44 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2010 iptelorg GmbH
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * History
+ * -------
+ * 2010-04-26 Initial version (Miklos)
+ */
+
+#include "bit_count.h"
+
+#if 0
+/* number of bits in a byte */
+int bits_in_char[256] = {
+ 0 ,1 ,1 ,2 ,1 ,2 ,2 ,3 ,1 ,2 ,2 ,3 ,2 ,3 ,3 ,4 ,
+ 1 ,2 ,2 ,3 ,2 ,3 ,3 ,4 ,2 ,3 ,3 ,4 ,3 ,4 ,4 ,5 ,
+ 1 ,2 ,2 ,3 ,2 ,3 ,3 ,4 ,2 ,3 ,3 ,4 ,3 ,4 ,4 ,5 ,
+ 2 ,3 ,3 ,4 ,3 ,4 ,4 ,5 ,3 ,4 ,4 ,5 ,4 ,5 ,5 ,6 ,
+ 1 ,2 ,2 ,3 ,2 ,3 ,3 ,4 ,2 ,3 ,3 ,4 ,3 ,4 ,4 ,5 ,
+ 2 ,3 ,3 ,4 ,3 ,4 ,4 ,5 ,3 ,4 ,4 ,5 ,4 ,5 ,5 ,6 ,
+ 2 ,3 ,3 ,4 ,3 ,4 ,4 ,5 ,3 ,4 ,4 ,5 ,4 ,5 ,5 ,6 ,
+ 3 ,4 ,4 ,5 ,4 ,5 ,5 ,6 ,4 ,5 ,5 ,6 ,5 ,6 ,6 ,7 ,
+ 1 ,2 ,2 ,3 ,2 ,3 ,3 ,4 ,2 ,3 ,3 ,4 ,3 ,4 ,4 ,5 ,
+ 2 ,3 ,3 ,4 ,3 ,4 ,4 ,5 ,3 ,4 ,4 ,5 ,4 ,5 ,5 ,6 ,
+ 2 ,3 ,3 ,4 ,3 ,4 ,4 ,5 ,3 ,4 ,4 ,5 ,4 ,5 ,5 ,6 ,
+ 3 ,4 ,4 ,5 ,4 ,5 ,5 ,6 ,4 ,5 ,5 ,6 ,5 ,6 ,6 ,7 ,
+ 2 ,3 ,3 ,4 ,3 ,4 ,4 ,5 ,3 ,4 ,4 ,5 ,4 ,5 ,5 ,6 ,
+ 3 ,4 ,4 ,5 ,4 ,5 ,5 ,6 ,4 ,5 ,5 ,6 ,5 ,6 ,6 ,7 ,
+ 3 ,4 ,4 ,5 ,4 ,5 ,5 ,6 ,4 ,5 ,5 ,6 ,5 ,6 ,6 ,7 ,
+ 4 ,5 ,5 ,6 ,5 ,6 ,6 ,7 ,5 ,6 ,6 ,7 ,6 ,7 ,7 ,8 };
+#endif
diff --git a/bit_count.h b/bit_count.h
new file mode 100644
index 0000000..6e7f62c
--- /dev/null
+++ b/bit_count.h
@@ -0,0 +1,101 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2010 iptelorg GmbH
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * History
+ * -------
+ * 2010-04-26 Initial version (Miklos)
+ */
+
+/* Implements the bit counting function:
+ * int bit_count(unsigned int u)
+ * Returns the number of bits in u.
+ */
+
+#ifndef _BIT_COUNT_H
+#define _BIT_COUNT_H
+
+/* fix __CPU_i386 -> __CPU_x86 */
+#if defined __CPU_i386 && ! defined __CPU_x86
+#define __CPU_x86
+#endif
+
+#ifdef CC_GCC_LIKE_ASM
+#if defined __CPU_x86 || defined __CPU_x86_64
+#ifdef __SSE4_2__
+/* popcnt requires SSE4.2 support,
+ * see http://en.wikipedia.org/wiki/SSE4 */
+#define BIT_COUNT_ASM
+#endif
+#endif
+#endif
+
+#ifdef BIT_COUNT_ASM
+
+/* Returns the number of 1 bits in u. */
+static inline int bit_count(unsigned int u)
+{
+ int v;
+
+ asm volatile(" popcnt %1, %0 " : "=r" (v) : "rm" (u));
+ return v;
+}
+
+#else /* BIT_COUNT_ASM */
+
+/* Returns the number of 1 bits in u.
+ * source: http://en.wikipedia.org/wiki/Hamming_weight
+ */
+#if 0
+static inline int bit_count(unsigned int u)
+{
+ int count;
+
+ /* It is likely to have only few
+ * bits set to 1, so there will be only
+ * few iterations */
+ for (count=0; u; count++)
+ u &= u-1;
+ return count;
+}
+#endif
+
+static inline int bit_count(unsigned int i)
+{
+ i = i - ((i >> 1) & 0x55555555);
+ i = (i & 0x33333333) + ((i >> 2) & 0x33333333);
+ return (((i + (i >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24;
+}
+
+#if 0
+/* number of bits in a byte.
+ * (Only slightly faster then the above version,
+ * It is not worth the extra memory usage.)
+ */
+extern int bits_in_char[256];
+
+static inline int bit_count(unsigned int u)
+{
+ return bits_in_char [u & 0xffu]
+ + bits_in_char [(u >> 8 ) & 0xffu]
+ + bits_in_char [(u >> 16) & 0xffu]
+ + bits_in_char [(u >> 24) & 0xffu];
+}
+#endif
+
+#endif /* BIT_COUNT_ASM */
+
+#endif /* _BIT_COUNT_H */
diff --git a/bit_test.h b/bit_test.h
new file mode 100644
index 0000000..534e502
--- /dev/null
+++ b/bit_test.h
@@ -0,0 +1,121 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2010 iptelorg GmbH
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * History
+ * -------
+ * 2010-04-26 Initial version (Miklos)
+ */
+
+/* Bit test functions:
+ * - int bit_test(int offset, unsigned int *addr)
+ * Returns the bit found at offset position
+ * in a bitstring pointed by addr.
+ *
+ * - int bit_test_and_set(int offset, unsigned int *addr)
+ * Returns the bit found at offset position
+ * in a bitstring pointed by addr, and sets
+ * the bit at the given offset.
+ *
+ * Note that 0 <= offset <= 128, Make sure that addr points to
+ * a large enough memory area.
+ */
+
+#ifndef _BIT_TEST_H
+#define _BIT_TEST_H
+
+/* fix __CPU_i386 -> __CPU_x86 */
+#if defined __CPU_i386 && ! defined __CPU_x86
+#define __CPU_x86
+#endif
+
+#ifdef CC_GCC_LIKE_ASM
+#if defined __CPU_x86 || defined __CPU_x86_64
+#define BIT_TEST_ASM
+#endif
+#endif
+
+#ifdef BIT_TEST_ASM
+
+/* Returns the bit found at offset position in the bitstring
+ * pointed by addr.
+ * Note that the CPU can access 4 bytes starting from addr,
+ * hence 0 <= offset < 128 holds. Make sure that addr points
+ * to a memory area that is large enough.
+ */
+static inline int bit_test(int offset, unsigned int *addr)
+{
+ unsigned char v;
+
+ asm volatile(
+ " bt %2, %1 \n\t"
+ " setc %0 \n\t"
+ : "=qm" (v) : "m" (*addr), "r" (offset)
+ );
+ return (int)v;
+}
+
+/* Returns the bit found at offset position in the bitstring
+ * pointed by addr and sets it to 1.
+ * Note that the CPU can access 4 bytes starting from addr,
+ * hence 0 <= offset < 128 holds. Make sure that addr points
+ * to a memory area that is large enough.
+ */
+static inline int bit_test_and_set(int offset, unsigned int *addr)
+{
+ unsigned char v;
+
+ asm volatile(
+ " bts %2, %1 \n\t"
+ " setc %0 \n\t"
+ : "=qm" (v) : "m" (*addr), "r" (offset)
+ );
+ return (int)v;
+}
+
+#else /* BIT_TEST_ASM */
+
+/* Returns the bit found at offset position in the bitstring
+ * pointed by addr.
+ * Note that offset can be grater than 32, make sure that addr points
+ * to a memory area that is large enough.
+ */
+static inline int bit_test(int offset, unsigned int *addr)
+{
+ return ((*(addr + offset/32)) & (1U << (offset % 32))) ? 1 : 0;
+}
+
+/* Returns the bit found at offset position in the bitstring
+ * pointed by addr and sets it to 1.
+ * Note that offset can be grater than 32, make sure that addr points
+ * to a memory area that is large enough.
+ */
+static inline int bit_test_and_set(int offset, unsigned int *addr)
+{
+ unsigned int *i;
+ int mask, res;
+
+ i = addr + offset/32;
+ mask = 1U << (offset % 32);
+ res = ((*i) & mask) ? 1 : 0;
+ (*i) |= mask;
+
+ return res;
+}
+
+#endif /* BIT_TEST_ASM */
+
+#endif /* #ifndef _BIT_TEST_H */