Belle II Software  release-08-01-10
DqmSharedMem.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 "daq/dqm/DqmSharedMem.h"
10 
11 #include <fcntl.h>
12 #include <sys/ipc.h>
13 #include <sys/sem.h>
14 #include <sys/shm.h>
15 #include <sys/types.h>
16 #include <unistd.h>
17 
18 #include <cstring>
19 
20 using namespace Belle2;
21 using namespace std;
22 
23 // Constructor / Destructor
24 
25 DqmSharedMem::DqmSharedMem(const char* name, int size)
26 {
27  std::string tmpPathName;
28  // 0. Determine shared memory type
29  if (strcmp(name, "private") != 0) { // Global
30  tmpPathName = getTmpFileName(getenv("USER"), name);
31  m_pathfd = open(tmpPathName.c_str(), O_CREAT | O_EXCL | O_RDWR, 0644);
32  if (m_pathfd > 0) { // a new shared memory file created
33  printf("DqmSharedMem: Creating a shared memory with key %s\n", name);
34  m_new = true;
35  } else if (m_pathfd == -1 && errno == EEXIST) { // shm already there
36  printf("DqmSharedMem: Attaching the ring buffer with key %s\n", name);
37  m_new = false;
38  } else {
39  printf("DqmSharedMem: error to open shm file\n");
40  return;
41  }
42  m_shmkey = ftok(tmpPathName.c_str(), 1);
43  m_semkey = ftok(tmpPathName.c_str(), 2);
44  } else { // Private
45  m_new = true;
46  m_shmkey = IPC_PRIVATE;
47  m_semkey = IPC_PRIVATE;
48  printf("DqmSharedMem: Opening private shared memory\n");
49  }
50 
51  printf("Shared memory/Semaphore Keys: $%X $%X\n", m_shmkey, m_semkey);
52  // Behavior:
53  // - IPC_CREATE will open existing or create new one
54  // - IPC_CREATE|IPC_EXCL will create new one and fail is existing
55  // - 0 will open existing one and fails if not existing
56 
57  // 1. Open shared memory
58  m_shmid = shmget(m_shmkey, size * 4, IPC_CREAT | 0644);
59  if (m_shmid < 0) {
60  perror("DqmSharedMem::shmget");
61  return;
62  }
63  m_shmadr = (int*) shmat(m_shmid, 0, 0);
64  if (m_shmadr == (int*) - 1) {
65  perror("DqmSharedMem::shmat");
66  return;
67  }
68 
69  // 2. Open semaphore
70 
71  // Behavior:
72  // - IPC_CREATE will open existing or create new one
73  // - IPC_CREATE|IPC_EXCL will create new one and fail is existing
74  // - 0 will open existing one and fails if not existing
75  m_semid = semget(m_semkey, 1, IPC_CREAT | 0644);
76  if (m_semid >= 0) {
77  // POSIX doesn't guarantee any particular state of our fresh semaphore
78  int semval = 1; //unlocked state
79  if (semctl(m_semid, 0, SETVAL, semval) == -1) { //set 0th semaphore to semval
80  printf("Initializing semaphore with semctl() failed.\n");
81  }
82  } else if (errno == EEXIST) {
83  m_semid = semget(m_semkey, 1, 0600);
84  }
85  if (m_semid < 0) {
86  perror("DqmSharedMem::shmget");
87  return;
88  }
89 
90  // 3. Leave id of shm and semaphore in file name
91  if (m_new) {
92  /*
93  m_strbuf = new char[1024];
94  sprintf(m_strbuf, "/tmp/SHM%d-SEM%d-SHM_%s", m_shmid, m_semid, name);
95  int fd = open(m_strbuf, O_CREAT | O_TRUNC | O_RDWR, 0644);
96  if (fd < 0) {
97  printf("DqmSharedMem ID file could not be created.\n");
98  } else {
99  close(fd);
100  }
101  */
102  // printf("DqmSharedMem: leaving shmid and semid in the path file %d %d fd=%d\n", m_shmid, m_semid, m_pathfd);
103  char shminfo[256];
104  sprintf(shminfo, "%d %d\n", m_shmid, m_semid);
105  int is = write(m_pathfd, shminfo, strlen(shminfo));
106  if (is < 0) perror("write");
107  close(m_pathfd);
108  }
109  printf("DqmSharedMem: created. shmid = %d, semid = %d\n", m_shmid, m_semid);
110 
111 }
112 
113 DqmSharedMem::DqmSharedMem(int shm_id, int sem_id, int size)
114 {
115  m_shmid = shm_id;
116  m_shmadr = (int*) shmat(m_shmid, 0, SHM_RDONLY);
117  if (m_shmadr == (int*) - 1) {
118  perror("DqmSharedMem::shmat");
119  return;
120  }
121  m_semid = sem_id;
122  printf("DqmSharedMem: open shmid = %d, semid = %d\n", m_shmid, m_semid);
123 }
124 
126 {
128 
129  //shmdt((const void*) m_shmadr);
130  //shmctl(m_shmid, IPC_RMID, NULL);
131  //printf("DqmSharedMem: destructor called for ID %d\n", m_shmid);
132  // TODO: problem, neither semaphore nor tmp file are deleted if they exist
133  // TODO: there is no guarantee that the destructor is called (e.g. on exit(), crash)
134  // printf("DqmSharedMem: destructor called for %s\n", m_strbuf);
135 }
136 
137 void* DqmSharedMem::ptr(void)
138 {
139  return (void*) m_shmadr;
140 }
141 
142 int DqmSharedMem::shmid(void)
143 {
144  return m_shmid;
145 }
146 
147 bool DqmSharedMem::IsCreated(void)
148 {
149  return m_new;
150 }
151 
152 std::string DqmSharedMem::getTmpFileName(std::string user, std::string name)
153 {
154  return string("/tmp/") + user + string("_SHM_") + name;
155 }
156 
157 bool DqmSharedMem::getIdFromTmpFileName(std::string filename, int& shmid, int& semid)
158 {
159  char shminfo[256];
160  int fd = open(filename.c_str(), O_RDONLY);
161  if (fd < 0) {
162  printf("DqmSharedMem: error to reopen tmp file %s\n", filename.c_str());
163  return false;
164  }
165  shmid = -1;
166  semid = -1;
167  memset(shminfo, 0, sizeof(shminfo));
168  int n = read(fd, shminfo, sizeof(shminfo));
169  close(fd);
170  sscanf(shminfo, "%d %d", &shmid, &semid);
171  return (n >= 3 && shmid >= 0 && semid >= 0);
172 }
173 
174 void DqmSharedMem::lock()
175 {
176  struct sembuf sb;
177  sb.sem_num = 0;
178  sb.sem_op = -1;
179  sb.sem_flg = 0;
180  while (semop(m_semid, &sb, 1) == -1) {
181  if (errno == EINTR) {
182  //interrupted by signal (e.g. window size changed), try again
183  continue;
184  } else {
185  perror("lock:semop");
186  exit(-1);
187  }
188  }
189 }
190 
191 void DqmSharedMem::unlock()
192 {
193  struct sembuf sb;
194  sb.sem_num = 0;
195  sb.sem_op = 1;
196  sb.sem_flg = 0;
197  while (semop(m_semid, &sb, 1) == -1) {
198  if (errno == EINTR) {
199  //interrupted by signal (e.g. window size changed), try again
200  continue;
201  } else {
202  perror("unlock:semop");
203  exit(-1);
204  }
205  }
206 }
207 
208 bool DqmSharedMem::isLocked()
209 {
210  int ignored = 0;
211  return (semctl(m_semid, 0, GETVAL, ignored) == 0); //0: locked, 1: unlocked
212 }
213 
214 
Abstract base class for different kinds of events.