c_buffer 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README +22 -0
- data/ext/c_buffer/c_buffer.c +166 -0
- data/ext/c_buffer/c_buffer.h +42 -0
- data/lib/c_buffer.rb +79 -0
- data/lib/c_buffer/c_buffer.dll +0 -0
- data/lib/c_buffer/c_buffer.so +0 -0
- data/rakefile.rb +32 -0
- data/test/test_c_buffer.rb +17 -0
- metadata +64 -0
data/README
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
##
|
2
|
+
#
|
3
|
+
# CBuffer
|
4
|
+
#
|
5
|
+
# Simple circular buffer for staging data before writing to disk
|
6
|
+
#
|
7
|
+
# author hugo benichi
|
8
|
+
# email hugo.benichi@m4x.org
|
9
|
+
# copyright 2012 hugo benichi
|
10
|
+
# version 0.1.0
|
11
|
+
#
|
12
|
+
##
|
13
|
+
|
14
|
+
installation:
|
15
|
+
|
16
|
+
run "rake install" in the root directory
|
17
|
+
it will compile the gem library and produce a .gem package for ruby
|
18
|
+
it will then install the .gem automatically
|
19
|
+
|
20
|
+
usage, test:
|
21
|
+
|
22
|
+
cf test/test_cbuffer.rb
|
@@ -0,0 +1,166 @@
|
|
1
|
+
/*
|
2
|
+
*
|
3
|
+
* CBuffer
|
4
|
+
*
|
5
|
+
* Simple circular buffer for staging data before writing to disk
|
6
|
+
*
|
7
|
+
* author hugo benichi
|
8
|
+
* email hugo.benichi@m4x.org
|
9
|
+
* copyright 2012 hugo benichi
|
10
|
+
* version 0.1.1
|
11
|
+
*
|
12
|
+
*/
|
13
|
+
|
14
|
+
|
15
|
+
#include <stdlib.h>
|
16
|
+
#include <stdio.h>
|
17
|
+
#include <c_buffer.h>
|
18
|
+
#include <assert.h>
|
19
|
+
|
20
|
+
|
21
|
+
DLL cbuffer*
|
22
|
+
cbuffer_new(
|
23
|
+
int chunk, // the size in byte of one chunk of buffer memory
|
24
|
+
int size // the total size in byte of the buffer, at creation
|
25
|
+
)
|
26
|
+
{
|
27
|
+
assert(chunk > 0);
|
28
|
+
assert(size > 0);
|
29
|
+
|
30
|
+
int n = size / chunk;
|
31
|
+
if (!n) n = 2;
|
32
|
+
|
33
|
+
link* lnk_ary = malloc( n * sizeof(link) );
|
34
|
+
|
35
|
+
if ( !lnk_ary )
|
36
|
+
fprintf(stderr,"cbuffer.c: error while allocating memory for new cbuffer\n");
|
37
|
+
|
38
|
+
int i = 0;
|
39
|
+
while( n - i)
|
40
|
+
{
|
41
|
+
lnk_ary[i].mem = malloc(chunk);
|
42
|
+
if( !( lnk_ary[i].mem ) )
|
43
|
+
fprintf(stderr,"cbuffer.c: error while allocating memory for new cbuffer\n");
|
44
|
+
if(i+1 < n)
|
45
|
+
lnk_ary[i].next = &lnk_ary[i+1];
|
46
|
+
i++;
|
47
|
+
}
|
48
|
+
lnk_ary[n-1].next = lnk_ary;
|
49
|
+
|
50
|
+
|
51
|
+
cbuffer* cbuf = malloc(sizeof(cbuffer));
|
52
|
+
if ( !cbuf )
|
53
|
+
fprintf(stderr,"cbuffer.c: error while allocating memory for new cbuffer\n");
|
54
|
+
|
55
|
+
cbuf->inbound = lnk_ary; // start feeding at mem[0]
|
56
|
+
//cbuf->start = lnk_ary; // remember mem[0]
|
57
|
+
cbuf->start = NULL; // remember mem[0]
|
58
|
+
cbuf->outbound = NULL; // null until inbound != start
|
59
|
+
cbuf->stop = NULL; // when not null inbound as stopped at stop
|
60
|
+
cbuf->output = NULL;
|
61
|
+
cbuf->chunk = chunk;
|
62
|
+
|
63
|
+
return cbuf;
|
64
|
+
}
|
65
|
+
|
66
|
+
|
67
|
+
DLL void
|
68
|
+
cbuffer_free(cbuffer* buf)
|
69
|
+
{
|
70
|
+
link* l = buf->start;
|
71
|
+
link* s = buf->start;
|
72
|
+
while( l != s)
|
73
|
+
{
|
74
|
+
free(l->mem);
|
75
|
+
l = l->next;
|
76
|
+
}
|
77
|
+
free( buf->start );
|
78
|
+
free( buf );
|
79
|
+
}
|
80
|
+
|
81
|
+
|
82
|
+
DLL void
|
83
|
+
cbuffer_open(
|
84
|
+
cbuffer* buf,
|
85
|
+
const char* address
|
86
|
+
)
|
87
|
+
{
|
88
|
+
buf-> output = fopen(address, "w" );
|
89
|
+
|
90
|
+
if( !(buf->output) )
|
91
|
+
fprintf(stderr, "cbuffer.c: error while opening file %s\n", address);
|
92
|
+
|
93
|
+
}
|
94
|
+
|
95
|
+
|
96
|
+
DLL char*
|
97
|
+
cbuffer_next(cbuffer* buf)
|
98
|
+
{
|
99
|
+
if ( buf->start ) // wait until the next buffer is free
|
100
|
+
{
|
101
|
+
while( buf->inbound->next == buf->outbound ); //busy wait until the next buffer is free
|
102
|
+
buf->inbound = buf->inbound->next;
|
103
|
+
} else {
|
104
|
+
buf->start = buf->inbound;
|
105
|
+
}
|
106
|
+
return buf->inbound->mem;
|
107
|
+
}
|
108
|
+
|
109
|
+
|
110
|
+
DLL char*
|
111
|
+
cbuffer_has_next(cbuffer* buf)
|
112
|
+
{
|
113
|
+
char* out = NULL;
|
114
|
+
if ( buf->start )
|
115
|
+
{
|
116
|
+
if( buf->inbound != buf->outbound )
|
117
|
+
{
|
118
|
+
buf->inbound = buf->inbound->next;
|
119
|
+
out = buf->inbound->mem;
|
120
|
+
}
|
121
|
+
} else {
|
122
|
+
buf->start = buf->inbound;
|
123
|
+
out = buf->inbound->mem;
|
124
|
+
}
|
125
|
+
return out;
|
126
|
+
}
|
127
|
+
|
128
|
+
|
129
|
+
DLL void
|
130
|
+
cbuffer_stop(cbuffer* buf)
|
131
|
+
{
|
132
|
+
buf->stop = buf->inbound;
|
133
|
+
buf->inbound = buf->inbound->next;
|
134
|
+
}
|
135
|
+
|
136
|
+
|
137
|
+
DLL int
|
138
|
+
cbuffer_write(cbuffer* buf)
|
139
|
+
{
|
140
|
+
while( !( buf->start ) || buf->inbound == buf->start);
|
141
|
+
// busy wait while the first buffer is written
|
142
|
+
|
143
|
+
buf->outbound = buf->start;
|
144
|
+
|
145
|
+
int count = 0;
|
146
|
+
while( !( buf->stop ) )
|
147
|
+
{
|
148
|
+
fwrite( buf->outbound->mem, 1, buf-> chunk, buf-> output);
|
149
|
+
count += buf->chunk;
|
150
|
+
|
151
|
+
buf->outbound = buf->outbound->next;
|
152
|
+
while(buf->outbound == buf->inbound); //busy wait
|
153
|
+
}
|
154
|
+
|
155
|
+
while(1)
|
156
|
+
{
|
157
|
+
fwrite( buf->outbound->mem, 1, buf-> chunk, buf-> output);
|
158
|
+
count += 1;
|
159
|
+
if( buf->stop == buf->outbound )
|
160
|
+
break;
|
161
|
+
buf->outbound = buf->outbound->next;
|
162
|
+
}
|
163
|
+
|
164
|
+
fclose(buf->output);
|
165
|
+
return count;
|
166
|
+
}
|
@@ -0,0 +1,42 @@
|
|
1
|
+
#include <stdio.h>
|
2
|
+
|
3
|
+
|
4
|
+
#if defined(_WIN32)
|
5
|
+
#define DLL extern __declspec(dllexport)
|
6
|
+
#else
|
7
|
+
#define DLL
|
8
|
+
#endif
|
9
|
+
|
10
|
+
|
11
|
+
typedef struct cbuffer cbuffer;
|
12
|
+
typedef struct link link;
|
13
|
+
|
14
|
+
|
15
|
+
struct
|
16
|
+
cbuffer // 192 bytes on 32bits machines and 352 bytes on 64bits machines
|
17
|
+
{
|
18
|
+
link* inbound; // next buffer memory for incoming data
|
19
|
+
link* outbound; // next buffer memory for writing
|
20
|
+
link* start; // start of the memory (used for cleaning and init)
|
21
|
+
link* stop; // where to write to
|
22
|
+
FILE* output; // file
|
23
|
+
int chunk; // size of one chunk
|
24
|
+
};
|
25
|
+
|
26
|
+
|
27
|
+
struct
|
28
|
+
link
|
29
|
+
{
|
30
|
+
char* mem;
|
31
|
+
link* next;
|
32
|
+
};
|
33
|
+
|
34
|
+
|
35
|
+
DLL cbuffer* cbuffer_new (int chunk, int size); // size is n_chunk * chunk
|
36
|
+
DLL void cbuffer_free (cbuffer*); // don't forget to close output if open
|
37
|
+
DLL void cbuffer_open (cbuffer*, const char* ); // open a new file at the given path
|
38
|
+
|
39
|
+
DLL char* cbuffer_next (cbuffer*); // blocking, return the next buffer memory inline
|
40
|
+
DLL char* cbuffer_has_next (cbuffer*); // non-blocking, return null if not ready
|
41
|
+
DLL void cbuffer_stop (cbuffer*); // flag for stopping (cut the circular list)
|
42
|
+
DLL int cbuffer_write (cbuffer*); // blocking, write everything untill stop
|
data/lib/c_buffer.rb
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
##
|
2
|
+
#
|
3
|
+
# CBuffer
|
4
|
+
#
|
5
|
+
# Simple circular buffer for staging data before writing to disk
|
6
|
+
#
|
7
|
+
# author hugo benichi
|
8
|
+
# email hugo.benichi@m4x.org
|
9
|
+
# copyright 2012 hugo benichi
|
10
|
+
# version 0.1.1
|
11
|
+
#
|
12
|
+
##
|
13
|
+
|
14
|
+
# Main class and namespace of the program
|
15
|
+
# This class should be instancied to use a buffer
|
16
|
+
class CBuffer
|
17
|
+
|
18
|
+
require 'ffi'
|
19
|
+
|
20
|
+
# the API module wraps the native functions of cbuffer.c
|
21
|
+
module API
|
22
|
+
extend FFI::Library
|
23
|
+
lib_type = ENV["OS"] ? "dll" : "so"
|
24
|
+
#ffi_lib $LOAD_PATH.map{ |p| p + "/cbuffer/cbuffer.#{lib_type}" }
|
25
|
+
ffi_lib File.dirname(__FILE__) + "/c_buffer/c_buffer.#{lib_type}"
|
26
|
+
[
|
27
|
+
[ :cbuffer_new, [:int32, :int32], :pointer ],
|
28
|
+
[ :cbuffer_free, [:pointer], :void ],
|
29
|
+
[ :cbuffer_open, [:pointer, :pointer], :void ],
|
30
|
+
[ :cbuffer_next, [:pointer], :pointer, :blocking => true ],
|
31
|
+
[ :cbuffer_has_next, [:pointer], :pointer ],
|
32
|
+
[ :cbuffer_stop, [:pointer], :void ],
|
33
|
+
[ :cbuffer_write, [:pointer], :int32, :blocking => true ],
|
34
|
+
].each{ |sig| attach_function *sig }
|
35
|
+
end
|
36
|
+
|
37
|
+
# the CBufferRaw class wraps the native struct memory used to store the buffer memory
|
38
|
+
# not used at the momentm here for reference only
|
39
|
+
class CBufferRaw < FFI::Struct
|
40
|
+
layout :inbound, :pointer,
|
41
|
+
:outbound, :pointer,
|
42
|
+
:start, :pointer,
|
43
|
+
:stop, :pointer,
|
44
|
+
:output, :pointer,
|
45
|
+
:chunk, :int
|
46
|
+
end
|
47
|
+
|
48
|
+
def initialize args
|
49
|
+
chunk = args[:chunk] || 1
|
50
|
+
length = args[:length] || 2
|
51
|
+
path = args[:path] || 1
|
52
|
+
@struct = API::cbuffer_new chunk, length
|
53
|
+
API::cbuffer_open @struct, path
|
54
|
+
self
|
55
|
+
end
|
56
|
+
|
57
|
+
def write &block
|
58
|
+
running = true
|
59
|
+
self.define_singleton_method :stop do
|
60
|
+
API.cbuffer_stop @struct
|
61
|
+
sleep 1 while running
|
62
|
+
API.cbuffer_free @struct
|
63
|
+
end
|
64
|
+
Thread.new do
|
65
|
+
begin
|
66
|
+
count = API.cbuffer_write @struct
|
67
|
+
running = false
|
68
|
+
block.call(count) if block
|
69
|
+
catch
|
70
|
+
puts "error in writing thread"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def next
|
76
|
+
API.cbuffer_next @struct
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
Binary file
|
Binary file
|
data/rakefile.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
|
2
|
+
name = "c_buffer"
|
3
|
+
|
4
|
+
lib_type = ENV["OS"] ? "dll" : "so"
|
5
|
+
lib_file = "./lib/%s/%s.%s" % [name,name,lib_type]
|
6
|
+
src_file = "./ext/%s/%s.c" % [name,name]
|
7
|
+
hdr_path = "./ext/%s" % name
|
8
|
+
|
9
|
+
flags = ENV["OS"] ? "-D _WIN32" : "-fPIC"
|
10
|
+
|
11
|
+
task :compile => lib_file
|
12
|
+
|
13
|
+
task lib_file => src_file do
|
14
|
+
sh "gcc -shared -o #{lib_file} #{src_file} -I#{hdr_path} #{flags}"
|
15
|
+
end
|
16
|
+
|
17
|
+
task :test_global do
|
18
|
+
ruby "test/test_%s.rb" % name
|
19
|
+
end
|
20
|
+
|
21
|
+
task :test_local do
|
22
|
+
ruby "-I./lib test/test_%s.rb" % name
|
23
|
+
end
|
24
|
+
|
25
|
+
task :gem_install => :gem_build do
|
26
|
+
gemfile = Dir.new("./").entries.select{ |f| f =~ /cbuffer-[\d]+\.[\d]+\.[\d]+.gem/ }[0]
|
27
|
+
sh "gem install %s" % gemfile
|
28
|
+
end
|
29
|
+
|
30
|
+
task :gem_build => :compile do
|
31
|
+
sh "gem build %s.gemspec" % name
|
32
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'c_buffer'
|
2
|
+
|
3
|
+
repet = 126
|
4
|
+
chunk = 1024*126
|
5
|
+
length = chunk * 64
|
6
|
+
|
7
|
+
|
8
|
+
buf = CBuffer.new( path: "./data", chunk: chunk, length: length )
|
9
|
+
buf.write{ |count| puts "wrote #{count} bytes of data" }
|
10
|
+
|
11
|
+
data = Array.new(chunk){rand 255}
|
12
|
+
|
13
|
+
repet.times do |i|
|
14
|
+
buf.next.put_array_of_uchar 0, data
|
15
|
+
end
|
16
|
+
|
17
|
+
buf.stop
|
metadata
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: c_buffer
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.2
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Hugo Benichi
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-07-05 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: ffi
|
16
|
+
requirement: &19284820 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *19284820
|
25
|
+
description: A simple circular buffer and its Ruby interface to go along RbScope and
|
26
|
+
RbVisa. Perfect for staging high throughput input data to low throughput I/O.
|
27
|
+
email: hugo.benichi@m4x.org
|
28
|
+
executables: []
|
29
|
+
extensions: []
|
30
|
+
extra_rdoc_files: []
|
31
|
+
files:
|
32
|
+
- lib/c_buffer.rb
|
33
|
+
- lib/c_buffer/c_buffer.so
|
34
|
+
- lib/c_buffer/c_buffer.dll
|
35
|
+
- ext/c_buffer/c_buffer.c
|
36
|
+
- ext/c_buffer/c_buffer.h
|
37
|
+
- rakefile.rb
|
38
|
+
- README
|
39
|
+
- test/test_c_buffer.rb
|
40
|
+
homepage: http://github.com/hugobenichi/cbuffer
|
41
|
+
licenses: []
|
42
|
+
post_install_message:
|
43
|
+
rdoc_options: []
|
44
|
+
require_paths:
|
45
|
+
- lib
|
46
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
47
|
+
none: false
|
48
|
+
requirements:
|
49
|
+
- - ! '>='
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: '0'
|
52
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ! '>='
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: '0'
|
58
|
+
requirements: []
|
59
|
+
rubyforge_project:
|
60
|
+
rubygems_version: 1.8.11
|
61
|
+
signing_key:
|
62
|
+
specification_version: 3
|
63
|
+
summary: A simple circular buffer and its Ruby interface
|
64
|
+
test_files: []
|