]> arthur.barton.de Git - netdata.git/blob - src/ipc.c
Merge pull request #1998 from ktsaou/master
[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 HAVE_UNION_SEMUN
45 /* according to X/OPEN we have to define it ourselves */
46 union semun {
47     int val;
48     struct semid_ds *buf;
49     unsigned short int *array;
50     struct seminfo *__buf;
51 };
52 #endif
53
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] = "";
58
59     if(unlikely(!filename[0]))
60         snprintfz(filename, FILENAME_MAX, "%s/proc/sys/kernel/sem", netdata_configured_host_prefix);
61
62     if(unlikely(!ff)) {
63         ff = procfile_open(filename, NULL, PROCFILE_FLAG_DEFAULT);
64         if(unlikely(!ff)) {
65             if(unlikely(!error_shown)) {
66                 error("IPC: Cannot open file '%s'.", filename);
67                 error_shown = 1;
68             }
69             goto ipc;
70         }
71     }
72
73     ff = procfile_readall(ff);
74     if(unlikely(!ff)) {
75         if(unlikely(!error_shown)) {
76             error("IPC: Cannot read file '%s'.", filename);
77             error_shown = 1;
78         }
79         goto ipc;
80     }
81
82     if(procfile_lines(ff) >= 1 && procfile_linewords(ff, 0) >= 4) {
83         lim->semvmx = SEMVMX;
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));
88         return 0;
89     }
90     else {
91         if(unlikely(!error_shown)) {
92             error("IPC: Invalid content in file '%s'.", filename);
93             error_shown = 1;
94         }
95         goto ipc;
96     }
97
98 ipc:
99     // cannot do it from the file
100     // query IPC
101     {
102         struct seminfo seminfo = {.semmni = 0};
103         union semun arg = {.array = (ushort *) &seminfo};
104
105         if(unlikely(semctl(0, 0, IPC_INFO, arg) < 0)) {
106             error("IPC: Failed to read '%s' and request IPC_INFO with semctl().", filename);
107             goto error;
108         }
109
110         lim->semvmx = SEMVMX;
111         lim->semmni = seminfo.semmni;
112         lim->semmsl = seminfo.semmsl;
113         lim->semmns = seminfo.semmns;
114         lim->semopm = seminfo.semopm;
115         return 0;
116     }
117
118 error:
119     lim->semvmx = 0;
120     lim->semmni = 0;
121     lim->semmsl = 0;
122     lim->semmns = 0;
123     lim->semopm = 0;
124     return -1;
125 }
126
127 /*
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);
134
135 printf ("------ Semaphore Status --------\n");
136 printf ("used arrays = %d\n", status.semusz);
137 printf ("allocated semaphores = %d\n", status.semaem);
138 */
139
140 static inline int ipc_sem_get_status(struct ipc_status *st) {
141     struct seminfo seminfo;
142     union semun arg;
143
144     arg.array = (ushort *)  (void *) &seminfo;
145
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");
151             error_shown = 1;
152         }
153         st->semusz = 0;
154         st->semaem = 0;
155         return -1;
156     }
157
158     st->semusz = seminfo.semusz;
159     st->semaem = seminfo.semaem;
160     return 0;
161 }
162
163 int do_ipc(int update_every, usec_t dt) {
164     (void)dt;
165
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;
171
172     if(unlikely(!initialized)) {
173         initialized = 1;
174         
175         // make sure it works
176         if(ipc_sem_get_limits(&limits) == -1) {
177             error("unable to fetch semaphore limits");
178             return 1;
179         }
180
181         // make sure it works
182         if(ipc_sem_get_status(&status) == -1) {
183             error("unable to fetch semaphore statistics");
184             return 1;
185         }
186
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");
189
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);
192
193         // create the charts
194         semaphores = rrdset_find_localhost("system.ipc_semaphores");
195         if(!semaphores) {
196             semaphores = rrdset_create_localhost("system", "ipc_semaphores", NULL, "ipc semaphores", NULL
197                                                  , "IPC Semaphores", "semaphores", 1000, localhost->rrd_update_every
198                                                  , RRDSET_TYPE_AREA);
199             rrddim_add(semaphores, "semaphores", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
200         }
201
202         arrays = rrdset_find_localhost("system.ipc_semaphore_arrays");
203         if(!arrays) {
204             arrays = rrdset_create_localhost("system", "ipc_semaphore_arrays", NULL, "ipc semaphores", NULL
205                                              , "IPC Semaphore Arrays", "arrays", 1000, localhost->rrd_update_every
206                                              , RRDSET_TYPE_AREA);
207             rrddim_add(arrays, "arrays", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
208         }
209     }
210
211     if(unlikely(read_limits_next < 0)) {
212         if(unlikely(ipc_sem_get_limits(&limits) == -1)) {
213             error("Unable to fetch semaphore limits.");
214         }
215         else {
216             if(arrays_max)     rrdvar_custom_host_variable_set(arrays_max, limits.semmni);
217             if(semaphores_max) rrdvar_custom_host_variable_set(semaphores_max, limits.semmns);
218
219             arrays->red = limits.semmni;
220             semaphores->red = limits.semmns;
221
222             read_limits_next = 60 / update_every;
223         }
224     }
225     else
226         read_limits_next--;
227
228     if(unlikely(ipc_sem_get_status(&status) == -1)) {
229         error("Unable to get semaphore statistics");
230         return 0;
231     }
232
233     if(semaphores->counter_done) rrdset_next(semaphores);
234     rrddim_set(semaphores, "semaphores", status.semaem);
235     rrdset_done(semaphores);
236
237     if(arrays->counter_done) rrdset_next(arrays);
238     rrddim_set(arrays, "arrays", status.semusz);
239     rrdset_done(arrays);
240
241     return 0;
242 }