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 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: []