-
Notifications
You must be signed in to change notification settings - Fork 7
/
lock.c
148 lines (122 loc) · 3.54 KB
/
lock.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/*
* IceBreaker
* Copyright (c) 2002-2020 Matthew Miller <mattdm@mattdm.org> and
* Enrico Tassi <gareuselesinge@infinito.it>
*
* <http://www.mattdm.org/icebreaker/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* 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.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifndef WIN32
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#endif
#include "lock.h"
// the return value of lock/unlock system calls
static int sysret;
// the number of times to retry before returning from lock()
#define RETRY_N 3
// the number of seconds between two lock syscalls (in seconds)
#define INTERVAL 1
//***************** OH MY *******************************************
// And now for a bunch of crazy cross-platform macros devised
// by Enrico. :)
//***************** LOCK_DEBUG MACRO *********************************
//#include "stdio.h"
//#define LOCK_DEBUG(a...) fprintf(stderr,a)
#define LOCK_DEBUG(a...)
//***************** SYSCALL WRAPPING *********************************
#ifdef WIN32
# define DELAY (INTERVAL * 1000)
# define LOCK_SYSCALL(a) {sysret=LockFile(a,0,0,1,0);}
# define UNLOCK_SYSCALL(a) {sysret=UnlockFile(a,0,0,1,0);}
# define OPEN_SYSCALL(a) CreateFile(a,GENERIC_READ,1,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM,NULL)
# define CLOSE_SYSCALL(a) CloseHandle(a)
# define SLEEP_SYSCALL() Sleep(DELAY)
# define BAD_VALUE 0
# define IS_OK(a) (a != BAD_VALUE)
#else
static struct flock lockstr; // used by fcntl
# define DELAY INTERVAL
# define LOCK_SYSCALL(a) {memset(&lockstr,0,sizeof(lockstr));lockstr.l_type = F_WRLCK;sysret = fcntl(a, F_SETLK , &lockstr);}
# define UNLOCK_SYSCALL(a) {memset(&lockstr,0,sizeof(lockstr));lockstr.l_type = F_UNLCK;sysret = fcntl(a, F_SETLK , &lockstr);}
# define OPEN_SYSCALL(a) open(a,O_RDWR)
# define CLOSE_SYSCALL(a) close(a)
# define SLEEP_SYSCALL() sleep(DELAY)
# define BAD_VALUE -1
# define IS_OK(a) (a != BAD_VALUE)
#endif
//************************ REAL FUNCTIONS ****************************
/* return values:
* 0 = success
* -1 = lock failed
*/
int lock(FILE_DESC f)
{
int i;
sysret = BAD_VALUE;
for( i = 0 ; i < RETRY_N && !IS_OK(sysret) ; i++ )
{
LOCK_SYSCALL(f);
if(!IS_OK(sysret) && i < RETRY_N -1)
{
SLEEP_SYSCALL();
}
}
if(IS_OK(sysret))
{
LOCK_DEBUG("lock obtained\n");
return 0;
}
else
{
LOCK_DEBUG("lock denied\n");
return -1;
}
}
/* return values:
* 0 = success
* -1 = unlock failed
*/
int unlock(FILE_DESC f)
{
UNLOCK_SYSCALL(f);
if(!IS_OK(sysret))
{
LOCK_DEBUG("unlock failed\n");
// FIX: do something to warn about this, because it shouldn't
// happen and will definitely cause problems if it does.
return -1;
}
else
{
LOCK_DEBUG("unlocked\n");
return 0;
}
}
/* return values:
* ? = success
* INVALID_FILE_DESC = failed
*/
FILE_DESC openlockfile(char* fname)
{
return OPEN_SYSCALL(fname);
}
void closelockfile(FILE_DESC f)
{
CLOSE_SYSCALL(f);
}