diff options
author | Christian Grothoff <christian@grothoff.org> | 2015-10-18 21:54:11 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2015-10-18 21:54:11 +0000 |
commit | 770959a6e7ed92e09d61553e170e3dc6053f0355 (patch) | |
tree | 667b68f58923cf09d6026363362fdae057e4907a /src/arm/gnunet-service-arm.c | |
parent | 8af92fb15d1166dbd79e40a53c3a785ca8c0346b (diff) | |
download | gnunet-770959a6e7ed92e09d61553e170e3dc6053f0355.tar.gz gnunet-770959a6e7ed92e09d61553e170e3dc6053f0355.zip |
-fix
Diffstat (limited to 'src/arm/gnunet-service-arm.c')
-rw-r--r-- | src/arm/gnunet-service-arm.c | 304 |
1 files changed, 164 insertions, 140 deletions
diff --git a/src/arm/gnunet-service-arm.c b/src/arm/gnunet-service-arm.c index b8cda5945..b3bf168f1 100644 --- a/src/arm/gnunet-service-arm.c +++ b/src/arm/gnunet-service-arm.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | This file is part of GNUnet. | 2 | This file is part of GNUnet. |
3 | Copyright (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) | 3 | Copyright (C) 2009, 2010, 2011, 2015 Christian Grothoff (and other contributing authors) |
4 | 4 | ||
5 | GNUnet is free software; you can redistribute it and/or modify | 5 | GNUnet is free software; you can redistribute it and/or modify |
6 | it under the terms of the GNU General Public License as published | 6 | it under the terms of the GNU General Public License as published |
@@ -1046,7 +1046,7 @@ shutdown_task (void *cls, | |||
1046 | { | 1046 | { |
1047 | GNUNET_CONTAINER_DLL_remove (pos->listen_head, | 1047 | GNUNET_CONTAINER_DLL_remove (pos->listen_head, |
1048 | pos->listen_tail, sli); | 1048 | pos->listen_tail, sli); |
1049 | if (sli->accept_task != NULL) | 1049 | if (NULL != sli->accept_task) |
1050 | { | 1050 | { |
1051 | GNUNET_SCHEDULER_cancel (sli->accept_task); | 1051 | GNUNET_SCHEDULER_cancel (sli->accept_task); |
1052 | sli->accept_task = NULL; | 1052 | sli->accept_task = NULL; |
@@ -1168,7 +1168,8 @@ delayed_restart_task (void *cls, | |||
1168 | * @param tc context | 1168 | * @param tc context |
1169 | */ | 1169 | */ |
1170 | static void | 1170 | static void |
1171 | maint_child_death (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | 1171 | maint_child_death (void *cls, |
1172 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
1172 | { | 1173 | { |
1173 | struct ServiceList *pos; | 1174 | struct ServiceList *pos; |
1174 | struct ServiceList *next; | 1175 | struct ServiceList *next; |
@@ -1184,172 +1185,195 @@ maint_child_death (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | |||
1184 | pr = GNUNET_DISK_pipe_handle (sigpipe, GNUNET_DISK_PIPE_END_READ); | 1185 | pr = GNUNET_DISK_pipe_handle (sigpipe, GNUNET_DISK_PIPE_END_READ); |
1185 | child_death_task = NULL; | 1186 | child_death_task = NULL; |
1186 | if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY)) | 1187 | if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY)) |
1187 | { | 1188 | { |
1188 | /* shutdown scheduled us, ignore! */ | 1189 | /* shutdown scheduled us, ignore! */ |
1189 | child_death_task = | 1190 | child_death_task = |
1190 | GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, | 1191 | GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, |
1191 | pr, &maint_child_death, NULL); | 1192 | pr, |
1192 | return; | 1193 | &maint_child_death, |
1193 | } | 1194 | NULL); |
1195 | return; | ||
1196 | } | ||
1194 | /* consume the signal */ | 1197 | /* consume the signal */ |
1195 | GNUNET_break (0 < GNUNET_DISK_file_read (pr, &c, sizeof (c))); | 1198 | GNUNET_break (0 < GNUNET_DISK_file_read (pr, &c, sizeof (c))); |
1196 | 1199 | ||
1197 | /* check for services that died (WAITPID) */ | 1200 | /* check for services that died (WAITPID) */ |
1198 | next = running_head; | 1201 | next = running_head; |
1199 | while (NULL != (pos = next)) | 1202 | while (NULL != (pos = next)) |
1200 | { | 1203 | { |
1201 | next = pos->next; | 1204 | next = pos->next; |
1202 | 1205 | ||
1203 | if (pos->proc == NULL) | 1206 | if (NULL == pos->proc) |
1204 | { | 1207 | { |
1205 | if (GNUNET_YES == in_shutdown) | 1208 | if (GNUNET_YES == in_shutdown) |
1206 | free_service (pos); | 1209 | free_service (pos); |
1207 | continue; | 1210 | continue; |
1208 | } | 1211 | } |
1209 | #if HAVE_WAIT4 | 1212 | #if HAVE_WAIT4 |
1210 | if (NULL != wait_file) | 1213 | if (NULL != wait_file) |
1214 | { | ||
1215 | /* need to use 'wait4()' to obtain and log performance data */ | ||
1216 | struct rusage ru; | ||
1217 | int status; | ||
1218 | pid_t pid; | ||
1219 | |||
1220 | pid = GNUNET_OS_process_get_pid (pos->proc); | ||
1221 | ret = wait4 (pid, | ||
1222 | &status, | ||
1223 | WNOHANG, | ||
1224 | &ru); | ||
1225 | if (ret <= 0) | ||
1226 | continue; /* no process done */ | ||
1227 | if (WIFEXITED (status)) | ||
1211 | { | 1228 | { |
1212 | /* need to use 'wait4()' to obtain and log performance data */ | 1229 | statusType = GNUNET_OS_PROCESS_EXITED; |
1213 | struct rusage ru; | 1230 | statusCode = WEXITSTATUS (status); |
1214 | int status; | ||
1215 | pid_t pid; | ||
1216 | |||
1217 | pid = GNUNET_OS_process_get_pid (pos->proc); | ||
1218 | ret = wait4 (pid, | ||
1219 | &status, | ||
1220 | WNOHANG, | ||
1221 | &ru); | ||
1222 | if (ret <= 0) | ||
1223 | continue; /* no process done */ | ||
1224 | if (WIFEXITED (status)) | ||
1225 | { | ||
1226 | statusType = GNUNET_OS_PROCESS_EXITED; | ||
1227 | statusCode = WEXITSTATUS (status); | ||
1228 | } | ||
1229 | else if (WIFSIGNALED (status)) | ||
1230 | { | ||
1231 | statusType = GNUNET_OS_PROCESS_SIGNALED; | ||
1232 | statusCode = WTERMSIG (status); | ||
1233 | } | ||
1234 | else if (WIFSTOPPED (status)) | ||
1235 | { | ||
1236 | statusType = GNUNET_OS_PROCESS_SIGNALED; | ||
1237 | statusCode = WSTOPSIG (status); | ||
1238 | } | ||
1239 | #ifdef WIFCONTINUED | ||
1240 | else if (WIFCONTINUED (status)) | ||
1241 | { | ||
1242 | statusType = GNUNET_OS_PROCESS_RUNNING; | ||
1243 | statusCode = 0; | ||
1244 | } | ||
1245 | #endif | ||
1246 | else | ||
1247 | { | ||
1248 | statusType = GNUNET_OS_PROCESS_UNKNOWN; | ||
1249 | statusCode = 0; | ||
1250 | } | ||
1251 | if ( (GNUNET_OS_PROCESS_EXITED == statusType) || | ||
1252 | (GNUNET_OS_PROCESS_SIGNALED == statusType) ) | ||
1253 | { | ||
1254 | fprintf (wait_file, | ||
1255 | "%s(%u) %llu.%llu %llu.%llu %llu %llu %llu %llu %llu\n", | ||
1256 | pos->binary, | ||
1257 | (unsigned int) pid, | ||
1258 | (unsigned long long) ru.ru_utime.tv_sec, | ||
1259 | (unsigned long long) ru.ru_utime.tv_usec, | ||
1260 | (unsigned long long) ru.ru_stime.tv_sec, | ||
1261 | (unsigned long long) ru.ru_stime.tv_usec, | ||
1262 | (unsigned long long) ru.ru_maxrss, | ||
1263 | (unsigned long long) ru.ru_inblock, | ||
1264 | (unsigned long long) ru.ru_oublock, | ||
1265 | (unsigned long long) ru.ru_nvcsw, | ||
1266 | (unsigned long long) ru.ru_nivcsw); | ||
1267 | } | ||
1268 | } | 1231 | } |
1269 | else /* continue with #else */ | 1232 | else if (WIFSIGNALED (status)) |
1270 | #else | ||
1271 | if ((GNUNET_SYSERR == | ||
1272 | (ret = | ||
1273 | GNUNET_OS_process_status (pos->proc, &statusType, &statusCode))) || | ||
1274 | ((ret == GNUNET_NO) || | ||
1275 | (statusType == GNUNET_OS_PROCESS_STOPPED) || | ||
1276 | (statusType == GNUNET_OS_PROCESS_RUNNING) ) ) | ||
1277 | continue; | ||
1278 | #endif | ||
1279 | if (statusType == GNUNET_OS_PROCESS_EXITED) | ||
1280 | { | 1233 | { |
1281 | statstr = _( /* process termination method */ "exit"); | 1234 | statusType = GNUNET_OS_PROCESS_SIGNALED; |
1282 | statcode = statusCode; | 1235 | statusCode = WTERMSIG (status); |
1283 | } | 1236 | } |
1284 | else if (statusType == GNUNET_OS_PROCESS_SIGNALED) | 1237 | else if (WIFSTOPPED (status)) |
1285 | { | 1238 | { |
1286 | statstr = _( /* process termination method */ "signal"); | 1239 | statusType = GNUNET_OS_PROCESS_SIGNALED; |
1287 | statcode = statusCode; | 1240 | statusCode = WSTOPSIG (status); |
1288 | } | 1241 | } |
1289 | else | 1242 | #ifdef WIFCONTINUED |
1243 | else if (WIFCONTINUED (status)) | ||
1290 | { | 1244 | { |
1291 | statstr = _( /* process termination method */ "unknown"); | 1245 | statusType = GNUNET_OS_PROCESS_RUNNING; |
1292 | statcode = 0; | 1246 | statusCode = 0; |
1293 | } | 1247 | } |
1294 | if (0 != pos->killed_at.abs_value_us) | 1248 | #endif |
1249 | else | ||
1295 | { | 1250 | { |
1296 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | 1251 | statusType = GNUNET_OS_PROCESS_UNKNOWN; |
1297 | _("Service `%s' took %s to terminate\n"), | 1252 | statusCode = 0; |
1298 | pos->name, | ||
1299 | GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (pos->killed_at), GNUNET_YES)); | ||
1300 | } | 1253 | } |
1301 | GNUNET_OS_process_destroy (pos->proc); | 1254 | if ( (GNUNET_OS_PROCESS_EXITED == statusType) || |
1302 | pos->proc = NULL; | 1255 | (GNUNET_OS_PROCESS_SIGNALED == statusType) ) |
1303 | broadcast_status (pos->name, GNUNET_ARM_SERVICE_STOPPED, NULL); | ||
1304 | if (NULL != pos->killing_client) | ||
1305 | { | 1256 | { |
1306 | signal_result (pos->killing_client, pos->name, | 1257 | fprintf (wait_file, |
1307 | pos->killing_client_request_id, GNUNET_ARM_RESULT_STOPPED); | 1258 | "%s(%u) %llu.%llu %llu.%llu %llu %llu %llu %llu %llu\n", |
1308 | GNUNET_SERVER_client_drop (pos->killing_client); | 1259 | pos->binary, |
1309 | pos->killing_client = NULL; | 1260 | (unsigned int) pid, |
1310 | pos->killing_client_request_id = 0; | 1261 | (unsigned long long) ru.ru_utime.tv_sec, |
1262 | (unsigned long long) ru.ru_utime.tv_usec, | ||
1263 | (unsigned long long) ru.ru_stime.tv_sec, | ||
1264 | (unsigned long long) ru.ru_stime.tv_usec, | ||
1265 | (unsigned long long) ru.ru_maxrss, | ||
1266 | (unsigned long long) ru.ru_inblock, | ||
1267 | (unsigned long long) ru.ru_oublock, | ||
1268 | (unsigned long long) ru.ru_nvcsw, | ||
1269 | (unsigned long long) ru.ru_nivcsw); | ||
1311 | } | 1270 | } |
1312 | if (GNUNET_YES != in_shutdown) | 1271 | } |
1272 | else /* continue with JUST this "if" as "else" (intentionally no brackets!) */ | ||
1273 | #endif | ||
1274 | if ( (GNUNET_SYSERR == | ||
1275 | (ret = | ||
1276 | GNUNET_OS_process_status (pos->proc, | ||
1277 | &statusType, | ||
1278 | &statusCode))) || | ||
1279 | (ret == GNUNET_NO) || | ||
1280 | (statusType == GNUNET_OS_PROCESS_STOPPED) || | ||
1281 | (statusType == GNUNET_OS_PROCESS_UNKNOWN) || | ||
1282 | (statusType == GNUNET_OS_PROCESS_RUNNING) ) | ||
1283 | continue; | ||
1284 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1285 | "Running with %d/%d\n", | ||
1286 | statusType, | ||
1287 | statusCode); | ||
1288 | |||
1289 | if (statusType == GNUNET_OS_PROCESS_EXITED) | ||
1290 | { | ||
1291 | statstr = _( /* process termination method */ "exit"); | ||
1292 | statcode = statusCode; | ||
1293 | } | ||
1294 | else if (statusType == GNUNET_OS_PROCESS_SIGNALED) | ||
1295 | { | ||
1296 | statstr = _( /* process termination method */ "signal"); | ||
1297 | statcode = statusCode; | ||
1298 | } | ||
1299 | else | ||
1300 | { | ||
1301 | statstr = _( /* process termination method */ "unknown"); | ||
1302 | statcode = 0; | ||
1303 | } | ||
1304 | if (0 != pos->killed_at.abs_value_us) | ||
1305 | { | ||
1306 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
1307 | _("Service `%s' took %s to terminate\n"), | ||
1308 | pos->name, | ||
1309 | GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (pos->killed_at), | ||
1310 | GNUNET_YES)); | ||
1311 | } | ||
1312 | GNUNET_OS_process_destroy (pos->proc); | ||
1313 | pos->proc = NULL; | ||
1314 | broadcast_status (pos->name, | ||
1315 | GNUNET_ARM_SERVICE_STOPPED, | ||
1316 | NULL); | ||
1317 | if (NULL != pos->killing_client) | ||
1318 | { | ||
1319 | signal_result (pos->killing_client, pos->name, | ||
1320 | pos->killing_client_request_id, | ||
1321 | GNUNET_ARM_RESULT_STOPPED); | ||
1322 | GNUNET_SERVER_client_drop (pos->killing_client); | ||
1323 | pos->killing_client = NULL; | ||
1324 | pos->killing_client_request_id = 0; | ||
1325 | } | ||
1326 | if (GNUNET_YES != in_shutdown) | ||
1327 | { | ||
1328 | if ( (statusType == GNUNET_OS_PROCESS_EXITED) && | ||
1329 | (statcode == 0) ) | ||
1313 | { | 1330 | { |
1314 | if ((statusType == GNUNET_OS_PROCESS_EXITED) && (statcode == 0)) | 1331 | /* process terminated normally, allow restart at any time */ |
1315 | { | 1332 | pos->restart_at.abs_value_us = 0; |
1316 | /* process terminated normally, allow restart at any time */ | 1333 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, |
1317 | pos->restart_at.abs_value_us = 0; | 1334 | _("Service `%s' terminated normally, will restart at any time\n"), |
1318 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | 1335 | pos->name); |
1319 | _("Service `%s' terminated normally, will restart at any time\n"), | 1336 | /* process can still be re-started on-demand, ensure it is re-started if there is demand */ |
1320 | pos->name); | 1337 | for (sli = pos->listen_head; NULL != sli; sli = sli->next) |
1321 | /* process can still be re-started on-demand, ensure it is re-started if there is demand */ | ||
1322 | for (sli = pos->listen_head; NULL != sli; sli = sli->next) | ||
1323 | { | ||
1324 | GNUNET_break (NULL == sli->accept_task); | ||
1325 | sli->accept_task = | ||
1326 | GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, | ||
1327 | sli->listen_socket, &accept_connection, sli); | ||
1328 | } | ||
1329 | } | ||
1330 | else | ||
1331 | { | 1338 | { |
1332 | if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) | 1339 | GNUNET_break (NULL == sli->accept_task); |
1333 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | 1340 | sli->accept_task = |
1334 | _("Service `%s' terminated with status %s/%d, will restart in %s\n"), | 1341 | GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, |
1335 | pos->name, statstr, statcode, | 1342 | sli->listen_socket, |
1336 | GNUNET_STRINGS_relative_time_to_string (pos->backoff, GNUNET_YES)); | 1343 | &accept_connection, |
1337 | /* schedule restart */ | 1344 | sli); |
1338 | pos->restart_at = GNUNET_TIME_relative_to_absolute (pos->backoff); | ||
1339 | pos->backoff = GNUNET_TIME_STD_BACKOFF (pos->backoff); | ||
1340 | if (NULL != child_restart_task) | ||
1341 | GNUNET_SCHEDULER_cancel (child_restart_task); | ||
1342 | child_restart_task = GNUNET_SCHEDULER_add_with_priority ( | ||
1343 | GNUNET_SCHEDULER_PRIORITY_IDLE, &delayed_restart_task, NULL); | ||
1344 | } | 1345 | } |
1345 | } | 1346 | } |
1346 | else | 1347 | else |
1347 | { | 1348 | { |
1348 | free_service (pos); | 1349 | if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) |
1350 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
1351 | _("Service `%s' terminated with status %s/%d, will restart in %s\n"), | ||
1352 | pos->name, | ||
1353 | statstr, | ||
1354 | statcode, | ||
1355 | GNUNET_STRINGS_relative_time_to_string (pos->backoff, | ||
1356 | GNUNET_YES)); | ||
1357 | /* schedule restart */ | ||
1358 | pos->restart_at = GNUNET_TIME_relative_to_absolute (pos->backoff); | ||
1359 | pos->backoff = GNUNET_TIME_STD_BACKOFF (pos->backoff); | ||
1360 | if (NULL != child_restart_task) | ||
1361 | GNUNET_SCHEDULER_cancel (child_restart_task); | ||
1362 | child_restart_task | ||
1363 | = GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_IDLE, | ||
1364 | &delayed_restart_task, | ||
1365 | NULL); | ||
1349 | } | 1366 | } |
1350 | } | 1367 | } |
1368 | else | ||
1369 | { | ||
1370 | free_service (pos); | ||
1371 | } | ||
1372 | } | ||
1351 | child_death_task = GNUNET_SCHEDULER_add_read_file ( | 1373 | child_death_task = GNUNET_SCHEDULER_add_read_file ( |
1352 | GNUNET_TIME_UNIT_FOREVER_REL, pr, &maint_child_death, NULL); | 1374 | GNUNET_TIME_UNIT_FOREVER_REL, |
1375 | pr, | ||
1376 | &maint_child_death, NULL); | ||
1353 | if ((NULL == running_head) && (GNUNET_YES == in_shutdown)) | 1377 | if ((NULL == running_head) && (GNUNET_YES == in_shutdown)) |
1354 | do_shutdown (); | 1378 | do_shutdown (); |
1355 | else if (GNUNET_YES == in_shutdown) | 1379 | else if (GNUNET_YES == in_shutdown) |