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.
44 #ifndef HAVE_UNION_SEMUN
45 /* according to X/OPEN we have to define it ourselves */
49 unsigned short int *array;
50 struct seminfo *__buf;
54 static inline int ipc_sem_get_limits(struct ipc_limits *lim) {
55 static procfile *ff = NULL;
56 static int error_shown = 0;
57 static char filename[FILENAME_MAX + 1] = "";
59 if(unlikely(!filename[0]))
60 snprintfz(filename, FILENAME_MAX, "%s/proc/sys/kernel/sem", global_host_prefix);
63 ff = procfile_open(filename, NULL, PROCFILE_FLAG_DEFAULT);
65 if(unlikely(!error_shown)) {
66 error("IPC: Cannot open file '%s'.", filename);
73 ff = procfile_readall(ff);
75 if(unlikely(!error_shown)) {
76 error("IPC: Cannot read file '%s'.", filename);
82 if(procfile_lines(ff) >= 1 && procfile_linewords(ff, 0) >= 4) {
84 lim->semmsl = str2i(procfile_lineword(ff, 0, 0));
85 lim->semmns = str2i(procfile_lineword(ff, 0, 1));
86 lim->semopm = str2i(procfile_lineword(ff, 0, 2));
87 lim->semmni = str2i(procfile_lineword(ff, 0, 3));
91 if(unlikely(!error_shown)) {
92 error("IPC: Invalid content in file '%s'.", filename);
99 // cannot do it from the file
102 struct seminfo seminfo = {.semmni = 0};
103 union semun arg = {.array = (ushort *) &seminfo};
105 if(unlikely(semctl(0, 0, IPC_INFO, arg) < 0)) {
106 error("IPC: Failed to read '%s' and request IPC_INFO with semctl().", filename);
110 lim->semvmx = SEMVMX;
111 lim->semmni = seminfo.semmni;
112 lim->semmsl = seminfo.semmsl;
113 lim->semmns = seminfo.semmns;
114 lim->semopm = seminfo.semopm;
128 printf ("------ Semaphore Limits --------\n");
129 printf ("max number of arrays = %d\n", limits.semmni);
130 printf ("max semaphores per array = %d\n", limits.semmsl);
131 printf ("max semaphores system wide = %d\n", limits.semmns);
132 printf ("max ops per semop call = %d\n", limits.semopm);
133 printf ("semaphore max value = %u\n", limits.semvmx);
135 printf ("------ Semaphore Status --------\n");
136 printf ("used arrays = %d\n", status.semusz);
137 printf ("allocated semaphores = %d\n", status.semaem);
140 static inline int ipc_sem_get_status(struct ipc_status *st) {
141 struct seminfo seminfo;
144 arg.array = (ushort *) (void *) &seminfo;
146 if(unlikely(semctl (0, 0, SEM_INFO, arg) < 0)) {
147 /* kernel not configured for semaphores */
148 static int error_shown = 0;
149 if(unlikely(!error_shown)) {
150 error("IPC: kernel is not configured for semaphores");
158 st->semusz = seminfo.semusz;
159 st->semaem = seminfo.semaem;
163 int do_ipc(int update_every, usec_t dt) {
166 static int initialized = 0, read_limits_next = 0;
167 static struct ipc_limits limits;
168 static struct ipc_status status;
169 static RRDVAR *arrays_max = NULL, *semaphores_max = NULL;
170 static RRDSET *semaphores = NULL, *arrays = NULL;
172 if(unlikely(!initialized)) {
175 // make sure it works
176 if(ipc_sem_get_limits(&limits) == -1) {
177 error("unable to fetch semaphore limits");
181 // make sure it works
182 if(ipc_sem_get_status(&status) == -1) {
183 error("unable to fetch semaphore statistics");
187 arrays_max = rrdvar_custom_host_variable_create(&localhost, "ipc.semaphores.arrays.max");
188 semaphores_max = rrdvar_custom_host_variable_create(&localhost, "ipc.semaphores.max");
190 if(arrays_max) rrdvar_custom_host_variable_set(arrays_max, limits.semmni);
191 if(semaphores_max) rrdvar_custom_host_variable_set(semaphores_max, limits.semmns);
194 semaphores = rrdset_find("system.ipc_semaphores");
196 semaphores = rrdset_create("system", "ipc_semaphores", NULL, "ipc semaphores", NULL, "IPC Semaphores", "semaphores", 1000, rrd_update_every, RRDSET_TYPE_AREA);
197 rrddim_add(semaphores, "semaphores", NULL, 1, 1, RRDDIM_ABSOLUTE);
200 arrays = rrdset_find("system.ipc_semaphore_arrays");
202 arrays = rrdset_create("system", "ipc_semaphore_arrays", NULL, "ipc semaphores", NULL, "IPC Semaphore Arrays", "arrays", 1000, rrd_update_every, RRDSET_TYPE_AREA);
203 rrddim_add(arrays, "arrays", NULL, 1, 1, RRDDIM_ABSOLUTE);
207 if(unlikely(read_limits_next < 0)) {
208 if(unlikely(ipc_sem_get_limits(&limits) == -1)) {
209 error("Unable to fetch semaphore limits.");
212 if(arrays_max) rrdvar_custom_host_variable_set(arrays_max, limits.semmni);
213 if(semaphores_max) rrdvar_custom_host_variable_set(semaphores_max, limits.semmns);
215 arrays->red = limits.semmni;
216 semaphores->red = limits.semmns;
218 read_limits_next = 60 / update_every;
224 if(unlikely(ipc_sem_get_status(&status) == -1)) {
225 error("Unable to get semaphore statistics");
229 if(semaphores->counter_done) rrdset_next(semaphores);
230 rrddim_set(semaphores, "semaphores", status.semaem);
231 rrdset_done(semaphores);
233 if(arrays->counter_done) rrdset_next(arrays);
234 rrddim_set(arrays, "arrays", status.semusz);