Project

General

Profile

Feature #4464 ยป 0001-add-Fcntl-Flock-object-for-easier-use-of-POSIX-file-.patch

normalperson (Eric Wong), 03/04/2011 04:42 AM

View differences:

ext/fcntl/extconf.rb
1 1
require 'mkmf'
2
have_type('struct flock', %w(unistd.h fcntl.h))
2 3
create_makefile('fcntl')
ext/fcntl/fcntl.c
33 33

  
34 34
#include "ruby.h"
35 35
#include <fcntl.h>
36
static void Init_FcntlFlock(VALUE);
36 37

  
37 38
/* Fcntl loads the constants defined in the system's <fcntl.h> C header
38 39
 * file, and used with both the fcntl(2) and open(2) POSIX system calls.
......
113 114
Init_fcntl()
114 115
{
115 116
    VALUE mFcntl = rb_define_module("Fcntl");
117
    Init_FcntlFlock(mFcntl);
118

  
116 119
#ifdef F_DUPFD
117 120
    rb_define_const(mFcntl, "F_DUPFD", INT2NUM(F_DUPFD));
118 121
#endif
......
185 188
    rb_define_const(mFcntl, "O_ACCMODE", INT2FIX(O_RDONLY | O_WRONLY | O_RDWR));
186 189
#endif
187 190
}
191

  
192
#ifdef HAVE_TYPE_STRUCT_FLOCK
193
static short
194
num2short(VALUE val)
195
{
196
    int i = NUM2INT(val);
197

  
198
    if (i != (short)i) {
199
	const char *s = i > 0 ? "big" : "small";
200
	rb_raise(rb_eRangeError, "Integer %d too %s to for `short'", i, s);
201
    }
202

  
203
    return (short)i;
204
}
205

  
206
static struct flock *
207
flock_ptr(VALUE self)
208
{
209
    if (RSTRING_LEN(self) < sizeof(struct flock))
210
	rb_raise(rb_eRuntimeError, "flock buffer shortened");
211
    rb_str_modify(self);
212

  
213
    return (struct flock *)RSTRING_PTR(self);
214
}
215

  
216
static VALUE
217
flock_init(int argc, VALUE *argv, VALUE self)
218
{
219
    struct flock *flock;
220
    VALUE type, whence, start, len;
221

  
222
    rb_str_resize(self, sizeof(struct flock));
223
    flock = flock_ptr(self);
224
    rb_scan_args(argc, argv, "04", &type, &whence, &start, &len);
225
    flock->l_type = NIL_P(type) ? F_RDLCK : num2short(type);
226
    flock->l_whence = NIL_P(whence) ? SEEK_SET : num2short(whence);
227
    flock->l_start = NIL_P(start) ? 0 : NUM2OFFT(start);
228
    flock->l_len = NIL_P(len) ? 0 : NUM2OFFT(len);
229
    flock->l_pid = (pid_t)-1;
230

  
231
    return self;
232
}
233

  
234
static VALUE
235
l_type(VALUE self)
236
{
237
    return INT2NUM(flock_ptr(self)->l_type);
238
}
239

  
240
static VALUE
241
set_l_type(VALUE self, VALUE val)
242
{
243
    flock_ptr(self)->l_type = num2short(val);
244

  
245
    return val;
246
}
247

  
248
static VALUE
249
l_whence(VALUE self)
250
{
251
    return INT2NUM(flock_ptr(self)->l_whence);
252
}
253

  
254
static VALUE
255
set_l_whence(VALUE self, VALUE val)
256
{
257
    flock_ptr(self)->l_whence = num2short(val);
258

  
259
    return val;
260
}
261

  
262
static VALUE
263
l_start(VALUE self)
264
{
265
    return OFFT2NUM(flock_ptr(self)->l_start);
266
}
267

  
268
static VALUE
269
set_l_start(VALUE self, VALUE val)
270
{
271
    flock_ptr(self)->l_start = NUM2OFFT(val);
272

  
273
    return val;
274
}
275

  
276
static VALUE
277
l_len(VALUE self)
278
{
279
    return OFFT2NUM(flock_ptr(self)->l_len);
280
}
281

  
282
static VALUE
283
set_l_len(VALUE self, VALUE val)
284
{
285
    flock_ptr(self)->l_len = NUM2OFFT(val);
286

  
287
    return val;
288
}
289

  
290
static VALUE
291
l_pid(VALUE self)
292
{
293
    return PIDT2NUM(flock_ptr(self)->l_pid);
294
}
295

  
296
static VALUE
297
flock_inspect(VALUE self)
298
{
299
    struct flock *flock = flock_ptr(self);
300
    const char fmt[] = "#<%s: type=%s, whence=%s, start=%lld, len=%lld, pid=%ld>";
301
    const char *name = rb_obj_classname(self);
302
    const char *type, *whence;
303

  
304
    switch (flock->l_type) {
305
    case F_RDLCK: type = "Fcntl::F_RDLCK"; break;
306
    case F_WRLCK: type = "Fcntl::F_WRLCK"; break;
307
    case F_UNLCK: type = "Fcntl::F_UNLCK"; break;
308
    default: type = "(unknown)";
309
    }
310

  
311
    switch (flock->l_whence) {
312
    case SEEK_SET: whence = "IO::SEEK_SET"; break;
313
    case SEEK_CUR: whence = "IO::SEEK_CUR"; break;
314
    case SEEK_END: whence = "IO::SEEK_END"; break;
315
    default: whence = "(unknown)";
316
    }
317

  
318
    return rb_sprintf(fmt, name, type, whence,
319
		      (unsigned long long)flock->l_start,
320
		      (unsigned long long)flock->l_len,
321
		      (long)flock->l_pid);
322
}
323

  
324
static void
325
Init_FcntlFlock(VALUE mFcntl)
326
{
327
    VALUE cFcntlFlock = rb_define_class_under(mFcntl, "Flock", rb_cString);
328

  
329
    rb_define_private_method(cFcntlFlock, "initialize", flock_init, -1);
330

  
331
    rb_define_method(cFcntlFlock, "type", l_type, 0);
332
    rb_define_method(cFcntlFlock, "type=", set_l_type, 1);
333

  
334
    rb_define_method(cFcntlFlock, "whence", l_whence, 0);
335
    rb_define_method(cFcntlFlock, "whence=", set_l_whence, 1);
336

  
337
    rb_define_method(cFcntlFlock, "start", l_start, 0);
338
    rb_define_method(cFcntlFlock, "start=", set_l_start, 1);
339

  
340
    rb_define_method(cFcntlFlock, "len", l_len, 0);
341
    rb_define_method(cFcntlFlock, "len=", set_l_len, 1);
342

  
343
    rb_define_method(cFcntlFlock, "pid", l_pid, 0);
344

  
345
    rb_define_method(cFcntlFlock, "inspect", flock_inspect, 0);
346
}
347
#else /* ! HAVE_TYPE_STRUCT_FLOCK */
348
static void Init_FcntlFlock(VALUE mFcntl) { }
349
#endif /* HAVE_TYPE_STRUCT_FLOCK */
test/fcntl/test_fcntl_flock.rb
1
require "test/unit"
2
begin
3
  require "fcntl"
4
rescue LoadError
5
end
6
require "tempfile"
7

  
8
class TestFcntlFlock < Test::Unit::TestCase
9

  
10
  def test_initialize_noargs
11
    flock = Fcntl::Flock.new
12
    assert_equal Fcntl::F_RDLCK, flock.type
13
    assert_equal IO::SEEK_SET, flock.whence
14
    assert_equal 0, flock.start
15
    assert_equal 0, flock.len
16
  end
17

  
18
  def test_inspect
19
    expect = "#<Fcntl::Flock: type=Fcntl::F_RDLCK, whence=IO::SEEK_SET, " \
20
             "start=0, len=0, pid=-1>"
21
    assert_equal expect, Fcntl::Flock.new.inspect
22
  end
23

  
24
  def test_initialize_write_lock
25
    flock = Fcntl::Flock.new Fcntl::F_WRLCK
26
    assert_equal Fcntl::F_WRLCK, flock.type
27
    assert_equal IO::SEEK_SET, flock.whence
28
    assert_equal 0, flock.start
29
    assert_equal 0, flock.len
30
  end
31

  
32
  def test_accessors
33
    flock = Fcntl::Flock.new
34
    assert_kind_of Integer, flock.pid
35

  
36
    flock.type = Fcntl::F_UNLCK
37
    assert_equal Fcntl::F_UNLCK, flock.type
38

  
39
    flock.whence = IO::SEEK_CUR
40
    assert_equal IO::SEEK_CUR, flock.whence
41

  
42
    flock.len = 2
43
    assert_equal 2, flock.len
44

  
45
    flock.start = 3
46
    assert_equal 3, flock.start
47
  end
48

  
49
  def test_get_lock
50
    lock = Fcntl::Flock.new Fcntl::F_WRLCK
51
    pid = nil
52
    Tempfile.open(self.class.name) do |tmp|
53
      r, w = IO.pipe
54
      pid = fork do
55
        File.open(tmp.path, "wb") do |fp|
56
          fp.fcntl Fcntl::F_SETLKW, lock
57
          r.close
58
          w.syswrite "."
59
          sleep
60
        end
61
      end
62
      w.close
63
      assert_equal ".", r.read(1)
64
      r.close
65
      tmp.fcntl Fcntl::F_GETLK, lock
66
    end
67
    assert_equal pid, lock.pid
68
    Process.kill :TERM, pid
69
    Process.waitpid2(pid)
70
  end
71
end if defined? Fcntl::Flock
0
-