2
* Copyright (C) 2012 Red Hat Inc.
4
* This program is free software; you can redistribute it and/or modify
5
* it under the terms of the GNU General Public License as published by
6
* the Free Software Foundation; either version 2 of the License, or
7
* (at your option) any later version.
9
* This program is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
* GNU General Public License for more details.
14
* You should have received a copy of the GNU General Public License
15
* along with this program; if not, write to the Free Software
16
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
/* Regression test for RHBZ#790721.
21
* This bug involves locking issues when building the appliance in
22
* parallel from multiple threads in the same process. We use a read
23
* lock on the 'checksum' file, and it turns out this causes two
24
* problems: (1) locks don't have any effect on threads in the same
25
* process, and (2) because the PID is identical in different threads,
26
* the file we are trying to overwrite has the same name.
28
* To test this we want to create the appliance repeatedly from
29
* multiple threads, but we don't really care about launching the full
30
* qemu (a waste of time and memory for this test). Therefore replace
31
* qemu with a fake process and just look for the linking error.
46
/* Number of worker threads running the test. */
49
static pthread_barrier_t barrier;
50
static void *start_thread (void *);
53
main (int argc, char *argv[])
55
pthread_t thread[NR_THREADS];
59
/* Ensure error messages are not translated. */
60
setenv ("LC_ALL", "C", 1);
62
pthread_barrier_init (&barrier, NULL, NR_THREADS);
64
/* Create the other threads which will set up their own libguestfs
65
* handle then wait at a barrier before launching.
67
for (i = 0; i < NR_THREADS; ++i) {
69
r = pthread_create (&thread[i], NULL, start_thread, &data[i]);
71
fprintf (stderr, "pthread_create: %s\n", strerror (r));
76
/* Wait for the threads to exit. */
79
for (i = 0; i < NR_THREADS; ++i) {
82
r = pthread_join (thread[i], (void **) &ret);
84
fprintf (stderr, "pthread_join: %s\n", strerror (r));
91
exit (errors == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
95
start_thread (void *vi)
99
guestfs_error_handler_cb old_error_cb;
100
void *old_error_data;
103
g = guestfs_create ();
105
perror ("guestfs_create");
110
if (guestfs_add_drive_opts (g, "/dev/null",
111
GUESTFS_ADD_DRIVE_OPTS_FORMAT, "raw",
112
GUESTFS_ADD_DRIVE_OPTS_READONLY, 1,
119
if (guestfs_set_qemu (g, "/bin/true") == -1) {
124
/* Wait for the other threads to finish starting up. */
125
r = pthread_barrier_wait (&barrier);
126
if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) {
127
fprintf (stderr, "pthread_barrier_wait: %s\n", strerror (r));
132
/* Launch the handle. Because of the faked out qemu, we expect this
133
* will fail with "child process died unexpectedly". We are
134
* interested in other failures.
136
old_error_cb = guestfs_get_error_handler (g, &old_error_data);
137
guestfs_set_error_handler (g, NULL, NULL);
138
r = guestfs_launch (g);
139
error = guestfs_last_error (g);
141
if (r == 0) { /* This should NOT happen. */
142
fprintf (stderr, "rhbz790721: strangeness in test: expected launch to fail, but it didn't!\n");
147
if (error == NULL) { /* This also should NOT happen. */
148
fprintf (stderr, "rhbz790721: strangeness in test: no error message!\n");
153
/* If this happens, it indicates a bug/race in the appliance
154
* building code which is what this regression test is designed to
157
if (strcmp (error, "child process died unexpectedly") != 0) {
158
fprintf (stderr, "rhbz790721: error: %s\n", error);
163
guestfs_set_error_handler (g, old_error_cb, old_error_data);
165
/* Close the handle. */