Mail Archives: cygwin/2005/04/26/16:11:51
On Tue, 26 Apr 2005 09:21:40 -0400, Vladislav Grinchenko wrote:
>
> In short, this happens when I try to handle PID file locking to preclude
> multiple instances of the same program simultaneously running on a
> host.
>
> If there is a more preferable way of handling this task in cygwin/win32,
> I wouldn't mind implementing it.
You can use "file creation test & lock" instead of UNIX file area
locking. Attached source for "crtst-tmout" command is below.
To check if another copy is in memory you can check the /proc file
system. You can use the attached source below as an example.
Instead of /proc/<pid>/stat you may use /proc/<pid>/exename (this
does not exist on UNIX, and /proc/<pid>/exe needs root permission).
Ehud.
------------------------- proc fs searching -------------------------
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/types.h>
#include <signal.h> /* for kill */
char *get_pname ( pid_t pid ) ; /* find program name from pid
returns program name or ""
uses /proc/<pid>/stat */
pid_t next_pid ( int cont ) ; /* get next pid from /proc
cont should be 0 on 1st call,
!= 0 on continuation
returns: pid (>0)
0 - no more pids
<0 - error */
void kill_old ( void ) /* kill other instances */
{
pid_t my_pid , pid = 0 ; /* my pid , pid (temp) to check */
char my_name [ 256 ] , *pname ; /* my name, temp program name */
my_pid = getpid ( ) ; /* get my pid */
pname = get_pname ( my_pid ) ;
if ( *pname == 0 ) /* empty name - Error */
return ;
strcpy ( my_name ,pname ) ; /* save my name */
while ( ( pid = next_pid ( pid ) ) > 0 ) /* next pid */
{
if ( pid == my_pid ) /* ignore myself */
continue ;;
pname = get_pname ( pid ) ;
if ( strcmp ( my_name , pname ) == 0 )
kill ( pid , SIGKILL ) ; /* send the kill signal */
}
if ( pid < 0 ) /* no process found - ERROR */
return ; /* (must have found myself) */
}
/*============================================================================*/
char *get_pname ( pid_t pid ) /* find program name from pid */
{ /* use /proc/<pid>/stat */
FILE *stt ; /* stat virtual file Handel */
static char pname [256] , *none = "" ; /* program name is < 256 chars */
char *nbeg, *nend ; /* temp pointer */
/* structure of 1st and only line of /proc/<pid>/stat
pid (name) stt ..... name is the exact disk name (upper case under DOS)
1300 (bash) S 1 1300 1300 1280
1988 (SLeeP-TsT) S 1 1988 1988 1280 */
sprintf ( pname , "/proc/%d/stat" , pid ) ; /* stat file name */
stt = fopen ( pname , "rt" ) ; /* try to open */
if ( stt == NULL )
{
return ( none ) ; /* no name (error signal) */
}
fgets ( pname , 256 , stt ) ; /* read 1st (only) line from stat */
fclose ( stt ) ; /* close "stat", no check */
if ( ( nbeg = strchr ( pname , '(' ) ) == NULL )/* search "(" before name */
{
return ( none ) ; /* no name (error signal) */
}
if ( ( nend = strchr ( nbeg , ')' ) ) == NULL ) /* search ")" after name */
{
return ( none ) ; /* no name (error signal) */
}
*nend = 0 ; /* cap it */
return ( ++ nbeg ) ; /* 1st char of program name */
}
/*=========================================================================*/
pid_t next_pid ( int cont ) /* get next pid */
{ /* cont = 0 - start new search */
static DIR *hdir = NULL ; /* handle for open directory */
struct dirent *dent ; /* directory entry pointer */
#define FPID ( dent->d_name ) /* PID as file name pointer */
if ( cont == 0 ) /* new search */
{
if ( hdir != NULL ) /* a search in progress ? */
closedir ( hdir ) ; /* close directory (no check) */
if ( ( hdir = opendir ( "/proc" ) ) == NULL ) /* open directory "/proc" */
{
fprintf ( stderr , "Could not open \"/proc\" virtual directory.\n" ) ;
exit ( 1 ) ; /* error return ? */
}
}
if ( hdir == NULL ) /* no search started / already ended */
return ( -1 ) ; /* no next pid */
while ( ( dent = readdir ( hdir ) ) != NULL ) /* next entry */
{
if ( ( FPID [ 0 ] < '1' ) || /* pid number must start */
( FPID [ 0 ] > '9' ) ) /* with 1 to 9 digit */
continue ;
return ( atoi ( FPID ) ) ; /* return pid as number */
}
/* no more pids */
closedir ( hdir ) ; /* close directory (no check) */
hdir = NULL ; /* search ended ! */
return ( 0 ) ; /* no more pids */
}
/*=========================================================================*/
------------------------- crtest-tmout -------------------------
/* crtest-tmout: create file name (1st arg) with optional timeout (2nd arg)
Exit code is 0 if the file is created successfully.
If the file already exist the program sleeps for 7 seconds and trys again.
Exit code of 1 is returned if the file can not be created because of
any other error (invalid name, dir or system error).
2nd argument is immidate/timeout value:
Value of 0 cause the program to try only once and returns
exit code 2 if the file exist.
A positive value is Timoout (in seconds). If the lock age is
greater than this, the lock is removed.
*/
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h> /* standard library */
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h> /* for file 'stat' */
#include <time.h>
#include <unistd.h> /* exit/sleep functions */
#define SLEEP_TIME 7 /* time to sleep between trys */
char *locknm ; /* lock file name */
int tmout = -1 ; /* optional second arg - wait condition */
int chk_tmout ( void ) ; /* return 1 if lock has timed out */
void try_rplc ( void ) ; /* try to replace lock */
int main ( int argc, char *argv[] )
{
int hndl = -1; /* open file handle */
locknm = argv [ 1 ] ; /* lock file name */
if ( argc > 2 ) /* is there 2nd parameter ? */
tmout = atoi ( argv [ 2 ] ) ; /* Yes, get its numeric value */
while (hndl < 0)
{
hndl = open ( locknm , O_RDWR | O_CREAT | O_EXCL , 0666 ) ;
if ( hndl > 0 )
exit ( 0 ) ; /* all ok */
if (errno != EEXIST)
{
fprintf ( stderr , "File %s, open error: %d\n" , locknm , errno) ;
exit (1) ;
}
if ( tmout == 0 ) /* NO wait (2nd arg = 0) ? */
exit ( 2 ) ; /* yes exit with error code 2 */
if ( tmout > 0 ) /* Timeout value (2nd arg > 0) ? */
if ( chk_tmout () > 0 ) /* check if passed */
try_rplc ( ) ; /* YES, try replace */
sleep ( SLEEP_TIME ) ; /* no, wait for next time */
}
return ( 0 ) ;
}
/*===========================================================================*/
int chk_tmout ( void ) /* return 1 if lock has timed out */
{
struct stat fs ; /* input file statistics */
time_t crrnt , ltime ; /* seconds from 1/1/1970 0.0.0 GMT */
if ( stat ( locknm , & fs ) < 0 ) /* file statistics (times) */
return ( -1 ) ; /* Error (whatever) */
ltime = fs.st_mtime ; /* file time */
crrnt = time ( NULL ) ; /* current time */
if ( ( crrnt - ltime ) > tmout ) /* time out has passed */
return ( 1 ) ;
return ( -1 ) ; /* NOT timed out */
}
/*===========================================================================*/
void try_rplc ( void ) /* try to replace lock */
{
char *tmp_nm = NULL ;
size_t nmlng ;
int hndl ;
nmlng = strlen ( locknm ) + 15 ; /* name of temp secondary lock */
while ( ( tmp_nm = malloc ( nmlng ) ) == NULL )
sleep ( 1 ) ; /* wait 1 sec */
sprintf ( tmp_nm , "%s [*] temp" , locknm ) ; /* temp name */
hndl = open ( tmp_nm , O_RDWR | O_CREAT | O_EXCL , 0666 ) ;
if ( hndl > 0 )
{
if ( chk_tmout () > 0 ) /* Re check time out */
if ( rename ( tmp_nm , locknm ) == 0 ) /* rename succeeded */
exit ( 0 ) ; /* ALL OK ! ! ! */
close ( hndl ) ; /* better close (free handle) */
unlink ( tmp_nm ) ; /* MUST ! (otherwise will stop lock check) */
}
free ( tmp_nm ) ; /* free tmp_nm when failed */
}
/*===========================================================================*/
--
Ehud Karni Tel: +972-3-7966-561 /"\
Mivtach - Simon Fax: +972-3-7966-667 \ / ASCII Ribbon Campaign
Insurance agencies (USA) voice mail and X Against HTML Mail
http://www.mvs.co.il FAX: 1-815-5509341 / \
GnuPG: 98EA398D <http://www.keyserver.net/> Better Safe Than Sorry
--
Unsubscribe info: http://cygwin.com/ml/#unsubscribe-simple
Problem reports: http://cygwin.com/problems.html
Documentation: http://cygwin.com/docs.html
FAQ: http://cygwin.com/faq/
- Raw text -