]> arthur.barton.de Git - netdata.git/blob - src/ipc.c
54ebe81749aec4e36984009d75e6695e0e70f168
[netdata.git] / src / ipc.c
1 #include "common.h"
2
3 #include <sys/sem.h>
4 #include <sys/msg.h>
5 #include <sys/shm.h>
6
7
8 #ifndef SEMVMX
9 #define SEMVMX  32767  /* <= 32767 semaphore maximum value */
10 #endif
11
12 /* Some versions of libc only define IPC_INFO when __USE_GNU is defined. */
13 #ifndef IPC_INFO
14 #define IPC_INFO   3
15 #endif
16
17 struct ipc_limits {
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 */
22
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) */
28
29     int             msgmni;     /* max queues system wide */
30     size_t          msgmax;     /* max size of message */
31     int             msgmnb;     /* default max size of queue */
32 };
33
34 struct ipc_status {
35     int             semusz;     /* current number of arrays */
36     int             semaem;     /* current semaphores system wide */
37 };
38
39 /*
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.
43  */
44 #ifndef __FreeBSD__
45 #ifndef HAVE_UNION_SEMUN
46 /* according to X/OPEN we have to define it ourselves */
47 union semun {
48     int val;
49     struct semid_ds *buf;
50     unsigned short int *array;
51     struct seminfo *__buf;
52 };
53 #endif
54 #else /* __FreeBSD__ */
55 struct seminfo {
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 */
65 };
66 #endif /* __FreeBSD__ */
67
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] = "";
72
73     if(unlikely(!filename[0]))
74         snprintfz(filename, FILENAME_MAX, "%s/proc/sys/kernel/sem", global_host_prefix);
75
76     if(unlikely(!ff)) {
77         ff = procfile_open(filename, NULL, PROCFILE_FLAG_DEFAULT);
78         if(unlikely(!ff)) {
79             if(unlikely(!error_shown)) {
80                 error("IPC: Cannot open file '%s'.", filename);
81                 error_shown = 1;
82             }
83             goto ipc;
84         }
85     }
86
87     ff = procfile_readall(ff);
88     if(unlikely(!ff)) {
89         if(unlikely(!error_shown)) {
90             error("IPC: Cannot read file '%s'.", filename);
91             error_shown = 1;
92         }
93         goto ipc;
94     }
95
96     if(procfile_lines(ff) >= 1 && procfile_linewords(ff, 0) >= 4) {
97         lim->semvmx = SEMVMX;
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));
102         return 0;
103     }
104     else {
105         if(unlikely(!error_shown)) {
106             error("IPC: Invalid content in file '%s'.", filename);
107             error_shown = 1;
108         }
109         goto ipc;
110     }
111
112 ipc:
113     // cannot do it from the file
114     // query IPC
115     {
116         struct seminfo seminfo = {.semmni = 0};
117         union semun arg = {.array = (ushort *) &seminfo};
118
119         if(unlikely(semctl(0, 0, IPC_INFO, arg) < 0)) {
120             error("IPC: Failed to read '%s' and request IPC_INFO with semctl().", filename);
121             goto error;
122         }
123
124         lim->semvmx = SEMVMX;
125         lim->semmni = seminfo.semmni;
126         lim->semmsl = seminfo.semmsl;
127         lim->semmns = seminfo.semmns;
128         lim->semopm = seminfo.semopm;
129         return 0;
130     }
131
132 error:
133     lim->semvmx = 0;
134     lim->semmni = 0;
135     lim->semmsl = 0;
136     lim->semmns = 0;
137     lim->semopm = 0;
138     return -1;
139 }
140
141 /*
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);
148
149 printf ("------ Semaphore Status --------\n");
150 printf ("used arrays = %d\n", status.semusz);
151 printf ("allocated semaphores = %d\n", status.semaem);
152 */
153
154 static inline int ipc_sem_get_status(struct ipc_status *st) {
155     struct seminfo seminfo;
156     union semun arg;
157
158     arg.array = (ushort *)  (void *) &seminfo;
159
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");
165             error_shown = 1;
166         }
167         st->semusz = 0;
168         st->semaem = 0;
169         return -1;
170     }
171
172     st->semusz = seminfo.semusz;
173     st->semaem = seminfo.semaem;
174     return 0;
175 }
176
177 int do_ipc(int update_every, unsigned long long dt) {
178     (void)dt;
179
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;
185
186     if(unlikely(!initialized)) {
187         initialized = 1;
188         
189         // make sure it works
190         if(ipc_sem_get_limits(&limits) == -1) {
191             error("unable to fetch semaphore limits");
192             return 1;
193         }
194
195         // make sure it works
196         if(ipc_sem_get_status(&status) == -1) {
197             error("unable to fetch semaphore statistics");
198             return 1;
199         }
200
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");
203
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);
206
207         // create the charts
208         semaphores = rrdset_find("system.ipc_semaphores");
209         if(!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);
212         }
213
214         arrays = rrdset_find("system.ipc_semaphore_arrays");
215         if(!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);
218         }
219     }
220
221     if(unlikely(read_limits_next < 0)) {
222         if(unlikely(ipc_sem_get_limits(&limits) == -1)) {
223             error("Unable to fetch semaphore limits.");
224         }
225         else {
226             rrdvar_custom_host_variable_set(arrays_max, limits.semmni);
227             rrdvar_custom_host_variable_set(semaphores_max, limits.semmns);
228
229             arrays->red = limits.semmni;
230             semaphores->red = limits.semmns;
231
232             read_limits_next = 60 / update_every;
233         }
234     }
235     else
236         read_limits_next--;
237
238     if(unlikely(ipc_sem_get_status(&status) == -1)) {
239         error("Unable to get semaphore statistics");
240         return 0;
241     }
242
243     if(semaphores->counter_done) rrdset_next(semaphores);
244     rrddim_set(semaphores, "semaphores", status.semaem);
245     rrdset_done(semaphores);
246
247     if(arrays->counter_done) rrdset_next(arrays);
248     rrddim_set(arrays, "arrays", status.semusz);
249     rrdset_done(arrays);
250
251     return 0;
252 }