diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 18:28:35 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 18:28:35 -0800 |
commit | f721e3ac031f892af46f255a47d7f54a91317b30 (patch) | |
tree | 4b825dc642cb6eb9a060e54bf8d69288fbee4904 /android/utils/filelock.c | |
parent | bae1bc39312d5019bd9a5b8d840a529213a69a17 (diff) | |
download | external_qemu-f721e3ac031f892af46f255a47d7f54a91317b30.zip external_qemu-f721e3ac031f892af46f255a47d7f54a91317b30.tar.gz external_qemu-f721e3ac031f892af46f255a47d7f54a91317b30.tar.bz2 |
auto import from //depot/cupcake/@135843
Diffstat (limited to 'android/utils/filelock.c')
-rw-r--r-- | android/utils/filelock.c | 414 |
1 files changed, 0 insertions, 414 deletions
diff --git a/android/utils/filelock.c b/android/utils/filelock.c deleted file mode 100644 index a8b18da..0000000 --- a/android/utils/filelock.c +++ /dev/null @@ -1,414 +0,0 @@ -/* Copyright (C) 2007-2008 The Android Open Source Project -** -** This software is licensed under the terms of the GNU General Public -** License version 2, as published by the Free Software Foundation, and -** may be copied, distributed, and modified under those terms. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -*/ - -#include "android/utils/filelock.h" -#include "android/utils/path.h" -#include <stdio.h> -#include <stdlib.h> -#include <errno.h> -#include <sys/stat.h> -#include <time.h> -#include <fcntl.h> -#ifdef _WIN32 -# include <process.h> -# include <windows.h> -# include <tlhelp32.h> -#else -# include <sys/types.h> -# include <unistd.h> -# include <signal.h> -#endif - -#define D(...) ((void)0) - -#ifndef CHECKED -# ifdef _WIN32 -# define CHECKED(ret, call) (ret) = (call) -# else -# define CHECKED(ret, call) do { (ret) = (call); } while ((ret) < 0 && errno == EINTR) -# endif -#endif - -/** FILE LOCKS SUPPORT - ** - ** a FileLock is useful to prevent several emulator instances from using the same - ** writable file (e.g. the userdata.img disk images). - ** - ** create a FileLock object with filelock_create(), ithis function should return NULL - ** only if the corresponding file path could not be locked. - ** - ** all file locks are automatically released and destroyed when the program exits. - ** the filelock_lock() function can also detect stale file locks that can linger - ** when the emulator crashes unexpectedly, and will happily clean them for you - ** - ** here's how it works, three files are used: - ** file - the data file accessed by the emulator - ** lock - a lock file (file + '.lock') - ** temp - a temporary file make unique with mkstemp - ** - ** when locking: - ** create 'temp' and store our pid in it - ** attemp to link 'lock' to 'temp' - ** if the link succeeds, we obtain the lock - ** unlink 'temp' - ** - ** when unlocking: - ** unlink 'lock' - ** - ** - ** on Windows, 'lock' is a directory name. locking is equivalent to - ** creating it... - ** - **/ - -struct FileLock -{ - const char* file; - const char* lock; - char* temp; - int locked; - FileLock* next; -}; - -/* used to cleanup all locks at emulator exit */ -static FileLock* _all_filelocks; - - -#define LOCK_NAME ".lock" -#define TEMP_NAME ".tmp-XXXXXX" - -#ifdef _WIN32 -#define PIDFILE_NAME "pid" -#endif - -/* returns 0 on success, -1 on failure */ -static int -filelock_lock( FileLock* lock ) -{ - int ret; -#ifdef _WIN32 - int pidfile_fd = -1; - - ret = _mkdir( lock->lock ); - if (ret < 0) { - if (errno == ENOENT) { - D( "could not access directory '%s', check path elements", lock->lock ); - return -1; - } else if (errno != EEXIST) { - D( "_mkdir(%s): %s", lock->lock, strerror(errno) ); - return -1; - } - - /* if we get here, it's because the .lock directory already exists */ - /* check to see if there is a pid file in it */ - D("directory '%s' already exist, waiting a bit to ensure that no other emulator instance is starting", lock->lock ); - { - int _sleep = 200; - int tries; - - for ( tries = 4; tries > 0; tries-- ) - { - pidfile_fd = open( lock->temp, O_RDONLY ); - - if (pidfile_fd >= 0) - break; - - Sleep( _sleep ); - _sleep *= 2; - } - } - - if (pidfile_fd < 0) { - D( "no pid file in '%s', assuming stale directory", lock->lock ); - } - else - { - /* read the pidfile, and check wether the corresponding process is still running */ - char buf[16]; - int len, lockpid; - HANDLE processSnapshot; - PROCESSENTRY32 pe32; - int is_locked = 0; - - len = read( pidfile_fd, buf, sizeof(buf)-1 ); - if (len < 0) { - D( "could not read pid file '%s'", lock->temp ); - close( pidfile_fd ); - return -1; - } - buf[len] = 0; - lockpid = atoi(buf); - - /* PID 0 is the IDLE process, and 0 is returned in case of invalid input */ - if (lockpid == 0) - lockpid = -1; - - close( pidfile_fd ); - - pe32.dwSize = sizeof( PROCESSENTRY32 ); - processSnapshot = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 ); - - if ( processSnapshot == INVALID_HANDLE_VALUE ) { - D( "could not retrieve the list of currently active processes\n" ); - is_locked = 1; - } - else if ( !Process32First( processSnapshot, &pe32 ) ) - { - D( "could not retrieve first process id\n" ); - CloseHandle( processSnapshot ); - is_locked = 1; - } - else - { - do { - if (pe32.th32ProcessID == lockpid) { - is_locked = 1; - break; - } - } while (Process32Next( processSnapshot, &pe32 ) ); - - CloseHandle( processSnapshot ); - } - - if (is_locked) { - D( "the file '%s' is locked by process ID %d\n", lock->file, lockpid ); - return -1; - } - } - } - - /* write our PID into the pid file */ - pidfile_fd = open( lock->temp, O_WRONLY | O_CREAT | O_TRUNC ); - if (pidfile_fd < 0) { - if (errno == EACCES) { - if ( path_delete_file( lock->temp ) < 0 ) { - D( "could not remove '%s': %s\n", lock->temp, strerror(errno) ); - return -1; - } - pidfile_fd = open( lock->temp, O_WRONLY | O_CREAT | O_TRUNC ); - } - if (pidfile_fd < 0) { - D( "could not create '%s': %s\n", lock->temp, strerror(errno) ); - return -1; - } - } - - { - char buf[16]; - sprintf( buf, "%ld", GetCurrentProcessId() ); - ret = write( pidfile_fd, buf, strlen(buf) ); - close(pidfile_fd); - if (ret < 0) { - D( "could not write PID to '%s'\n", lock->temp ); - return -1; - } - } - - lock->locked = 1; - return 0; -#else - int temp_fd = -1; - int lock_fd = -1; - int rc, tries, _sleep; - FILE* f = NULL; - char pid[8]; - struct stat st_temp; - - strcpy( lock->temp, lock->file ); - strcat( lock->temp, TEMP_NAME ); - temp_fd = mkstemp( lock->temp ); - - if (temp_fd < 0) { - D("cannot create locking temp file '%s'", lock->temp ); - goto Fail; - } - - sprintf( pid, "%d", getpid() ); - ret = write( temp_fd, pid, strlen(pid)+1 ); - if (ret < 0) { - D( "cannot write to locking temp file '%s'", lock->temp); - goto Fail; - } - close( temp_fd ); - temp_fd = -1; - - CHECKED(rc, lstat( lock->temp, &st_temp )); - if (rc < 0) { - D( "can't properly stat our locking temp file '%s'", lock->temp ); - goto Fail; - } - - /* now attempt to link the temp file to the lock file */ - _sleep = 0; - for ( tries = 4; tries > 0; tries-- ) - { - struct stat st_lock; - int rc; - - if (_sleep > 0) { - if (_sleep > 2000000) { - D( "cannot acquire lock file '%s'", lock->lock ); - goto Fail; - } - usleep( _sleep ); - } - _sleep += 200000; - - /* the return value of link() is buggy on NFS */ - CHECKED(rc, link( lock->temp, lock->lock )); - - CHECKED(rc, lstat( lock->lock, &st_lock )); - if (rc == 0 && - st_temp.st_rdev == st_lock.st_rdev && - st_temp.st_ino == st_lock.st_ino ) - { - /* SUCCESS */ - lock->locked = 1; - CHECKED(rc, unlink( lock->temp )); - return 0; - } - - /* if we get there, it means that the link() call failed */ - /* check the lockfile to see if it is stale */ - if (rc == 0) { - char buf[16]; - time_t now; - int lockpid = 0; - int lockfd; - int stale = 2; /* means don't know */ - struct stat st; - - CHECKED(rc, time( &now)); - st.st_mtime = now - 120; - - CHECKED(lockfd, open( lock->lock,O_RDONLY )); - if ( lockfd >= 0 ) { - int len; - - CHECKED(len, read( lockfd, buf, sizeof(buf)-1 )); - buf[len] = 0; - lockpid = atoi(buf); - - CHECKED(rc, fstat( lockfd, &st )); - if (rc == 0) - now = st.st_atime; - - CHECKED(rc, close(lockfd)); - } - /* if there is a PID, check that it is still alive */ - if (lockpid > 0) { - CHECKED(rc, kill( lockpid, 0 )); - if (rc == 0 || errno == EPERM) { - stale = 0; - } else if (rc < 0 && errno == ESRCH) { - stale = 1; - } - } - if (stale == 2) { - /* no pid, stale if the file is older than 1 minute */ - stale = (now >= st.st_mtime + 60); - } - - if (stale) { - D( "removing stale lockfile '%s'", lock->lock ); - CHECKED(rc, unlink( lock->lock )); - _sleep = 0; - tries++; - } - } - } - D("file '%s' is already in use by another process", lock->file ); - -Fail: - if (f) - fclose(f); - - if (temp_fd >= 0) { - close(temp_fd); - } - - if (lock_fd >= 0) { - close(lock_fd); - } - - unlink( lock->lock ); - unlink( lock->temp ); - return -1; -#endif -} - -void -filelock_release( FileLock* lock ) -{ - if (lock->locked) { -#ifdef _WIN32 - path_delete_file( (char*)lock->temp ); - rmdir( (char*)lock->lock ); -#else - unlink( (char*)lock->lock ); -#endif - lock->locked = 0; - } -} - -static void -filelock_atexit( void ) -{ - FileLock* lock; - - for (lock = _all_filelocks; lock != NULL; lock = lock->next) - filelock_release( lock ); -} - -/* create a file lock */ -FileLock* -filelock_create( const char* file ) -{ - int file_len = strlen(file); - int lock_len = file_len + sizeof(LOCK_NAME); -#ifdef _WIN32 - int temp_len = lock_len + 1 + sizeof(PIDFILE_NAME); -#else - int temp_len = file_len + sizeof(TEMP_NAME); -#endif - int total_len = sizeof(FileLock) + file_len + lock_len + temp_len + 3; - - FileLock* lock = malloc(total_len); - - lock->file = (const char*)(lock + 1); - memcpy( (char*)lock->file, file, file_len+1 ); - - lock->lock = lock->file + file_len + 1; - memcpy( (char*)lock->lock, file, file_len+1 ); - strcat( (char*)lock->lock, LOCK_NAME ); - - lock->temp = (char*)lock->lock + lock_len + 1; -#ifdef _WIN32 - snprintf( (char*)lock->temp, temp_len, "%s\\" PIDFILE_NAME, lock->lock ); -#else - lock->temp[0] = 0; -#endif - lock->locked = 0; - - if (filelock_lock(lock) < 0) { - free(lock); - return NULL; - } - - lock->next = _all_filelocks; - _all_filelocks = lock; - - if (lock->next == NULL) - atexit( filelock_atexit ); - - return lock; -} |