3 #include "tap-interface.h"
4 #include "system/wait.h"
12 #include "external-agent.h"
15 #define alarm fast_alarm
17 /* Speed things up by doing things in milliseconds. */
18 static unsigned int fast_alarm(unsigned int milli_seconds
)
22 it
.it_interval
.tv_sec
= it
.it_interval
.tv_usec
= 0;
23 it
.it_value
.tv_sec
= milli_seconds
/ 1000;
24 it
.it_value
.tv_usec
= milli_seconds
* 1000;
25 setitimer(ITIMER_REAL
, &it
, NULL
);
29 #define CatchSignal(sig, handler) signal((sig), (handler))
31 static void do_nothing(int signum
)
35 /* This example code is taken from SAMBA, so try not to change it. */
36 static struct flock flock_struct
;
38 /* Return a value which is none of v1, v2 or v3. */
39 static inline short int invalid_value(short int v1
, short int v2
, short int v3
)
41 short int try = (v1
+v2
+v3
)^((v1
+v2
+v3
) << 16);
42 while (try == v1
|| try == v2
|| try == v3
)
47 /* We invalidate in as many ways as we can, so the OS rejects it */
48 static void invalidate_flock_struct(int signum
)
50 flock_struct
.l_type
= invalid_value(F_RDLCK
, F_WRLCK
, F_UNLCK
);
51 flock_struct
.l_whence
= invalid_value(SEEK_SET
, SEEK_CUR
, SEEK_END
);
52 flock_struct
.l_start
= -1;
53 /* A large negative. */
54 flock_struct
.l_len
= (((off_t
)1 << (sizeof(off_t
)*CHAR_BIT
- 1)) + 1);
57 static int timeout_lock(int fd
, int rw
, off_t off
, off_t len
, bool waitflag
,
60 int ret
, saved_errno
= errno
;
61 unsigned int timeout
= *(unsigned int *)_timeout
;
63 flock_struct
.l_type
= rw
;
64 flock_struct
.l_whence
= SEEK_SET
;
65 flock_struct
.l_start
= off
;
66 flock_struct
.l_len
= len
;
68 CatchSignal(SIGALRM
, invalidate_flock_struct
);
73 ret
= fcntl(fd
, F_SETLKW
, &flock_struct
);
75 ret
= fcntl(fd
, F_SETLK
, &flock_struct
);
80 /* Not signalled? Something else went wrong. */
81 if (flock_struct
.l_len
== len
) {
82 if (errno
== EAGAIN
|| errno
== EINTR
)
97 static int ntdb_chainlock_with_timeout_internal(struct ntdb_context
*ntdb
,
102 union ntdb_attribute locking
;
103 enum NTDB_ERROR ecode
;
106 locking
.base
.attr
= NTDB_ATTRIBUTE_FLOCK
;
107 ecode
= ntdb_get_attribute(ntdb
, &locking
);
108 if (ecode
!= NTDB_SUCCESS
)
111 /* Replace locking function with our own. */
112 locking
.flock
.data
= &timeout
;
113 locking
.flock
.lock
= timeout_lock
;
115 ecode
= ntdb_set_attribute(ntdb
, &locking
);
116 if (ecode
!= NTDB_SUCCESS
)
119 if (rw_type
== F_RDLCK
)
120 ecode
= ntdb_chainlock_read(ntdb
, key
);
122 ecode
= ntdb_chainlock(ntdb
, key
);
125 ntdb_unset_attribute(ntdb
, NTDB_ATTRIBUTE_FLOCK
);
130 int main(int argc
, char *argv
[])
133 struct ntdb_context
*ntdb
;
134 NTDB_DATA key
= ntdb_mkdata("hello", 5);
135 int flags
[] = { NTDB_DEFAULT
, NTDB_NOMMAP
,
136 NTDB_CONVERT
, NTDB_NOMMAP
|NTDB_CONVERT
};
139 plan_tests(sizeof(flags
) / sizeof(flags
[0]) * 15);
141 agent
= prepare_external_agent();
143 for (i
= 0; i
< sizeof(flags
) / sizeof(flags
[0]); i
++) {
144 enum NTDB_ERROR ecode
;
145 ntdb
= ntdb_open("run-locktimeout.ntdb",
146 flags
[i
]|MAYBE_NOSYNC
,
147 O_RDWR
|O_CREAT
|O_TRUNC
, 0600, &tap_log_attr
);
151 /* Simple cases: should succeed. */
152 ecode
= ntdb_chainlock_with_timeout_internal(ntdb
, key
, 20,
154 ok1(ecode
== NTDB_SUCCESS
);
155 ok1(tap_log_messages
== 0);
157 ntdb_chainunlock_read(ntdb
, key
);
158 ok1(tap_log_messages
== 0);
160 ecode
= ntdb_chainlock_with_timeout_internal(ntdb
, key
, 20,
162 ok1(ecode
== NTDB_SUCCESS
);
163 ok1(tap_log_messages
== 0);
165 ntdb_chainunlock(ntdb
, key
);
166 ok1(tap_log_messages
== 0);
168 /* OK, get agent to start transaction, then we should time out. */
169 ok1(external_agent_operation(agent
, OPEN
, "run-locktimeout.ntdb")
171 ok1(external_agent_operation(agent
, TRANSACTION_START
, "")
173 ecode
= ntdb_chainlock_with_timeout_internal(ntdb
, key
, 20,
175 ok1(ecode
== NTDB_ERR_LOCK
);
176 ok1(tap_log_messages
== 0);
178 /* Even if we get a different signal, should be fine. */
179 CatchSignal(SIGUSR1
, do_nothing
);
180 external_agent_operation(agent
, SEND_SIGNAL
, "");
181 ecode
= ntdb_chainlock_with_timeout_internal(ntdb
, key
, 20,
183 ok1(ecode
== NTDB_ERR_LOCK
);
184 ok1(tap_log_messages
== 0);
186 ok1(external_agent_operation(agent
, TRANSACTION_COMMIT
, "")
188 ok1(external_agent_operation(agent
, CLOSE
, "")
192 free_external_agent(agent
);
193 return exit_status();