Belle II Software development
framework-pcore-clear_ipcs.cc
1/**************************************************************************
2 * basf2 (Belle II Analysis Software Framework) *
3 * Author: The Belle II Collaboration *
4 * *
5 * See git log for contributors and copyright holders. *
6 * This file is licensed under LGPL-3.0, see LICENSE.md. *
7 **************************************************************************/
8
9#include <dirent.h>
10#include <cstdio>
11#include <unistd.h>
12#include <cstring>
13#include <cstdlib>
14#include <filesystem>
15
16#include <sys/ipc.h>
17#include <sys/shm.h>
18#include <sys/sem.h>
19
20int main(int argc, char** argv)
21{
22 int mode = 2; // unnamed IPC resources only
23 if (argc > 1) {
24 if (strcmp(argv[1], "all") == 0)
25 mode = 0;
26 else if (strcmp(argv[1], "named") == 0)
27 mode = 1;
28 else if (strcmp(argv[1], "unnamed") == 0)
29 mode = 2;
30 else {
31 printf("Usage : clear_basf2_ipc {all|named|unnamed} \n");
32 printf("all: all IPCs, named: named IPCs only, unnamed: basf2 internal IPCs only(default)\n");
33
34 printf("\n Cleans up inter-process communication (IPC) resources left behind if basf2 crashes.\n\n");
35 printf("Normally, this shouldn't be necessary, but resources may remain after a bad crash or basf2 is killed using SIGKILL.\n");
36 printf("Resources currently in use are not touched.\n");
37 printf("The return code is set to 1 when uncleaned resources are found, 0 if none are found, and -1 on error.\n");
38 return -1;
39 }
40 }
41
42 DIR* dir;
43 if ((dir = opendir(std::filesystem::temp_directory_path().c_str())) != nullptr) {
44 int ret = 0;
45 struct dirent* ent;
46 while ((ent = readdir(dir)) != nullptr) {
47 if (strncmp(ent->d_name, "SHM", 3) == 0) {
48 // printf ("%s\n", ent->d_name);
49 int shmid, semid;
50 char name[256];
51 sscanf(ent->d_name, "SHM%d-SEM%d-%255s", &shmid, &semid, name);
52 // printf ( "name : %s - shmid = %d, semid = %d\n", name, shmid, semid );
53 int unnamed = strcmp(name, "UNNAMED");
54 bool deleted = false;
55 bool stale = false;
56 if (shmid > 0) {
57 if (mode == 0 || (unnamed == 0 && mode == 2) ||
58 (unnamed != 0 && mode == 1)) {
59
60 shmid_ds shmInfo;
61 if (shmctl(shmid, IPC_STAT, &shmInfo) != 0) {
62 printf("Removing stale file %s\n", ent->d_name);
63 stale = true; //already gone (note: stale files do not produce non-zero return code)
64 } else {
65 //Don't remove SHM segments which still have a process attached
66 //Note that nattch counter is decreased by both shmdt() and exit()
67 if (shmInfo.shm_nattch != 0) {
68 printf("%s/%s still has %ld processes attached, skipped.\n", std::filesystem::temp_directory_path().c_str(), ent->d_name,
69 shmInfo.shm_nattch);
70 continue;
71 }
72
73 if (shmctl(shmid, IPC_RMID, (struct shmid_ds*) nullptr) == 0) {
74 printf("SHM %d deleted. ", shmid);
75 deleted = true;
76 }
77 }
78 }
79 }
80 if (semid > 0) {
81 if (mode == 0 || (unnamed == 0 && mode == 2) ||
82 (unnamed != 0 && mode == 1)) {
83 if (semctl(semid, 1, IPC_RMID) == 0) {
84 printf("SEM %d deleted. ", semid);
85 deleted = true;
86 }
87 }
88 }
89 if (deleted or stale) {
90 ret = 1;
91 printf("\n");
92 char strbuf[1024];
93 snprintf(strbuf, 1024, "%s/%s", std::filesystem::temp_directory_path().c_str(), ent->d_name);
94 unlink(strbuf);
95 if (unnamed != 0) {
96 snprintf(strbuf, 1024, "%s/%s_%s", std::filesystem::temp_directory_path().c_str(), getenv("USER"), name);
97 unlink(strbuf);
98 }
99 }
100 }
101 }
102 closedir(dir);
103 return ret;
104 } else {
105 perror("");
106 return -1;
107 }
108}