Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

lring: initial

  • Loading branch information...
commit 2d95a1b416940f5f1530f58c4089d008d05a7e11 1 parent 061f207
@indutny authored
View
2  Makefile
@@ -41,7 +41,7 @@ node_g: config.gypi out/Makefile
ln -fs out/Debug/node $@
endif
-out/Makefile: common.gypi deps/uv/uv.gyp deps/http_parser/http_parser.gyp deps/zlib/zlib.gyp deps/v8/build/common.gypi deps/v8/tools/gyp/v8.gyp node.gyp config.gypi
+out/Makefile: common.gypi deps/lring/lring.gyp deps/uv/uv.gyp deps/http_parser/http_parser.gyp deps/zlib/zlib.gyp deps/v8/build/common.gypi deps/v8/tools/gyp/v8.gyp node.gyp config.gypi
ifeq ($(USE_NINJA),1)
touch out/Makefile
$(PYTHON) tools/gyp_node -f ninja
View
2  deps/lring/.gitignore
@@ -0,0 +1,2 @@
+build/
+out/
View
42 deps/lring/README.md
@@ -0,0 +1,42 @@
+# Lock-less ring
+
+Lock-less One-producer-one-consumer ring in C.
+
+## Example
+
+```C
+char data[1024];
+lring_t ring;
+
+lring_init(&ring);
+
+lring_write(&ring, data, sizeof(data));
+ssize_t bytes_read = lring_read(&ring, data, sizeof(data));
+
+lring_destroy(&ring);
+```
+
+### License
+
+This software is licensed under the MIT License.
+
+Copyright Fedor Indutny, 2012.
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to permit
+persons to whom the Software is furnished to do so, subject to the
+following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+USE OR OTHER DEALINGS IN THE SOFTWARE.
View
183 deps/lring/common.gypi
@@ -0,0 +1,183 @@
+{
+ 'variables': {
+ 'visibility%': 'hidden', # V8's visibility setting
+ 'target_arch%': 'ia32', # set v8's target architecture
+ 'host_arch%': 'ia32', # set v8's host architecture
+ 'library%': 'static_library', # allow override to 'shared_library' for DLL/.so builds
+ 'component%': 'static_library', # NB. these names match with what V8 expects
+ 'msvs_multi_core_compile': '0', # we do enable multicore compiles, but not using the V8 way
+ 'gcc_version%': 'unknown',
+ 'clang%': 0,
+ },
+
+ 'target_defaults': {
+ 'default_configuration': 'Debug',
+ 'configurations': {
+ 'Debug': {
+ 'defines': [ 'DEBUG', '_DEBUG' ],
+ 'cflags': [ '-g', '-O0' ],
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'target_conditions': [
+ ['library=="static_library"', {
+ 'RuntimeLibrary': 1, # static debug
+ }, {
+ 'RuntimeLibrary': 3, # DLL debug
+ }],
+ ],
+ 'Optimization': 0, # /Od, no optimization
+ 'MinimalRebuild': 'false',
+ 'OmitFramePointers': 'false',
+ 'BasicRuntimeChecks': 3, # /RTC1
+ },
+ 'VCLinkerTool': {
+ 'LinkIncremental': 2, # enable incremental linking
+ },
+ },
+ 'xcode_settings': {
+ 'GCC_OPTIMIZATION_LEVEL': '0',
+ },
+ 'conditions': [
+ ['OS != "win"', {
+ 'defines': [ 'EV_VERIFY=2' ],
+ }],
+ ]
+ },
+ 'Release': {
+ 'defines': [ 'NDEBUG' ],
+ 'cflags': [ '-O3', '-fomit-frame-pointer', '-fdata-sections', '-ffunction-sections' ],
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'target_conditions': [
+ ['library=="static_library"', {
+ 'RuntimeLibrary': 0, # static release
+ }, {
+ 'RuntimeLibrary': 2, # debug release
+ }],
+ ],
+ 'Optimization': 3, # /Ox, full optimization
+ 'FavorSizeOrSpeed': 1, # /Ot, favour speed over size
+ 'InlineFunctionExpansion': 2, # /Ob2, inline anything eligible
+ 'WholeProgramOptimization': 'true', # /GL, whole program optimization, needed for LTCG
+ 'OmitFramePointers': 'true',
+ 'EnableFunctionLevelLinking': 'true',
+ 'EnableIntrinsicFunctions': 'true',
+ },
+ 'VCLibrarianTool': {
+ 'AdditionalOptions': [
+ '/LTCG', # link time code generation
+ ],
+ },
+ 'VCLinkerTool': {
+ 'LinkTimeCodeGeneration': 1, # link-time code generation
+ 'OptimizeReferences': 2, # /OPT:REF
+ 'EnableCOMDATFolding': 2, # /OPT:ICF
+ 'LinkIncremental': 1, # disable incremental linking
+ },
+ },
+ }
+ },
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'StringPooling': 'true', # pool string literals
+ 'DebugInformationFormat': 3, # Generate a PDB
+ 'WarningLevel': 3,
+ 'BufferSecurityCheck': 'true',
+ 'ExceptionHandling': 1, # /EHsc
+ 'SuppressStartupBanner': 'true',
+ 'WarnAsError': 'false',
+ 'AdditionalOptions': [
+ '/MP', # compile across multiple CPUs
+ ],
+ },
+ 'VCLibrarianTool': {
+ },
+ 'VCLinkerTool': {
+ 'GenerateDebugInformation': 'true',
+ 'RandomizedBaseAddress': 2, # enable ASLR
+ 'DataExecutionPrevention': 2, # enable DEP
+ 'AllowIsolation': 'true',
+ 'SuppressStartupBanner': 'true',
+ 'target_conditions': [
+ ['_type=="executable"', {
+ 'SubSystem': 1, # console executable
+ }],
+ ],
+ },
+ },
+ 'conditions': [
+ ['OS == "win"', {
+ 'msvs_cygwin_shell': 0, # prevent actions from trying to use cygwin
+ 'defines': [
+ 'WIN32',
+ # we don't really want VC++ warning us about
+ # how dangerous C functions are...
+ '_CRT_SECURE_NO_DEPRECATE',
+ # ... or that C implementations shouldn't use
+ # POSIX names
+ '_CRT_NONSTDC_NO_DEPRECATE',
+ ],
+ 'target_conditions': [
+ ['target_arch=="x64"', {
+ 'msvs_configuration_platform': 'x64'
+ }]
+ ]
+ }],
+ [ 'OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="solaris"', {
+ 'cflags': [ '-Wall' ],
+ 'cflags_cc': [ '-fno-rtti', '-fno-exceptions' ],
+ 'conditions': [
+ [ 'host_arch != target_arch and target_arch=="ia32"', {
+ 'cflags': [ '-m32' ],
+ 'ldflags': [ '-m32' ],
+ }],
+ [ 'OS=="linux"', {
+ 'cflags': [ '-ansi' ],
+ }],
+ [ 'OS=="solaris"', {
+ 'cflags': [ '-pthreads' ],
+ 'ldflags': [ '-pthreads' ],
+ }, {
+ 'cflags': [ '-pthread' ],
+ 'ldflags': [ '-pthread' ],
+ }],
+ [ 'visibility=="hidden" and (clang==1 or gcc_version >= 40)', {
+ 'cflags': [ '-fvisibility=hidden' ],
+ }],
+ ],
+ }],
+ ['OS=="mac"', {
+ 'xcode_settings': {
+ 'ALWAYS_SEARCH_USER_PATHS': 'NO',
+ 'GCC_CW_ASM_SYNTAX': 'NO', # No -fasm-blocks
+ 'GCC_DYNAMIC_NO_PIC': 'NO', # No -mdynamic-no-pic
+ # (Equivalent to -fPIC)
+ 'GCC_ENABLE_CPP_EXCEPTIONS': 'NO', # -fno-exceptions
+ 'GCC_ENABLE_CPP_RTTI': 'NO', # -fno-rtti
+ 'GCC_ENABLE_PASCAL_STRINGS': 'NO', # No -mpascal-strings
+ # GCC_INLINES_ARE_PRIVATE_EXTERN maps to -fvisibility-inlines-hidden
+ 'GCC_INLINES_ARE_PRIVATE_EXTERN': 'YES',
+ 'GCC_SYMBOLS_PRIVATE_EXTERN': 'YES', # -fvisibility=hidden
+ 'GCC_THREADSAFE_STATICS': 'NO', # -fno-threadsafe-statics
+ 'GCC_WARN_ABOUT_MISSING_NEWLINE': 'YES', # -Wnewline-eof
+ 'PREBINDING': 'NO', # No -Wl,-prebind
+ 'USE_HEADERMAP': 'NO',
+ 'OTHER_CFLAGS': [
+ '-fno-strict-aliasing',
+ ],
+ 'WARNING_CFLAGS': [
+ '-Wall',
+ '-Wendif-labels',
+ '-W',
+ '-Wno-unused-parameter',
+ ],
+ },
+ 'target_conditions': [
+ ['_type!="static_library"', {
+ 'xcode_settings': {'OTHER_LDFLAGS': ['-Wl,-search_paths_first']},
+ }],
+ ],
+ }],
+ ],
+ },
+}
View
85 deps/lring/gyp_lring
@@ -0,0 +1,85 @@
+#!/usr/bin/env python
+
+import glob
+import os
+import subprocess
+import sys
+
+CC = os.environ.get('CC', 'cc')
+script_dir = os.path.dirname(__file__)
+lring_root = os.path.normpath(script_dir)
+output_dir = os.path.join(os.path.abspath(lring_root), 'out')
+
+sys.path.insert(0, os.path.join(lring_root, 'build', 'gyp', 'pylib'))
+try:
+ import gyp
+except ImportError:
+ print('You need to install gyp in build/gyp first. See the README.')
+ sys.exit(42)
+
+
+def compiler_version():
+ proc = subprocess.Popen(CC.split() + ['--version'], stdout=subprocess.PIPE)
+ is_clang = 'clang' in proc.communicate()[0].split('\n')[0]
+ proc = subprocess.Popen(CC.split() + ['-dumpversion'], stdout=subprocess.PIPE)
+ version = proc.communicate()[0].split('.')
+ version = map(int, version[:2])
+ version = tuple(version)
+ return (version, is_clang)
+
+
+def run_gyp(args):
+ rc = gyp.main(args)
+ if rc != 0:
+ print 'Error running GYP'
+ sys.exit(rc)
+
+
+if __name__ == '__main__':
+ args = sys.argv[1:]
+
+ # GYP bug.
+ # On msvs it will crash if it gets an absolute path.
+ # On Mac/make it will crash if it doesn't get an absolute path.
+ if sys.platform == 'win32':
+ args.append(os.path.join(lring_root, 'lring.gyp'))
+ common_fn = os.path.join(lring_root, 'common.gypi')
+ options_fn = os.path.join(lring_root, 'options.gypi')
+ # we force vs 2010 over 2008 which would otherwise be the default for gyp
+ if not os.environ.get('GYP_MSVS_VERSION'):
+ os.environ['GYP_MSVS_VERSION'] = '2010'
+ else:
+ args.append(os.path.join(os.path.abspath(lring_root), 'lring.gyp'))
+ common_fn = os.path.join(os.path.abspath(lring_root), 'common.gypi')
+ options_fn = os.path.join(os.path.abspath(lring_root), 'options.gypi')
+
+ if os.path.exists(common_fn):
+ args.extend(['-I', common_fn])
+
+ if os.path.exists(options_fn):
+ args.extend(['-I', options_fn])
+
+ args.append('--depth=' + lring_root)
+
+ # There's a bug with windows which doesn't allow this feature.
+ if sys.platform != 'win32':
+ if '-f' not in args:
+ args.extend('-f make'.split())
+ if 'ninja' not in args:
+ args.extend(['-Goutput_dir=' + output_dir])
+ args.extend(['--generator-output', output_dir])
+ (major, minor), is_clang = compiler_version()
+ args.append('-Dgcc_version=%d' % (10 * major + minor))
+ args.append('-Dclang=%d' % int(is_clang))
+
+ if not any(a.startswith('-Dtarget_arch') for a in args):
+ args.append('-Dtarget_arch=ia32')
+
+ if not any(a.startswith('-Dlibrary') for a in args):
+ args.append('-Dlibrary=static_library')
+
+ args.append('-Dcomponent=static_library')
+
+ gyp_args = list(args)
+ print gyp_args
+ run_gyp(gyp_args)
View
55 deps/lring/include/lring.h
@@ -0,0 +1,55 @@
+#ifndef _INCLUDE_LRING_H_
+#define _INCLUDE_LRING_H_
+
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct lring_s lring_t;
+typedef struct lring_page_s lring_page_t;
+
+struct lring_page_s {
+ lring_page_t* next;
+ volatile ssize_t roffset;
+ volatile ssize_t woffset;
+ char data[10 * 1024];
+};
+
+struct lring_s {
+ lring_page_t head;
+ lring_page_t* rhead;
+ lring_page_t* whead;
+ volatile ssize_t total;
+};
+
+/* Initialize ring */
+void lring_init(lring_t* ring);
+
+/* Deinitialize ring (won't free memory) */
+void lring_destroy(lring_t* ring);
+
+/* Returns current size of the ring */
+ssize_t lring_size(lring_t* ring);
+
+/* Put data into ring */
+void lring_write(lring_t* ring, const char* data, ssize_t size);
+
+/*
+ * Read at maximum `size` data from the ring,
+ * returns actual amount of data that was read.
+ * (NOTE: if `data` is NULL, lring_read will just flush that data).
+ */
+ssize_t lring_read(lring_t* ring, char* data, ssize_t size);
+
+/*
+ * Read data from ring without dequeuing it
+ * (Works exactly like `lring_read`)
+ */
+ssize_t lring_peek(lring_t* ring, char* data, ssize_t size);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _INCLUDE_LRING_H_ */
View
44 deps/lring/lring.gyp
@@ -0,0 +1,44 @@
+{
+ 'target_defaults': {
+ 'conditions': [
+ ['OS != "win"', {
+ 'defines': [
+ '_GNU_SOURCE',
+ ],
+ 'conditions': [
+ ['OS=="solaris"', {
+ 'cflags': ['-pthreads'],
+ 'ldlags': ['-pthreads'],
+ }, {
+ 'cflags': ['-pthread'],
+ 'ldlags': ['-pthread'],
+ }],
+ ],
+ }],
+ ],
+ },
+ "targets": [
+ {
+ "target_name": "lring",
+ "type": "<(library)",
+ "include_dirs": [
+ "include/",
+ "src/"
+ ],
+ "sources": [
+ "src/lring.c"
+ ]
+ }, {
+ "target_name": "tests",
+ "type": "executable",
+ "dependencies": [ "lring" ],
+ "include_dirs": [
+ "include/",
+ "test/"
+ ],
+ "sources": [
+ "test/ring-test.c"
+ ]
+ }
+ ]
+}
View
66 deps/lring/src/atomic.h
@@ -0,0 +1,66 @@
+#ifndef _SRC_ATOMIC_H_
+#define _SRC_ATOMIC_H_
+
+/* GCC >= 4.1 has built-in intrinsics. We'll use those */
+#if defined(__GNUC__)
+# if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)
+
+# define ATOMIC_ADD(arg, num) __sync_add_and_fetch(&arg, num)
+# define ATOMIC_SUB(arg, num) __sync_sub_and_fetch(&arg, num)
+
+# elif defined( __i386__ ) || defined( __i486__ ) || defined( __i586__ ) || \
+ defined( __i686__ ) || defined( __x86_64__ )
+
+# define ATOMIC_ADD(arg, num) asm volatile ("lock add %0, %1\n" : \
+ : "r" (num), "m" (arg))
+# define ATOMIC_SUB(arg, num) asm volatile ("lock sub %0, %1\n" : \
+ : "r" (num), "m" (arg))
+
+# else
+
+# error Atomic operations are not supported on your platform
+
+# endif
+
+#elif defined(__APPLE__)
+
+#include <libkern/OSAtomic.h>
+
+# if defined( __x86_64__ ) || defined ( __ppc64__)
+# define ATOMIC_CAST_WORD(arg) ((volatile int64_t*)(arg))
+
+# define ATOMIC_ADD(arg, num) OSAtomicAdd64(num, ATOMIC_CAST_WORD(&arg));
+# define ATOMIC_SUB(arg, num) OSAtomicAdd64(-num, ATOMIC_CAST_WORD(&arg));
+# else
+# define ATOMIC_CAST_WORD(arg) ((volatile int32_t*)(arg))
+
+# define ATOMIC_ADD(arg, num) OSAtomicAdd32(num, ATOMIC_CAST_WORD(&arg));
+# define ATOMIC_SUB(arg, num) OSAtomicAdd32(-num, ATOMIC_CAST_WORD(&arg));
+# endif
+
+#elif defined(_MSC_VER)
+
+# if defined(_M_X64)
+ extern "C" __int64 _InterlockedExchangeAdd64(__int64 volatile* addend, __int64 value);
+# pragma intrinsic (_InterlockedExchangeAdd64)
+# define ATOMIC_ADD(arg, num) ((void) _InterlockedExchangeAdd64(&(arg), (num)))
+# define ATOMIC_SUB(arg, num) ((void) _InterlockedExchangeAdd64(&(arg), -(num)))
+
+# elif defined(_M_IX86)
+ extern "C" long _InterlockedExchangeAdd(long volatile* addend, long value);
+# pragma intrinsic (_InterlockedExchangeAdd)
+# define ATOMIC_ADD(arg, num) ((void) _InterlockedExchangeAdd(&(arg), (num)))
+# define ATOMIC_SUB(arg, num) ((void) _InterlockedExchangeAdd(&(arg), -(num)))
+
+# else
+# error Atomic operations are not supported on your platform
+
+# endif
+
+#else
+
+# error Atomic operations are not supported on your platform
+
+#endif
+
+#endif /* _SRC_ATOMIC_H_ */
View
182 deps/lring/src/lring.c
@@ -0,0 +1,182 @@
+#include "lring.h"
+#include "atomic.h"
+#include "pa_memorybarrier.h"
+#include <sys/types.h> /* ssize_t, size_t */
+#include <stdlib.h> /* malloc, free */
+#include <string.h> /* memcpy */
+#include <assert.h>
+
+void lring_init_page(lring_page_t* page) {
+ page->next = page;
+ page->roffset = 0;
+ page->woffset = 0;
+}
+
+void lring_init(lring_t* ring) {
+ ring->total = 0;
+ ring->rhead = &ring->head;
+ ring->whead = &ring->head;
+
+ lring_init_page(&ring->head);
+}
+
+
+void lring_destroy(lring_t* ring) {
+ ring->rhead = NULL;
+ ring->whead = NULL;
+ ring->total = 0;
+
+ /* Destroy all pages */
+ while (ring->head.next != &ring->head) {
+ lring_page_t* next = ring->head.next;
+ ring->head.next = next->next;
+ free(next);
+ }
+}
+
+
+ssize_t lring_size(lring_t* ring) {
+ ssize_t total;
+
+ total = ring->total;
+
+ /* Sometimes total could be less than zero */
+ if (total >= 0) return total;
+ return 0;
+}
+
+
+void lring_write(lring_t* ring, const char* data, ssize_t size) {
+ ssize_t left;
+ ssize_t offset;
+ ssize_t woffset;
+ ssize_t available;
+ ssize_t bytes;
+ lring_page_t* p;
+
+ left = size;
+ offset = 0;
+ p = ring->whead;
+
+ while (left > 0) {
+ available = sizeof(p->data) - p->woffset;
+ bytes = available > left ? left : available;
+
+ assert((size_t)(p->woffset + bytes) <= sizeof(p->data));
+ memcpy(p->data + p->woffset, data + offset, bytes);
+
+ offset += bytes;
+ left -= bytes;
+
+ woffset = p->woffset + bytes;
+ p->woffset = woffset;
+
+ if (woffset == sizeof(p->data)) {
+ lring_page_t* next = p->next;
+
+ if (ring->rhead != next &&
+ next->roffset == sizeof(next->data) &&
+ next->woffset == sizeof(next->data)) {
+ /* Fully written and read buffer is the same thing as empty */
+ next->roffset = 0;
+ next->woffset = 0;
+ } else if (next->woffset != 0) {
+ /* Tail is full now - get a new one */
+ next = malloc(sizeof(lring_page_t));
+ if (next == NULL) abort();
+ lring_init_page(next);
+ next->next = p->next;
+
+ /* Insert buffer into ring */
+ *((volatile lring_page_t**) &p->next) = next;
+ }
+ p = next;
+
+ /* Move write head */
+ ring->whead = p;
+
+ assert(ring->whead->woffset == 0);
+ assert(ring->whead->roffset == 0);
+ }
+
+ PaUtil_WriteMemoryBarrier();
+ ATOMIC_ADD(ring->total, bytes);
+ }
+ assert(size == offset);
+}
+
+
+ssize_t lring_read(lring_t* ring, char* data, ssize_t size) {
+ ssize_t left;
+ ssize_t offset;
+ ssize_t roffset;
+ ssize_t avail;
+ ssize_t bytes;
+ lring_page_t* p;
+
+ left = size;
+ offset = 0;
+ p = ring->rhead;
+
+ while (ring->total > 0 && left > 0) {
+ PaUtil_ReadMemoryBarrier();
+
+ avail = p->woffset - p->roffset;
+ bytes = avail > left ? left : avail;
+
+ /* Copy only if there's place to save data */
+ if (data != NULL && bytes != 0) {
+ assert(avail >= bytes);
+ memcpy(data + offset, p->data + p->roffset, bytes);
+ }
+
+ left -= bytes;
+ offset += bytes;
+
+ roffset = p->roffset + bytes;
+ p->roffset = roffset;
+ ATOMIC_SUB(ring->total, bytes);
+
+ assert(roffset >= 0);
+
+ if (roffset == sizeof(p->data)) {
+ /* Move rhead if we can't read there anymore */
+ p = p->next;
+ ring->rhead = p;
+ }
+ }
+
+ return offset;
+}
+
+
+ssize_t lring_peek(lring_t* ring, char* data, ssize_t size) {
+ ssize_t left;
+ ssize_t offset;
+ ssize_t avail;
+ ssize_t bytes;
+ lring_page_t* current;
+
+ left = size;
+ offset = 0;
+ current = ring->rhead;
+
+ /* Limit amount of bytes that can be actually read */
+ if (left > ring->total) left = ring->total;
+
+ while (left > 0) {
+ avail = current->woffset - current->roffset;
+ if (avail == 0) break;
+ bytes = avail > left ? left : avail;
+
+ assert(current->roffset + bytes <= current->woffset);
+ memcpy(data + offset, current->data + current->roffset, bytes);
+
+ offset += bytes;
+ left -= bytes;
+
+ current = current->next;
+ }
+
+ return offset;
+}
View
127 deps/lring/src/pa_memorybarrier.h
@@ -0,0 +1,127 @@
+/*
+ * $Id: pa_memorybarrier.h 1240 2007-07-17 13:05:07Z bjornroche $
+ * Portable Audio I/O Library
+ * Memory barrier utilities
+ *
+ * Author: Bjorn Roche, XO Audio, LLC
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/*
+ * The text above constitutes the entire PortAudio license; however,
+ * the PortAudio community also makes the following non-binding requests:
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version. It is also
+ * requested that these non-binding requests be included along with the
+ * license above.
+ */
+
+/**
+ @file pa_memorybarrier.h
+ @ingroup common_src
+*/
+
+/****************
+ * Some memory barrier primitives based on the system.
+ * right now only OS X, FreeBSD, and Linux are supported. In addition to providing
+ * memory barriers, these functions should ensure that data cached in registers
+ * is written out to cache where it can be snooped by other CPUs. (ie, the volatile
+ * keyword should not be required)
+ *
+ * the primitives that must be defined are:
+ *
+ * PaUtil_FullMemoryBarrier()
+ * PaUtil_ReadMemoryBarrier()
+ * PaUtil_WriteMemoryBarrier()
+ *
+ ****************/
+
+#if defined(__APPLE__)
+# include <libkern/OSAtomic.h>
+ /* Here are the memory barrier functions. Mac OS X only provides
+ full memory barriers, so the three types of barriers are the same,
+ however, these barriers are superior to compiler-based ones. */
+# define PaUtil_FullMemoryBarrier() OSMemoryBarrier()
+# define PaUtil_ReadMemoryBarrier() OSMemoryBarrier()
+# define PaUtil_WriteMemoryBarrier() OSMemoryBarrier()
+#elif defined(__GNUC__)
+ /* GCC >= 4.1 has built-in intrinsics. We'll use those */
+# if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)
+# define PaUtil_FullMemoryBarrier() __sync_synchronize()
+# define PaUtil_ReadMemoryBarrier() __sync_synchronize()
+# define PaUtil_WriteMemoryBarrier() __sync_synchronize()
+ /* as a fallback, GCC understands volatile asm and "memory" to mean it
+ * should not reorder memory read/writes */
+ /* Note that it is not clear that any compiler actually defines __PPC__,
+ * it can probably removed safely. */
+# elif defined( __ppc__ ) || defined( __powerpc__) || defined( __PPC__ )
+# define PaUtil_FullMemoryBarrier() asm volatile("sync":::"memory")
+# define PaUtil_ReadMemoryBarrier() asm volatile("sync":::"memory")
+# define PaUtil_WriteMemoryBarrier() asm volatile("sync":::"memory")
+# elif defined( __i386__ ) || defined( __i486__ ) || defined( __i586__ ) || \
+ defined( __i686__ ) || defined( __x86_64__ )
+# define PaUtil_FullMemoryBarrier() asm volatile("mfence":::"memory")
+# define PaUtil_ReadMemoryBarrier() asm volatile("lfence":::"memory")
+# define PaUtil_WriteMemoryBarrier() asm volatile("sfence":::"memory")
+# else
+# ifdef ALLOW_SMP_DANGERS
+# warning Memory barriers not defined on this system or system unknown
+# warning For SMP safety, you should fix this.
+# define PaUtil_FullMemoryBarrier()
+# define PaUtil_ReadMemoryBarrier()
+# define PaUtil_WriteMemoryBarrier()
+# else
+# error Memory barriers are not defined on this system. You can still compile by defining ALLOW_SMP_DANGERS, but SMP safety will not be guaranteed.
+# endif
+# endif
+#elif (_MSC_VER >= 1400) && !defined(_WIN32_WCE)
+# include <intrin.h>
+# pragma intrinsic(_ReadWriteBarrier)
+# pragma intrinsic(_ReadBarrier)
+# pragma intrinsic(_WriteBarrier)
+# define PaUtil_FullMemoryBarrier() _ReadWriteBarrier()
+# define PaUtil_ReadMemoryBarrier() _ReadBarrier()
+# define PaUtil_WriteMemoryBarrier() _WriteBarrier()
+#elif defined(_WIN32_WCE)
+# define PaUtil_FullMemoryBarrier()
+# define PaUtil_ReadMemoryBarrier()
+# define PaUtil_WriteMemoryBarrier()
+#elif defined(_MSC_VER) || defined(__BORLANDC__)
+# define PaUtil_FullMemoryBarrier() _asm { lock add [esp], 0 }
+# define PaUtil_ReadMemoryBarrier() _asm { lock add [esp], 0 }
+# define PaUtil_WriteMemoryBarrier() _asm { lock add [esp], 0 }
+#else
+# ifdef ALLOW_SMP_DANGERS
+# warning Memory barriers not defined on this system or system unknown
+# warning For SMP safety, you should fix this.
+# define PaUtil_FullMemoryBarrier()
+# define PaUtil_ReadMemoryBarrier()
+# define PaUtil_WriteMemoryBarrier()
+# else
+# error Memory barriers are not defined on this system. You can still compile by defining ALLOW_SMP_DANGERS, but SMP safety will not be guaranteed.
+# endif
+#endif
View
79 deps/lring/test/ring-test.c
@@ -0,0 +1,79 @@
+#include "lring.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <pthread.h>
+
+#define NUM_ITERATIONS 1000000
+#define WRITE_BUF 1023
+#define READ_BUF 1023
+
+static lring_t ring;
+
+void* producer_fn(void* arg) {
+ unsigned char buf[WRITE_BUF];
+ int i;
+ size_t j;
+ int c;
+
+ /* Running counter */
+ c = 0;
+
+ for (i = 0; i < NUM_ITERATIONS; i++) {
+ for (j = 0; j < sizeof(buf); j++) {
+ buf[j] = c;
+ c = (c + 1) & 0xff;
+ }
+
+ lring_write(&ring, (const char*) buf, sizeof(buf));
+ }
+
+ return NULL;
+}
+
+
+void* consumer_fn(void* arg) {
+ unsigned char buf[READ_BUF];
+ ssize_t left;
+ ssize_t read;
+ int j;
+ int c;
+
+ left = WRITE_BUF * NUM_ITERATIONS;
+
+ /* Running counter */
+ c = 0;
+
+ while (left > 0) {
+ read = lring_read(&ring, (char*) buf, sizeof(buf));
+ left -= read;
+
+ /* Verify read data */
+ for (j = 0; j < read; j++) {
+ if (buf[j] != c) {
+ fprintf(stdout, "%d %d %ld\n", c, buf[j], left);
+ abort();
+ }
+ c = (c + 1) & 0xff;
+ }
+ }
+
+ return NULL;
+}
+
+
+int main() {
+ pthread_t producer;
+ pthread_t consumer;
+ lring_init(&ring);
+
+ pthread_create(&producer, NULL, producer_fn, NULL);
+ pthread_create(&consumer, NULL, consumer_fn, NULL);
+
+ pthread_join(producer, NULL);
+ pthread_join(consumer, NULL);
+
+ lring_destroy(&ring);
+
+ return 0;
+}
View
5 node.gyp
@@ -60,12 +60,14 @@
'deps/cares/cares.gyp:cares',
'deps/http_parser/http_parser.gyp:http_parser',
'deps/uv/uv.gyp:libuv',
+ 'deps/lring/lring.gyp:lring',
'node_js2c#host',
],
'include_dirs': [
'src',
'deps/uv/src/ares',
+ 'deps/lring/include',
'<(SHARED_INTERMEDIATE_DIR)' # for node_natives.h
],
@@ -101,6 +103,7 @@
'src/node.h',
'src/node_buffer.h',
'src/node_constants.h',
+ 'src/lring_bio.h',
'src/node_crypto.h',
'src/node_extensions.h',
'src/node_file.h',
@@ -138,7 +141,7 @@
'conditions': [
[ 'node_use_openssl=="true"', {
'defines': [ 'HAVE_OPENSSL=1' ],
- 'sources': [ 'src/node_crypto.cc' ],
+ 'sources': [ 'src/lring_bio.cc', 'src/node_crypto.cc' ],
'conditions': [
[ 'node_shared_openssl=="false"', {
'dependencies': [ './deps/openssl/openssl.gyp:openssl' ],
View
184 src/lring_bio.cc
@@ -0,0 +1,184 @@
+#include "lring_bio.h"
+#include "lring.h"
+#include <assert.h>
+#include <string.h>
+
+namespace node {
+
+static int mem_write(BIO*, const char*, int);
+static int mem_read(BIO*, char*, int);
+static int mem_puts(BIO*, const char*);
+static int mem_gets(BIO*, char*, int);
+static long mem_ctrl(BIO*, int, long, void*);
+static int mem_new(BIO*);
+static int mem_free(BIO*);
+
+#define BIO_TYPE_NO_EX_DATA 0x0800
+
+static BIO_METHOD mem_method = {
+ BIO_TYPE_MEM | BIO_TYPE_NO_EX_DATA,
+ "Super lring buffer",
+ mem_write,
+ mem_read,
+ mem_puts,
+ mem_gets,
+ mem_ctrl,
+ mem_new,
+ mem_free,
+ NULL,
+};
+
+
+BIO_METHOD* BIO_lring() {
+ return &mem_method;
+}
+
+
+static int mem_new(BIO* bio) {
+ lring_t* ring = new lring_t();
+ lring_init(ring);
+
+ bio->ptr = reinterpret_cast<char*>(ring);
+
+ // XXX Why am I doing it?!
+ bio->shutdown = 1;
+ bio->init = 1;
+ bio->num = -1;
+
+ return 1;
+}
+
+
+static int mem_free(BIO* bio) {
+ if (bio == NULL) return 0;
+
+ if (bio->shutdown) {
+ if (bio->init && bio->ptr != NULL) {
+ lring_t* ring = reinterpret_cast<lring_t*>(bio->ptr);
+ lring_destroy(ring);
+ delete ring;
+ bio->ptr = NULL;
+ }
+ }
+
+ return 1;
+}
+
+
+static int mem_read(BIO* bio, char* out, int len) {
+ BIO_clear_retry_flags(bio);
+
+ lring_t* r = reinterpret_cast<lring_t*>(bio->ptr);
+ assert(r != NULL);
+
+ if (lring_size(r) == 0) {
+ BIO_set_retry_read(bio);
+ return bio->num;
+ }
+
+ int bytes = static_cast<int>(lring_read(r, out, len));
+
+ return bytes;
+}
+
+
+static int mem_write(BIO* bio, const char* data, int len) {
+ lring_t* r = reinterpret_cast<lring_t*>(bio->ptr);
+
+ BIO_clear_retry_flags(bio);
+
+ assert(r != NULL);
+ lring_write(r, data, len);
+
+ return len;
+}
+
+
+static int mem_puts(BIO* bio, const char* str) {
+ return mem_write(bio, str, static_cast<int>(strlen(str)) + 1);
+}
+
+
+static int mem_gets(BIO* bio, char* out, int size) {
+ lring_t* r = reinterpret_cast<lring_t*>(bio->ptr);
+ assert(r != NULL);
+
+ int len = static_cast<int>(lring_peek(r, out, size));
+ if (len == 0) return 0;
+
+ int i;
+ char* tmp = out;
+ for (i = 0; i < len && *tmp != '\n'; i++, tmp++) {
+ // Nop
+ }
+
+ // Include newline char
+ if (*tmp == '\n' && i < size) i++;
+
+ // Flush read data
+ lring_read(r, NULL, i);
+
+ // Terminate line
+ if (size == i) i--;
+ out[i] = 0;
+
+ return i;
+}
+
+
+static long mem_ctrl(BIO* bio, int cmd, long num, void* ptr) {
+ long ret = 1;
+
+ lring_t* r = reinterpret_cast<lring_t*>(bio->ptr);
+ assert(r != NULL);
+
+ switch (cmd) {
+ case BIO_CTRL_RESET:
+ lring_read(r, NULL, lring_size(r));
+ break;
+ case BIO_CTRL_EOF:
+ ret = lring_size(r) == 0;
+ break;
+ case BIO_C_SET_BUF_MEM_EOF_RETURN:
+ bio->num = static_cast<int>(num);
+ break;
+ case BIO_CTRL_INFO:
+ ret = static_cast<long>(lring_size(r));
+ if (ptr != NULL)
+ *reinterpret_cast<void**>(ptr) = NULL;
+ break;
+ case BIO_C_SET_BUF_MEM:
+ mem_free(bio);
+ bio->shutdown= static_cast<int>(num);
+ bio->ptr = ptr;
+ break;
+ case BIO_C_GET_BUF_MEM_PTR:
+ if (ptr != NULL)
+ *reinterpret_cast<void**>(ptr) = r;
+ break;
+ case BIO_CTRL_GET_CLOSE:
+ ret = static_cast<long>(bio->shutdown);
+ break;
+ case BIO_CTRL_SET_CLOSE:
+ bio->shutdown = static_cast<int>(num);
+ break;
+ case BIO_CTRL_WPENDING:
+ ret = 0L;
+ break;
+ case BIO_CTRL_PENDING:
+ ret = static_cast<long>(lring_size(r));
+ break;
+ case BIO_CTRL_DUP:
+ case BIO_CTRL_FLUSH:
+ ret = 1;
+ break;
+ case BIO_CTRL_PUSH:
+ case BIO_CTRL_POP:
+ default:
+ ret = 0;
+ break;
+ }
+ return ret;
+}
+
+} // namespace node
View
14 src/lring_bio.h
@@ -0,0 +1,14 @@
+#ifndef _SRC_LRING_BIO_H_
+#define _SRC_LRING_BIO_H_
+
+#include "openssl/bio.h"
+#include "ngx-queue.h"
+#include "lring.h"
+
+namespace node {
+
+BIO_METHOD* BIO_lring();
+
+} // namespace node
+
+#endif // _SRC_LRING_BIO_H_
View
21 src/node_crypto.cc
@@ -21,6 +21,7 @@
#include "node_crypto.h"
#include "node_crypto_groups.h"
+#include "lring_bio.h"
#include "v8.h"
#include "node.h"
@@ -275,7 +276,7 @@ int SecureContext::NewSessionCallback(SSL* s, SSL_SESSION* sess) {
// Takes a string or buffer and loads it into a BIO.
// Caller responsible for BIO_free-ing the returned object.
static BIO* LoadBIO (Handle<Value> v) {
- BIO *bio = BIO_new(BIO_s_mem());
+ BIO *bio = BIO_new(BIO_lring());
if (!bio) return NULL;
HandleScope scope;
@@ -533,7 +534,7 @@ Handle<Value> SecureContext::AddRootCerts(const Arguments& args) {
root_cert_store = X509_STORE_new();
for (int i = 0; root_certs[i]; i++) {
- BIO *bp = BIO_new(BIO_s_mem());
+ BIO *bp = BIO_new(BIO_lring());
if (!BIO_write(bp, root_certs[i], strlen(root_certs[i]))) {
BIO_free(bp);
@@ -610,7 +611,7 @@ Handle<Value> SecureContext::SetSessionIdContext(const Arguments& args) {
Local<String> message;
BIO* bio;
BUF_MEM* mem;
- if ((bio = BIO_new(BIO_s_mem()))) {
+ if ((bio = BIO_new(BIO_lring()))) {
ERR_print_errors(bio);
BIO_get_mem_ptr(bio, &mem);
message = String::New(mem->data, mem->length);
@@ -919,7 +920,7 @@ int Connection::HandleSSLError(const char* func, int rv) {
// understood. And we should be somehow propagating these errors up
// into JavaScript. There is no test which demonstrates this problem.
// https://github.com/joyent/node/issues/1719
- if ((bio = BIO_new(BIO_s_mem()))) {
+ if ((bio = BIO_new(BIO_lring()))) {
ERR_print_errors(bio);
BIO_get_mem_ptr(bio, &mem);
Local<Value> e = Exception::Error(String::New(mem->data, mem->length));
@@ -1176,8 +1177,8 @@ Handle<Value> Connection::New(const Arguments& args) {
bool is_server = args[1]->BooleanValue();
p->ssl_ = SSL_new(sc->ctx_);
- p->bio_read_ = BIO_new(BIO_s_mem());
- p->bio_write_ = BIO_new(BIO_s_mem());
+ p->bio_read_ = BIO_new(BIO_lring());
+ p->bio_write_ = BIO_new(BIO_lring());
SSL_set_app_data(p->ssl_, p);
@@ -1490,7 +1491,7 @@ Handle<Value> Connection::GetPeerCertificate(const Arguments& args) {
Local<Object> info = Object::New();
X509* peer_cert = SSL_get_peer_certificate(ss->ssl_);
if (peer_cert != NULL) {
- BIO* bio = BIO_new(BIO_s_mem());
+ BIO* bio = BIO_new(BIO_lring());
BUF_MEM* mem;
if (X509_NAME_print_ex(bio, X509_get_subject_name(peer_cert), 0,
X509_NAME_FLAGS) > 0) {
@@ -2045,7 +2046,7 @@ static void HexDecode(unsigned char *input,
void base64(unsigned char *input, int length, char** buf64, int* buf64_len) {
BIO *b64 = BIO_new(BIO_f_base64());
- BIO *bmem = BIO_new(BIO_s_mem());
+ BIO *bmem = BIO_new(BIO_lring());
b64 = BIO_push(b64, bmem);
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
int len = BIO_write(b64, input, length);
@@ -3346,7 +3347,7 @@ class Sign : public ObjectWrap {
BIO *bp = NULL;
EVP_PKEY* pkey;
- bp = BIO_new(BIO_s_mem());
+ bp = BIO_new(BIO_lring());
if(!BIO_write(bp, key_pem, key_pemLen)) return 0;
pkey = PEM_read_bio_PrivateKey( bp, NULL, NULL, NULL );
@@ -3550,7 +3551,7 @@ class Verify : public ObjectWrap {
X509 *x509 = NULL;
int r = 0;
- bp = BIO_new(BIO_s_mem());
+ bp = BIO_new(BIO_lring());
if (bp == NULL) {
ERR_print_errors_fp(stderr);
return 0;
Please sign in to comment.
Something went wrong with that request. Please try again.