timeout = max( 0, intval( $timeout ) ); } /** * Modify the lock timeout (microseconds). * * @param int $timeout * @param string $name * @param int $blog_id * * @return int */ $this->timeout = apply_filters( 'groups_lock_timeout', $this->timeout, $name, $blog_id ); if ( is_numeric( $this->timeout ) ) { $this->timeout = max( 0, intval( $this->timeout ) ); } else { $this->timeout = 0; } /** * Modify the lock sleep gap (microseconds). * * @param int $sleep * @param string $name * @param int $blog_id * * @return int */ $this->sleep = apply_filters( 'groups_lock_sleep', $this->sleep, $name, $blog_id ); if ( is_numeric( $this->sleep ) ) { $this->sleep = max( 1, intval( $this->sleep ) ); } else { $this->sleep = self::SLEEP_DEFAULT; } if ( is_string( $path ) ) { $h = @fopen( $path, 'c' ); if ( $h !== false ) { $this->path = $path; @fclose( $h ); } else { $error = error_get_last(); $msg = $error !== null && !empty( $error['message'] ) ? $error['message'] : ''; if ( !file_exists( $path ) ) { $error = sprintf( 'Failed to create lock %s [%s]', $path, $msg ); } else { $error = sprintf( 'Failed to access lock %s [%s]', $path, $msg ); } throw new Groups_Lock_Exception( $error ); } } register_shutdown_function( array( $this, 'release' ) ); } else { throw new Groups_Lock_Exception( 'Lock requires fopen, flock, fclose, is_readable' ); } } /** * Lock is usable. * * @return boolean */ public function is_usable() { return $this->path !== null && is_readable( $this->path ); } /** * Lock is locked. * * @since 4.3.0 * * @return boolean */ public function is_locked() { return $this->h !== null; } /** * Write lock. * * @throws Groups_Lock_Exception * * @return boolean */ public function writer() { if ( $this->path !== null ) { if ( $this->h === null ) { $h = @fopen( $this->path, 'r+' ); if ( $h !== false ) { if ( $this->timeout === 0 ) { // blocking if ( @flock( $h, LOCK_EX ) ) { $this->h = $h; } } else { // non-blocking if ( function_exists( 'microtime' ) && function_exists( 'usleep' ) ) { $t = microtime( true ) * 1000000; while ( $this->h === null && ( microtime( true ) * 1000000 - $t < $this->timeout ) ) { if ( @flock( $h, LOCK_EX | LOCK_NB ) ) { $this->h = $h; break; } else { usleep( $this->sleep ); } } } else { // fallback if required functions missing $t = time(); while ( $this->h === null && ( time() - $t < self::AUX_TIMEOUT ) ) { if ( @flock( $h, LOCK_EX | LOCK_NB ) ) { $this->h = $h; break; } else { sleep( 1 ); } } } } if ( $this->h === null ) { throw new Groups_Lock_Exception( sprintf( 'Failed to obtain write lock %s', $this->path ) ); } } else { throw new Groups_Lock_Exception( sprintf( 'Failed to access write lock %s ', $this->path ) ); } } } return $this->h !== null; } /** * Read lock. * * @throws Groups_Lock_Exception * * @return boolean */ public function reader() { if ( $this->path !== null ) { if ( $this->h === null ) { $h = @fopen( $this->path, 'r' ); if ( $h !== false ) { if ( $this->timeout === 0 ) { // blocking if ( @flock( $h, LOCK_SH ) ) { $this->h = $h; } } else { // non if ( function_exists( 'microtime' ) && function_exists( 'usleep' ) ) { $t = microtime( true ) * 1000000; while ( $this->h === null && ( microtime( true ) * 1000000 - $t < $this->timeout ) ) { if ( @flock( $h, LOCK_SH | LOCK_NB ) ) { $this->h = $h; break; } else { usleep( $this->sleep ); } } } else { // fallback $t = time(); while ( $this->h === null && ( time() - $t < self::AUX_TIMEOUT ) ) { if ( @flock( $h, LOCK_SH | LOCK_NB ) ) { $this->h = $h; break; } else { sleep( 1 ); } } } } if ( $this->h === null ) { throw new Groups_Lock_Exception( sprintf( 'Failed to obtain read lock %s', $this->path ) ); } } else { throw new Groups_Lock_Exception( sprintf( 'Failed to access read lock %s', $this->path ) ); } } } return $this->h !== null; } /** * Release lock. * * @return boolean */ public function release() { $released = false; if ( $this->h !== null ) { $released = @flock( $this->h, LOCK_UN ); @fclose( $this->h ); $this->h = null; } return $released; } }