c_buffer 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
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: []