2013/8/22 ngoto (Naohisa Goto) ngotogenome@gmail.com:
Issue #8810 has been reported by ngoto (Naohisa Goto).
Bug #8810: SolarisでGDBM.open内で処理がブロックしたらTimeout.timeout が効かない
https://bugs.ruby-lang.org/issues/8810
Author: ngoto (Naohisa Goto)
Status: Open
Priority: Normal
Assignee:
Category: ext
Target version:
ruby -v: -
Backport: 1.9.3: UNKNOWN, 2.0.0: UNKNOWN
GDBM.open内で処理がブロックした場合にTimeout.timeoutが効きません。
再現方法は、Solarisにて、以下のようにGDBMをオープンしたままにして、
$ ruby -r gdbm -e 'db = GDBM.open("/var/tmp/tmpdb"); gets'
同一マシンで別のシェルで
$ ruby -r gdbm -r timeout -e 'Timeout.timeout(5) { db = GDBM.open("/var/tmp/tmpdb") }'
を実行しても、タイムアウトすることなく後者のGDBM.openがブロックし続けて終わりません。
Solarisだけでなく、Linux上にて、以下のように無理やりflockを使わないようconfigureしてmakeしたlibgdbm.soを使用した場合でも同様に再現しました。
ちらっと見たのですが、これはgdbmを直さないとどうしようもないような
以下コメント付きソースの抜粋。
int
_gdbm_lock_file (GDBM_FILE dbf)
{
#if HAVE_FCNTL_LOCK
struct flock fl;
#endif
int lock_val = -1;
#if HAVE_FLOCK // 最初にflockを試す
if (dbf->read_write == GDBM_READER)
lock_val = flock (dbf->desc, LOCK_SH + LOCK_NB); // この時はLOCK_NB使う
else
lock_val = flock (dbf->desc, LOCK_EX + LOCK_NB);
if ((lock_val == -1) && (errno == EWOULDBLOCK))
{
dbf->lock_type = LOCKING_NONE;
return lock_val;
}
else if (lock_val != -1)
{
dbf->lock_type = LOCKING_FLOCK;
return lock_val;
}
#endif
// 次に lockf ためす
#if HAVE_LOCKF
/* Mask doesn't matter for lockf. */
lock_val = lockf (dbf->desc, F_LOCK, (off_t)0L); // なぜか F_TLOCK つけない
if ((lock_val == -1) && (errno == EDEADLK))
{
dbf->lock_type = LOCKING_NONE;
return lock_val;
}
else if (lock_val != -1)
{
dbf->lock_type = LOCKING_LOCKF;
return lock_val;
}
#endif
// 最後に fcntl ためす
#if HAVE_FCNTL_LOCK
/* If we're still here, try fcntl. */
if (dbf->read_write == GDBM_READER)
fl.l_type = F_RDLCK;
else
fl.l_type = F_WRLCK;
fl.l_whence = SEEK_SET;
fl.l_start = fl.l_len = (off_t)0L;
lock_val = fcntl (dbf->desc, F_SETLK, &fl); // こんどはF_SETLKなので待たない
if (lock_val != -1)
dbf->lock_type = LOCKING_FCNTL;
#endif
if (lock_val == -1)
dbf->lock_type = LOCKING_NONE;
return lock_val;
}