aboutsummaryrefslogtreecommitdiffstats
path: root/android/utils/filelock.c
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2009-03-03 18:28:35 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2009-03-03 18:28:35 -0800
commitf721e3ac031f892af46f255a47d7f54a91317b30 (patch)
tree4b825dc642cb6eb9a060e54bf8d69288fbee4904 /android/utils/filelock.c
parentbae1bc39312d5019bd9a5b8d840a529213a69a17 (diff)
downloadexternal_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.c414
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;
-}