9 #define SEMVMX 32767 /* <= 32767 semaphore maximum value */
12 /* Some versions of libc only define IPC_INFO when __USE_GNU is defined. */
18 uint64_t shmmni; /* max number of segments */
19 uint64_t shmmax; /* max segment size */
20 uint64_t shmall; /* max total shared memory */
21 uint64_t shmmin; /* min segment size */
23 int semmni; /* max number of arrays */
24 int semmsl; /* max semaphores per array */
25 int semmns; /* max semaphores system wide */
26 int semopm; /* max ops per semop call */
27 unsigned int semvmx; /* semaphore max value (constant) */
29 int msgmni; /* max queues system wide */
30 size_t msgmax; /* max size of message */
31 int msgmnb; /* default max size of queue */
35 int semusz; /* current number of arrays */
36 int semaem; /* current semaphores system wide */
40 * The last arg of semctl is a union semun, but where is it defined? X/OPEN
41 * tells us to define it ourselves, but until recently Linux include files
42 * would also define it.
45 #ifndef HAVE_UNION_SEMUN
46 /* according to X/OPEN we have to define it ourselves */
50 unsigned short int *array;
51 struct seminfo *__buf;
54 #else /* __FreeBSD__ */
56 int semmni, /* # of semaphore identifiers */
57 semmns, /* # of semaphores in system */
58 semmnu, /* # of undo structures in system */
59 semmsl, /* max # of semaphores per id */
60 semopm, /* max # of operations per semop call */
61 semume, /* max # of undo entries per process */
62 semusz, /* size in bytes of undo structure */
63 semvmx, /* semaphore maximum value */
64 semaem; /* adjust on exit max value */
66 #endif /* __FreeBSD__ */
68 static inline int ipc_sem_get_limits(struct ipc_limits *lim) {
69 static procfile *ff = NULL;
70 static int error_shown = 0;
71 static char filename[FILENAME_MAX + 1] = "";
73 if(unlikely(!filename[0]))
74 snprintfz(filename, FILENAME_MAX, "%s/proc/sys/kernel/sem", global_host_prefix);
77 ff = procfile_open(filename, NULL, PROCFILE_FLAG_DEFAULT);
79 if(unlikely(!error_shown)) {
80 error("IPC: Cannot open file '%s'.", filename);
87 ff = procfile_readall(ff);
89 if(unlikely(!error_shown)) {
90 error("IPC: Cannot read file '%s'.", filename);
96 if(procfile_lines(ff) >= 1 && procfile_linewords(ff, 0) >= 4) {
98 lim->semmsl = atoi(procfile_lineword(ff, 0, 0));
99 lim->semmns = atoi(procfile_lineword(ff, 0, 1));
100 lim->semopm = atoi(procfile_lineword(ff, 0, 2));
101 lim->semmni = atoi(procfile_lineword(ff, 0, 3));
105 if(unlikely(!error_shown)) {
106 error("IPC: Invalid content in file '%s'.", filename);
113 // cannot do it from the file
116 struct seminfo seminfo = {.semmni = 0};
117 union semun arg = {.array = (ushort *) &seminfo};
119 if(unlikely(semctl(0, 0, IPC_INFO, arg) < 0)) {
120 error("IPC: Failed to read '%s' and request IPC_INFO with semctl().", filename);
124 lim->semvmx = SEMVMX;
125 lim->semmni = seminfo.semmni;
126 lim->semmsl = seminfo.semmsl;
127 lim->semmns = seminfo.semmns;
128 lim->semopm = seminfo.semopm;
142 printf ("------ Semaphore Limits --------\n");
143 printf ("max number of arrays = %d\n", limits.semmni);
144 printf ("max semaphores per array = %d\n", limits.semmsl);
145 printf ("max semaphores system wide = %d\n", limits.semmns);
146 printf ("max ops per semop call = %d\n", limits.semopm);
147 printf ("semaphore max value = %u\n", limits.semvmx);
149 printf ("------ Semaphore Status --------\n");
150 printf ("used arrays = %d\n", status.semusz);
151 printf ("allocated semaphores = %d\n", status.semaem);
154 static inline int ipc_sem_get_status(struct ipc_status *st) {
155 struct seminfo seminfo;
158 arg.array = (ushort *) (void *) &seminfo;
160 if(unlikely(semctl (0, 0, SEM_INFO, arg) < 0)) {
161 /* kernel not configured for semaphores */
162 static int error_shown = 0;
163 if(unlikely(!error_shown)) {
164 error("IPC: kernel is not configured for semaphores");
172 st->semusz = seminfo.semusz;
173 st->semaem = seminfo.semaem;
177 int do_ipc(int update_every, unsigned long long dt) {
180 static int initialized = 0, read_limits_next = 0;
181 static struct ipc_limits limits;
182 static struct ipc_status status;
183 static RRDVAR *arrays_max = NULL, *semaphores_max = NULL;
184 static RRDSET *semaphores = NULL, *arrays = NULL;
186 if(unlikely(!initialized)) {
189 // make sure it works
190 if(ipc_sem_get_limits(&limits) == -1) {
191 error("unable to fetch semaphore limits");
195 // make sure it works
196 if(ipc_sem_get_status(&status) == -1) {
197 error("unable to fetch semaphore statistics");
201 arrays_max = rrdvar_custom_host_variable_create(&localhost, "ipc.semaphores.arrays.max");
202 semaphores_max = rrdvar_custom_host_variable_create(&localhost, "ipc.semaphores.max");
204 if(arrays_max) rrdvar_custom_host_variable_set(arrays_max, limits.semmni);
205 if(semaphores_max) rrdvar_custom_host_variable_set(semaphores_max, limits.semmns);
208 semaphores = rrdset_find("system.ipc_semaphores");
210 semaphores = rrdset_create("system", "ipc_semaphores", NULL, "ipc semaphores", NULL, "IPC Semaphores", "semaphores", 1000, rrd_update_every, RRDSET_TYPE_AREA);
211 rrddim_add(semaphores, "semaphores", NULL, 1, 1, RRDDIM_ABSOLUTE);
214 arrays = rrdset_find("system.ipc_semaphore_arrays");
216 arrays = rrdset_create("system", "ipc_semaphore_arrays", NULL, "ipc semaphores", NULL, "IPC Semaphore Arrays", "arrays", 1000, rrd_update_every, RRDSET_TYPE_AREA);
217 rrddim_add(arrays, "arrays", NULL, 1, 1, RRDDIM_ABSOLUTE);
221 if(unlikely(read_limits_next < 0)) {
222 if(unlikely(ipc_sem_get_limits(&limits) == -1)) {
223 error("Unable to fetch semaphore limits.");
226 rrdvar_custom_host_variable_set(arrays_max, limits.semmni);
227 rrdvar_custom_host_variable_set(semaphores_max, limits.semmns);
229 arrays->red = limits.semmni;
230 semaphores->red = limits.semmns;
232 read_limits_next = 60 / update_every;
238 if(unlikely(ipc_sem_get_status(&status) == -1)) {
239 error("Unable to get semaphore statistics");
243 if(semaphores->counter_done) rrdset_next(semaphores);
244 rrddim_set(semaphores, "semaphores", status.semaem);
245 rrdset_done(semaphores);
247 if(arrays->counter_done) rrdset_next(arrays);
248 rrddim_set(arrays, "arrays", status.semusz);