From: bugs dot php dot net at chsc dot dk Operating system: Linux PHP version: 5.0.5 PHP Bug Type: Directory function related Bug description: Concurrency issue with recursive mkdir
Description: ------------ There appears to be a concurrency issue when mkdir is called on two separate threads with the following parameters: Thread 1: mkdir('/tmp/foo/bar/1', 0777, true); Thread 2: mkdir('/tmp/foo/bar/2', 0777, true); Sometimes one of the threads (e.g. thread 2) two fails with "Warning: mkdir(): File exists" and the directory /tmp/foo/bar/2 does not exist afterwards. What I think is happening in thread 2 is is this: PHP looks for /tmp/foo/bar/2 and sees that it does not exist. Neither does /tmp/foo/bar and /tmp/foo. So it tries to create /tmp/foo, but that directory was just created a millisecond second ago by another thread, so mkdir gives instead of just moving on to create /tmp/foo/bar and /tmp/foo/bar/2. Reproduce code: --------------- This code reproduces the problem in about every second attempt. It consists of two files, index.php and iframe.php. index.php: <?php $fire = time() + 2; ?> <h1>Nr. 1</h1> <iframe src="iframe.php?fire=<?= $fire ?>&no=1"></iframe> <h1>Nr. 2</h1> <iframe src="iframe.php?fire=<?= $fire ?>&no=2"></iframe> iframe.php: <?php $fire = $_GET['fire']; $no = $_GET['no']; // synchronize the two threads while ($fire > time()); $dir = '/tmp/' . $fire . '/foo/bar/foo/bar/' . $no; //sleep($no); var_dump(is_dir($dir)); echo "Making $dir "; mkdir($dir, 0777, true); var_dump(is_dir($dir)); ?> Expected result: ---------------- Thread 2 should output this: bool(false) Making /tmp/1132653651/foo/bar/foo/bar/2 bool(true) Actual result: -------------- Thread 2 sometimes outputs this: bool(false) Making /tmp/1132655181/foo/bar/foo/bar/2 Warning: mkdir(): File exists in /home/chsc/public_html/mkdir/iframe.php on line 10 bool(false) Notice that the directory does not exist afterwards. If I uncomment the sleep() call above, there are no problems. A workaround: $ok = mkdir($dir, 0777, true); if (!$ok && !is_dir($dir)) { sleep(1); mkdir($dir, 0777, true); } In other words, it works if I try again. I hope that mkdir() can be changed so that it only returns false if the directory cannot be created at all (e.g. because of lack of permissions or because it already exists). -- Edit bug report at http://bugs.php.net/?id=35326&edit=1 -- Try a CVS snapshot (php4): http://bugs.php.net/fix.php?id=35326&r=trysnapshot4 Try a CVS snapshot (php5.0): http://bugs.php.net/fix.php?id=35326&r=trysnapshot50 Try a CVS snapshot (php5.1): http://bugs.php.net/fix.php?id=35326&r=trysnapshot51 Fixed in CVS: http://bugs.php.net/fix.php?id=35326&r=fixedcvs Fixed in release: http://bugs.php.net/fix.php?id=35326&r=alreadyfixed Need backtrace: http://bugs.php.net/fix.php?id=35326&r=needtrace Need Reproduce Script: http://bugs.php.net/fix.php?id=35326&r=needscript Try newer version: http://bugs.php.net/fix.php?id=35326&r=oldversion Not developer issue: http://bugs.php.net/fix.php?id=35326&r=support Expected behavior: http://bugs.php.net/fix.php?id=35326&r=notwrong Not enough info: http://bugs.php.net/fix.php?id=35326&r=notenoughinfo Submitted twice: http://bugs.php.net/fix.php?id=35326&r=submittedtwice register_globals: http://bugs.php.net/fix.php?id=35326&r=globals PHP 3 support discontinued: http://bugs.php.net/fix.php?id=35326&r=php3 Daylight Savings: http://bugs.php.net/fix.php?id=35326&r=dst IIS Stability: http://bugs.php.net/fix.php?id=35326&r=isapi Install GNU Sed: http://bugs.php.net/fix.php?id=35326&r=gnused Floating point limitations: http://bugs.php.net/fix.php?id=35326&r=float No Zend Extensions: http://bugs.php.net/fix.php?id=35326&r=nozend MySQL Configuration Error: http://bugs.php.net/fix.php?id=35326&r=mysqlcfg