Looking at additional race conditions in test harness.
[awesomized/libmemcached] / tests / server.c
1 /* LibMemcached
2 * Copyright (C) 2006-2009 Brian Aker
3 * All rights reserved.
4 *
5 * Use and distribution licensed under the BSD license. See
6 * the COPYING file in the parent directory for full text.
7 *
8 * Summary:
9 *
10 */
11
12 /*
13 Startup, and shutdown the memcached servers.
14 */
15
16 #define TEST_PORT_BASE MEMCACHED_DEFAULT_PORT+10
17
18 #define PID_FILE_BASE "/tmp/%ulibmemcached_memc.pid"
19
20 #include "config.h"
21
22 #include <assert.h>
23 #include <limits.h>
24 #include <signal.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <sys/time.h>
29 #include <time.h>
30 #include <unistd.h>
31
32 #include <libmemcached/memcached.h>
33 #include <libmemcached/util.h>
34
35 #include "server.h"
36
37 static struct timespec global_sleep_value= { .tv_sec= 0, .tv_nsec= 50000 };
38
39 static void global_sleep(void)
40 {
41 #ifdef WIN32
42 sleep(1);
43 #else
44 nanosleep(&global_sleep_value, NULL);
45 #endif
46 }
47
48 static void kill_file(const char *file_buffer)
49 {
50 FILE *fp= fopen(file_buffer, "r");
51
52 while ((fp= fopen(file_buffer, "r")))
53 {
54 char pid_buffer[1024];
55
56 if (fgets(pid_buffer, sizeof(pid_buffer), fp) != NULL)
57 {
58 pid_t pid= (pid_t)atoi(pid_buffer);
59 if (pid != 0)
60 {
61 if (kill(pid, SIGTERM) == -1)
62 {
63 remove(file_buffer); // If this happens we may be dealing with a dead server that left its pid file.
64 }
65 else
66 {
67 uint32_t counter= 3;
68 while ((kill(pid, 0) == 0) && --counter)
69 {
70 global_sleep();
71 }
72 }
73 }
74 }
75
76 global_sleep();
77
78 fclose(fp);
79 }
80 }
81
82 void server_startup(server_startup_st *construct)
83 {
84 if ((construct->server_list= getenv("MEMCACHED_SERVERS")))
85 {
86 printf("servers %s\n", construct->server_list);
87 construct->servers= memcached_servers_parse(construct->server_list);
88 construct->server_list= NULL;
89 construct->count= 0;
90 }
91 else
92 {
93 {
94 char server_string_buffer[8096];
95 char *end_ptr;
96 end_ptr= server_string_buffer;
97
98 for (uint32_t x= 0; x < construct->count; x++)
99 {
100 int count;
101 int status;
102 in_port_t port;
103
104 {
105 char *var;
106 char variable_buffer[1024];
107
108 snprintf(variable_buffer, sizeof(variable_buffer), "LIBMEMCACHED_PORT_%u", x);
109
110 if ((var= getenv(variable_buffer)))
111 {
112 port= (in_port_t)atoi(var);
113 }
114 else
115 {
116 port= (in_port_t)(x + TEST_PORT_BASE);
117 }
118 }
119
120 char buffer[PATH_MAX];
121 snprintf(buffer, sizeof(buffer), PID_FILE_BASE, x);
122 kill_file(buffer);
123
124 if (x == 0)
125 {
126 snprintf(buffer, sizeof(buffer), "%s -d -u root -P "PID_FILE_BASE" -t 1 -p %u -U %u -m 128",
127 MEMCACHED_BINARY, x, port, port);
128 }
129 else
130 {
131 snprintf(buffer, sizeof(buffer), "%s -d -u root -P "PID_FILE_BASE" -t 1 -p %u -U %u",
132 MEMCACHED_BINARY, x, port, port);
133 }
134 if (libmemcached_util_ping("localhost", port, NULL))
135 {
136 fprintf(stderr, "Server on port %u already exists\n", port);
137 }
138 else
139 {
140 status= system(buffer);
141 fprintf(stderr, "STARTING SERVER: %s status:%d\n", buffer, status);
142 }
143 count= sprintf(end_ptr, "localhost:%u,", port);
144 end_ptr+= count;
145 }
146 *end_ptr= 0;
147
148
149 int *pids= calloc(construct->count, sizeof(int));
150 for (uint32_t x= 0; x < construct->count; x++)
151 {
152 char buffer[PATH_MAX]; /* Nothing special for number */
153
154 snprintf(buffer, sizeof(buffer), PID_FILE_BASE, x);
155
156 uint32_t counter= 3000; // Absurd, just to catch run away process
157 while (pids[x] <= 0 && --counter)
158 {
159 FILE *file= fopen(buffer, "r");
160 if (file)
161 {
162 char pid_buffer[1024];
163 char *found= fgets(pid_buffer, sizeof(pid_buffer), file);
164
165 if (found)
166 {
167 pids[x]= atoi(pid_buffer);
168 fclose(file);
169
170 if (pids[x] > 0)
171 break;
172 }
173 fclose(file);
174 }
175 global_sleep();
176 }
177
178 bool was_started= false;
179 if (pids[x] > 0)
180 {
181 counter= 30;
182 while (--counter)
183 {
184 if (kill(pids[x], 0) == 0)
185 {
186 was_started= true;
187 break;
188 }
189 global_sleep();
190 }
191 }
192
193 if (was_started == false)
194 {
195 fprintf(stderr, "Failed to open buffer %s(%d)\n", buffer, pids[x]);
196 for (uint32_t y= 0; y < construct->count; y++)
197 {
198 if (pids[y] > 0)
199 kill(pids[y], SIGTERM);
200 }
201 abort();
202 }
203 }
204 free(pids);
205
206 construct->server_list= strdup(server_string_buffer);
207 }
208 printf("servers %s\n", construct->server_list);
209 construct->servers= memcached_servers_parse(construct->server_list);
210 }
211
212 assert(construct->servers);
213
214 srandom((unsigned int)time(NULL));
215
216 for (uint32_t x= 0; x < memcached_server_list_count(construct->servers); x++)
217 {
218 printf("\t%s : %d\n", memcached_server_name(&construct->servers[x]), memcached_server_port(&construct->servers[x]));
219 assert(construct->servers[x].fd == -1);
220 assert(construct->servers[x].cursor_active == 0);
221 }
222
223 printf("\n");
224 }
225
226 void server_shutdown(server_startup_st *construct)
227 {
228 if (construct->server_list)
229 {
230 for (uint32_t x= 0; x < construct->count; x++)
231 {
232 char file_buffer[PATH_MAX]; /* Nothing special for number */
233 snprintf(file_buffer, sizeof(file_buffer), PID_FILE_BASE, x);
234 kill_file(file_buffer);
235 }
236
237 free(construct->server_list);
238 }
239 }