From: KOSAKI Motohiro Date: 2013-08-23T19:24:29-04:00 Subject: [ruby-dev:47655] Re: [ruby-trunk - Bug #8810][Open] SolarisでGDBM.open内で処理がブロックしたらTimeout.timeout が効かない 2013/8/22 ngoto (Naohisa Goto) : > > 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; }