1 /*
2 * %CopyrightBegin%
3 *
4 * Copyright Ericsson AB 1997-2016. All Rights Reserved.
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 * %CopyrightEnd%
19 */
20 /*
21 * CPU supervision
22 *
23 * Uses kstat library only available on Solaris 2
24 * Compile with: gcc -o cpu_sup cpu_sup.c -lkstat
25 *
26 * Use open_port({spawn,Prog},[stream]) to communicate.
27 *
28 */
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <unistd.h>
33 #include <string.h>
34
35 #if (defined(__APPLE__) && defined(__MACH__)) || defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)
36 #include <sys/param.h>
37 #include <sys/sysctl.h>
38 #include <limits.h>
39 #include <fcntl.h>
40 #endif
41 #if defined(__FreeBSD__) || defined(__DragonFly__)
42 #include <kvm.h>
43 #include <sys/user.h>
44 #endif
45
46 #if defined(__sun__)
47 #include <kstat.h>
48 #endif
49
50 #if (defined(__APPLE__) && defined(__MACH__))
51 #include <mach/mach.h>
52 #endif
53
54 #include <errno.h>
55
56 #if defined(__sun__) || defined(__linux__)
57 #include <sys/sysinfo.h>
58 #endif
59
60 #if defined(__linux__)
61
62 #define PROCSTAT "/proc/stat"
63 #define BUFFERSIZE (256)
64 typedef struct {
65 unsigned int id;
66 unsigned long long
67 /* total, */
68 user,
69 nice_user,
70 kernel,
71 idle,
72 io_wait,
73 hard_irq,
74 soft_irq,
75 steal;
76 } cpu_t;
77
78 #endif
79
80 #if (defined(__APPLE__) && defined(__MACH__))
81 #define CU_OSX_VALUES (5)
82 #endif
83
84 #if defined(__FreeBSD__)
85 #include <sys/resource.h>
86 #include <sys/sysctl.h>
87 #define CU_BSD_VALUES (6)
88 #endif
89
90
91 #define FD_IN (0)
92 #define FD_OUT (1)
93 #define FD_ERR (2)
94
95 #define PING 'p'
96 #define NPROCS 'n'
97 #define AVG1 '1'
98 #define AVG5 '5'
99 #define AVG15 'f'
100 #define UTIL 'u'
101 #define QUIT 'q'
102
103
104 #define CU_CPU_ID (0)
105 #define CU_USER (1)
106 #define CU_NICE_USER (2)
107 #define CU_KERNEL (3)
108 #define CU_IO_WAIT (4)
109 #define CU_IDLE (5)
110 #define CU_HARD_IRQ (6)
111 #define CU_SOFT_IRQ (7)
112 #define CU_STEAL (8)
113
114 #define CU_VALUES (9)
115 #define CU_KSTAT_VALUES (5)
116
117 /*
118 #define CU_FLG_CPU_ID (0 << 1)
119 #define CU_FLG_USER (0 << 2)
120 #define CU_FLG_NICE_USER (0 << 3)
121 #define CU_FLG_KERNEL (0 << 4)
122 #define CU_FLG_IO_WAIT (0 << 5)
123 #define CU_FLG_IDLE (0 << 6)
124 #define CU_FLG_HARD_IRQ (0 << 7)
125 #define CU_FLG_SOFT_IRQ (0 << 8)
126 #define CU_FLG_STEAL (0 << 9)
127 */
128
129 /* util_measure
130 * In:
131 * unsigned int **result_vec
132 * int *result_sz
133 * Purpose:
134 * Retrieve CPU utilization
135 * result_vec has 2 + np*ne*2 entries where np is number_of_cpus
136 * |------|------|
137 * | np | ne |
138 * |------|------|
139 * |val_id| value| (One entry)
140 * |------|------|
141 * |val_id| value| (One entry)
142 * |------|------|
143 * ......
144 * |------|------|
145 * |val_id| value|
146 * |------|------|
147 * np = number of processors
148 * ne = number of entries per processor
149 */
150
151 static void util_measure(unsigned int **result_vec, int *result_sz);
152
153 #if defined(__sun__)
154 static unsigned int misc_measure(char* name);
155 #elif defined(__linux__)
156 static unsigned int misc_measure(char cmd);
157 #endif
158 static void sendi(unsigned int data);
159 static void sendv(unsigned int data[], int ints);
160 static void error(char* err_msg);
161
162 #if (defined(__APPLE__) && defined(__MACH__)) || defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)
163 static void bsd_count_procs(void);
164 static void bsd_loadavg(int);
165 #endif
166
167 #if defined(__sun__)
168 static kstat_ctl_t *kstat_ctl;
169 #endif
170
171 #if defined(__linux__)
processors_online()172 static int processors_online() {
173 return (int)sysconf(_SC_NPROCESSORS_ONLN);
174 }
175 #endif
176
177 #if (defined(__APPLE__) && defined(__MACH__)) || defined(__FreeBSD__)
178 void getsysctl(const char *, void *, size_t);
179 #endif
180
main(int argc,char ** argv)181 int main(int argc, char** argv) {
182 char cmd;
183 int rc;
184 int sz;
185 unsigned int *rv;
186 #if defined(__linux__) || (defined(__APPLE__) && defined(__MACH__)) ||defined(__FreeBSD__)
187 unsigned int no_of_cpus = 0;
188 #endif
189
190 #if defined(__sun__)
191 kstat_ctl = kstat_open();
192 if(!kstat_ctl)
193 error("Can't open header kstat");
194 #endif
195
196 #if defined(__linux__)
197 no_of_cpus = processors_online();
198 if ( (rv = (unsigned int*)malloc(sizeof(unsigned int)*(2 + 2*no_of_cpus*CU_VALUES))) == NULL) {
199 error("cpu_sup: malloc error");
200 }
201 #endif
202
203 #if (defined(__APPLE__) && defined(__MACH__))
204 getsysctl("hw.ncpu", &no_of_cpus, sizeof(int));
205 if ( (rv = (unsigned int*)malloc(sizeof(unsigned int)*(2 + 2*no_of_cpus*CU_OSX_VALUES))) == NULL) {
206 error("cpu_sup: malloc error");
207 }
208 #endif
209
210 #if defined(__FreeBSD__)
211 getsysctl("hw.ncpu", &no_of_cpus, sizeof(int));
212 if ( (rv = (unsigned int*)malloc(sizeof(unsigned int)*(2 + 2*no_of_cpus*CU_BSD_VALUES))) == NULL) {
213 error("cpu_sup: malloc error");
214 }
215 #endif
216
217 while(1) {
218
219 rc = read(FD_IN, &cmd, 1);
220 if (rc < 0) {
221 if (errno == EINTR)
222 continue;
223 error("Error reading from Erlang");
224 }
225
226 if(rc == 0)
227 error("Erlang has closed");
228
229 switch(cmd) {
230 case PING: sendi(4711); break;
231 #if defined(__sun__)
232 case NPROCS: sendi(misc_measure("nproc")); break;
233 case AVG1: sendi(misc_measure("avenrun_1min")); break;
234 case AVG5: sendi(misc_measure("avenrun_5min")); break;
235 case AVG15: sendi(misc_measure("avenrun_15min")); break;
236 #elif defined(__linux__)
237 case NPROCS:
238 case AVG1:
239 case AVG5:
240 case AVG15: sendi(misc_measure(cmd)); break;
241 #elif defined(__OpenBSD__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__FreeBSD__) || defined(__DragonFly__)
242 case NPROCS: bsd_count_procs(); break;
243 case AVG1: bsd_loadavg(0); break;
244 case AVG5: bsd_loadavg(1); break;
245 case AVG15: bsd_loadavg(2); break;
246 #endif
247 #if defined(__sun__) || defined(__linux__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__FreeBSD__)
248 case UTIL: util_measure(&rv,&sz); sendv(rv, sz); break;
249 #endif
250 case QUIT: free((void*)rv); return 0;
251 default: error("Bad command"); break;
252 }
253 }
254 return 0; /* suppress warnings */
255 }
256
257 /* ---------------------------- *
258 * BSD stat functions *
259 * ---------------------------- */
260 #if defined(__OpenBSD__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__FreeBSD__) || defined(__DragonFly__)
261
bsd_loadavg(int idx)262 static void bsd_loadavg(int idx) {
263 double avgs[3];
264 if (getloadavg(avgs, 3) < 0) {
265 error(strerror(errno));
266 return;
267 }
268 sendi((unsigned int)(avgs[idx] * 256));
269 }
270
271 #endif
272
273 #if defined(__OpenBSD__)
274
bsd_count_procs(void)275 static void bsd_count_procs(void) {
276 int err, nproc;
277 size_t len = sizeof(nproc);
278 int mib[] = { CTL_KERN, KERN_NPROCS };
279
280 err = sysctl(mib, sizeof(mib) / sizeof(mib[0]), &nproc, &len, NULL, 0);
281 if (err) {
282 error(strerror(errno));
283 return;
284 }
285
286 sendi((unsigned int)nproc);
287 }
288
289 #elif defined(__FreeBSD__) || defined(__DragonFly__)
290
bsd_count_procs(void)291 static void bsd_count_procs(void) {
292 kvm_t *kd;
293 struct kinfo_proc *kp;
294 char err[_POSIX2_LINE_MAX];
295 int cnt = 0;
296
297 if ((kd = kvm_open(NULL, "/dev/null", NULL, O_RDONLY, err)) == NULL) {
298 error(err);
299 return;
300 }
301
302 #if defined(KERN_PROC_PROC)
303 if ((kp = kvm_getprocs(kd, KERN_PROC_PROC, 0, &cnt)) == NULL) {
304 #else
305 if ((kp = kvm_getprocs(kd, KERN_PROC_ALL, 0, &cnt)) == NULL) {
306 #endif
307 error(strerror(errno));
308 return;
309 }
310
311 (void)kvm_close(kd);
312 sendi((unsigned int)cnt);
313 }
314
315 #elif (defined(__APPLE__) && defined(__MACH__))
316
317 static void bsd_count_procs(void) {
318 int err;
319 size_t len = 0;
320 int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL };
321
322 err = sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &len, NULL, 0);
323 if (err) {
324 error(strerror(errno));
325 return;
326 }
327
328 sendi((unsigned int)(len / sizeof(struct kinfo_proc)));
329 }
330
331 #endif
332
333 /* ---------------------------- *
334 * Linux stat functions *
335 * ---------------------------- */
336
337 #if defined(__linux__)
338
339 static unsigned int misc_measure(char cmd) {
340 struct sysinfo info;
341
342 if (sysinfo(&info))
343 error(strerror(errno));
344
345 switch (cmd) {
346 case AVG1: return (unsigned int)(info.loads[0] / 256);
347 case AVG5: return (unsigned int)(info.loads[1] / 256);
348 case AVG15: return (unsigned int)(info.loads[2] / 256);
349 case NPROCS: return info.procs;
350 }
351
352 return -1;
353 }
354
355 static cpu_t *read_procstat(FILE *fp, cpu_t *cpu) {
356 char buffer[BUFFERSIZE];
357
358 if (fgets(buffer, BUFFERSIZE, fp) == NULL) {
359 memset(cpu, 0, sizeof(cpu_t));
360 return cpu;
361 }
362 sscanf(buffer, "cpu%u %llu %llu %llu %llu %llu %llu %llu %llu",
363 &(cpu->id),
364 &(cpu->user),
365 &(cpu->nice_user),
366 &(cpu->kernel),
367 &(cpu->idle),
368 &(cpu->io_wait),
369 &(cpu->hard_irq),
370 &(cpu->soft_irq),
371 &(cpu->steal));
372
373 return cpu;
374 }
375
376 static void util_measure(unsigned int **result_vec, int *result_sz) {
377 int no_of_cpus = processors_online();
378 int i;
379 char buffer[BUFFERSIZE];
380 FILE *fp;
381 unsigned int *rv = NULL;
382 cpu_t cpu;
383
384 rv = *result_vec;
385 rv[0] = no_of_cpus;
386
387 if ( (fp = fopen(PROCSTAT,"r")) == NULL) {
388 if (errno == EACCES) { /* SELinux */
389 rv[1] = 1; /* just the cpu id */
390 ++rv; /* first value is number of cpus */
391 ++rv; /* second value is number of entries */
392 for (i = 0; i < no_of_cpus; ++i) {
393 rv[0] = CU_CPU_ID;
394 rv[1] = i;
395 rv += 1*2;
396 }
397 *result_sz = 2 + 2*1 * no_of_cpus;
398 return;
399 }
400
401 /* Check if procfs is mounted,
402 * otherwise:
403 * try and try again, bad procsfs.
404 */
405 *result_sz = 0;
406 return;
407 }
408
409 /*ignore read*/
410 if (fgets(buffer, BUFFERSIZE, fp) == NULL) {
411 *result_sz = 0;
412 return;
413 }
414
415 rv[1] = CU_VALUES;
416 ++rv; /* first value is number of cpus */
417 ++rv; /* second value is number of entries */
418
419 for (i = 0; i < no_of_cpus; ++i) {
420 read_procstat(fp, &cpu);
421
422 rv[ 0] = CU_CPU_ID; rv[ 1] = cpu.id;
423 rv[ 2] = CU_USER; rv[ 3] = cpu.user;
424 rv[ 4] = CU_NICE_USER; rv[ 5] = cpu.nice_user;
425 rv[ 6] = CU_KERNEL; rv[ 7] = cpu.kernel;
426 rv[ 8] = CU_IO_WAIT; rv[ 9] = cpu.io_wait;
427 rv[10] = CU_IDLE; rv[11] = cpu.idle;
428 rv[12] = CU_HARD_IRQ; rv[13] = cpu.hard_irq;
429 rv[14] = CU_SOFT_IRQ; rv[15] = cpu.soft_irq;
430 rv[16] = CU_STEAL; rv[17] = cpu.steal;
431 rv += CU_VALUES*2;
432 }
433
434 fclose(fp);
435 *result_sz = 2 + 2*CU_VALUES * no_of_cpus;
436 }
437
438 #endif
439
440 /* ---------------------------- *
441 * Unix kstat functions *
442 * ---------------------------- */
443
444 #if defined(__sun__)
445 static unsigned int misc_measure(char* name) {
446 static kstat_t *ksp = NULL;
447 kstat_named_t* entry;
448 kid_t kcid;
449
450 kcid = kstat_chain_update(kstat_ctl);
451
452 if(kcid == -1)
453 error("Error updating kstat chain");
454
455 if (!ksp || kcid != 0) {
456
457 /* The kstat chain changed (or we are initializing);
458 find system misc entry in the new chain... */
459
460 ksp = kstat_lookup(kstat_ctl,"unix",0,"system_misc");
461 if(!ksp)
462 error("Can't open system_misc kstat");
463 }
464
465 kstat_read(kstat_ctl,ksp,NULL);
466 entry = kstat_data_lookup(ksp,name);
467 if(!entry)
468 return -1;
469
470 if(entry->data_type != KSTAT_DATA_UINT32)
471 return -1;
472
473 return entry->value.ui32;
474 }
475
476
477 static int cpu_cmp(const void *p1, const void *p2) {
478 kstat_t *ksp1 = *((kstat_t **) p1);
479 kstat_t *ksp2 = *((kstat_t **) p2);
480
481 if (ksp1->ks_instance > ksp2->ks_instance)
482 return 1;
483 if (ksp1->ks_instance < ksp2->ks_instance)
484 return -1;
485 return 0;
486 }
487
488
489 static void util_measure(unsigned int **result_vec, int *result_sz) {
490 static int no_of_cpus = 0;
491 static kstat_t **cpu_ksps = NULL;
492 static unsigned int * resv = NULL;
493 unsigned int *rv = NULL;
494 kstat_t *ksp;
495 kid_t kcid;
496 int cpu_stats_read;
497 int i;
498
499 kcid = kstat_chain_update(kstat_ctl);
500
501 if(kcid == -1)
502 error("Error updating kstat chain");
503
504 if (no_of_cpus == 0 || kcid != 0) {
505
506 /* The kstat chain changed (or we are initializing);
507 find cpu_stat entries in the new chain... */
508
509 no_of_cpus = 0;
510
511 for(ksp = kstat_ctl->kc_chain; ksp; ksp = ksp->ks_next) {
512 if (strcmp(ksp->ks_module, "cpu_stat") == 0
513 && ksp->ks_type == KSTAT_TYPE_RAW) {
514 no_of_cpus++;
515 /* Assumes that modifications of the cpu_stat_t struct
516 in future releases of Solaris only are additions
517 of fields at the end of the struct. */
518 if(ksp->ks_data_size < sizeof(cpu_stat_t))
519 error("Error: unexpected kstat data size");
520 }
521 }
522
523 free((void *) cpu_ksps);
524 if (no_of_cpus > 0) {
525 cpu_ksps = (kstat_t **) malloc(no_of_cpus*sizeof(kstat_t *));
526 if(!cpu_ksps)
527 error("Error allocating memory");
528
529 i = 0;
530 for(ksp = kstat_ctl->kc_chain;
531 ksp && i < no_of_cpus;
532 ksp = ksp->ks_next) {
533 if (strcmp(ksp->ks_module, "cpu_stat") == 0
534 && ksp->ks_type == KSTAT_TYPE_RAW) {
535 cpu_ksps[i++] = ksp;
536 }
537 }
538
539 if (i != no_of_cpus)
540 error("Error: private kstat chain copy unexpectedly changed");
541
542 /* Erlang assumes that cpu information are sent in ascending order;
543 sort them ... */
544 qsort((void *)cpu_ksps,(size_t)no_of_cpus,sizeof(kstat_t *),cpu_cmp);
545
546 }
547
548 free((void *) resv);
549 /* kstat defined values are:
550 * CU_CPU_ID
551 * CU_USER
552 * CU_KERNEL
553 * CU_IO_WAIT
554 * CU_IDLE
555 */
556 resv = (unsigned int *) malloc(sizeof(unsigned int)*(2 + 2*no_of_cpus*CU_KSTAT_VALUES));
557 if(!resv)
558 error("Error allocating memory");
559
560 }
561
562 /* Read cpu utilization statistics ... */
563
564 rv = resv;
565 rv++; /*first entry is np*/
566 rv++; /*second entry is ne*/
567 cpu_stats_read = 0;
568
569 for(i = 0; i < no_of_cpus; i++) {
570 if (kstat_read(kstat_ctl, cpu_ksps[i], NULL) != -1) {
571 cpu_stat_t *cpu_stat = (cpu_stat_t *)cpu_ksps[i]->ks_data;
572
573 rv[ 0] = CU_CPU_ID; rv[ 1] = cpu_ksps[i]->ks_instance;
574 rv[ 2] = CU_USER; rv[ 3] = cpu_stat->cpu_sysinfo.cpu[CPU_USER];
575 rv[ 4] = CU_KERNEL; rv[ 5] = cpu_stat->cpu_sysinfo.cpu[CPU_KERNEL];
576 rv[ 6] = CU_IO_WAIT; rv[ 7] = cpu_stat->cpu_sysinfo.cpu[CPU_WAIT];
577 rv[ 8] = CU_IDLE; rv[ 9] = cpu_stat->cpu_sysinfo.cpu[CPU_IDLE];
578
579 rv += CU_KSTAT_VALUES*2;
580 cpu_stats_read++;
581 }
582 }
583
584 resv[0] = cpu_stats_read;
585 resv[1] = CU_KSTAT_VALUES;
586
587 *result_vec = resv;
588 *result_sz = 2 + 2* CU_KSTAT_VALUES * cpu_stats_read;
589
590 }
591 #endif
592
593 /* ---------------------------- *
594 * OSX util functions *
595 * ---------------------------- */
596
597 #if (defined(__APPLE__) && defined(__MACH__))
598
599 static void util_measure(unsigned int **result_vec, int *result_sz) {
600 natural_t no_of_cpus;
601 processor_info_array_t info_array;
602 mach_msg_type_number_t info_count;
603 mach_port_t host_port;
604 kern_return_t error;
605 processor_cpu_load_info_data_t *cpu_load_info = NULL;
606 unsigned int *rv = NULL;
607 int i;
608
609 host_port = mach_host_self();
610 error = host_processor_info(host_port, PROCESSOR_CPU_LOAD_INFO,
611 &no_of_cpus, &info_array, &info_count);
612 if (error != KERN_SUCCESS) {
613 *result_sz = 0;
614 return;
615 }
616 mach_port_deallocate(mach_task_self(), host_port);
617 cpu_load_info = (processor_cpu_load_info_data_t *) info_array;
618
619 rv = *result_vec;
620 rv[0] = no_of_cpus;
621 rv[1] = CU_OSX_VALUES;
622 ++rv; /* first value is number of cpus */
623 ++rv; /* second value is number of entries */
624
625 for (i = 0; i < no_of_cpus; ++i) {
626 rv[0] = CU_CPU_ID; rv[1] = i;
627 rv[2] = CU_USER; rv[3] = cpu_load_info[i].cpu_ticks[CPU_STATE_USER];
628 rv[4] = CU_NICE_USER; rv[5] = cpu_load_info[i].cpu_ticks[CPU_STATE_NICE];
629 rv[6] = CU_KERNEL; rv[7] = cpu_load_info[i].cpu_ticks[CPU_STATE_SYSTEM];
630 rv[8] = CU_IDLE; rv[9] = cpu_load_info[i].cpu_ticks[CPU_STATE_IDLE];
631 rv += CU_OSX_VALUES*2;
632 }
633
634 *result_sz = 2 + 2*CU_OSX_VALUES * no_of_cpus;
635
636 error = vm_deallocate(mach_task_self(), (vm_address_t)info_array,
637 info_count * sizeof(int));
638 if (error != KERN_SUCCESS)
639 *result_sz = 0;
640 }
641 #endif
642
643 /* ---------------------------- *
644 * Utils for OSX and FreeBSD *
645 * ---------------------------- */
646
647 #if (defined(__APPLE__) && defined(__MACH__)) || defined(__FreeBSD__)
648
649 #define EXIT_WITH(msg) (rich_error(msg, __FILE__, __LINE__))
650 #define RICH_BUFLEN (213) /* left in error(char*) */
651
652 void rich_error(const char *reason, const char *file, const int line) {
653 char buf[RICH_BUFLEN];
654 snprintf(buf, RICH_BUFLEN, "%s (%s:%i)", reason, file, line);
655 error(buf);
656 }
657 #undef RICH_BUFLEN
658
659 void getsysctl(const char *name, void *ptr, size_t len)
660 {
661 size_t gotlen = len;
662 if (sysctlbyname(name, ptr, &gotlen, NULL, 0) != 0) {
663 EXIT_WITH("sysctlbyname failed");
664 }
665 if (gotlen != len) {
666 EXIT_WITH("sysctlbyname: unexpected length");
667 }
668 }
669 #endif
670
671
672 /* ---------------------------- *
673 * FreeBSD stat functions *
674 * ---------------------------- */
675
676 #if defined(__FreeBSD__)
677
678 static void util_measure(unsigned int **result_vec, int *result_sz) {
679 int no_of_cpus;
680 size_t size_cpu_times;
681 unsigned long *cpu_times;
682 unsigned int *rv = NULL;
683 int i;
684
685 getsysctl("hw.ncpu", &no_of_cpus, sizeof(int));
686 /* Header constant CPUSTATES = #long values per cpu. */
687 size_cpu_times = sizeof(long) * CPUSTATES * no_of_cpus;
688 cpu_times = malloc(size_cpu_times);
689 if (!cpu_times) {
690 EXIT_WITH("badalloc");
691 }
692 getsysctl("kern.cp_times", cpu_times, size_cpu_times);
693
694 rv = *result_vec;
695 rv[0] = no_of_cpus;
696 rv[1] = CU_BSD_VALUES;
697 ++rv; /* first value is number of cpus */
698 ++rv; /* second value is number of entries */
699
700 for (i = 0; i < no_of_cpus; ++i) {
701 int offset = i * CPUSTATES;
702 rv[ 0] = CU_CPU_ID; rv[ 1] = i;
703 rv[ 2] = CU_USER; rv[ 3] = cpu_times[CP_USER + offset];
704 rv[ 4] = CU_NICE_USER; rv[ 5] = cpu_times[CP_NICE + offset];
705 rv[ 6] = CU_KERNEL; rv[ 7] = cpu_times[CP_SYS + offset];
706 rv[ 8] = CU_IDLE; rv[ 9] = cpu_times[CP_IDLE + offset];
707 rv[10] = CU_HARD_IRQ; rv[11] = cpu_times[CP_INTR + offset];
708 rv += CU_BSD_VALUES*2;
709 }
710
711 *result_sz = 2 + 2*CU_BSD_VALUES * no_of_cpus;
712 }
713 #endif
714
715
716 /* ---------------------------- *
717 * Generic functions *
718 * ---------------------------- */
719
720 static void sendi(unsigned int data) { sendv(&data, 1); }
721
722 static void sendv(unsigned int data[], int ints) {
723 static unsigned char *buf = NULL;
724 static int bufsz = 0;
725 int rc, di, bi, msgsz;
726
727 /* Assumes 32-bit integers... */
728
729 msgsz = 4*ints;
730
731 if(bufsz < msgsz) {
732 if (buf != NULL) free((void *) buf);
733 buf = malloc(msgsz);
734 if (!buf) error("Error allocating memory");
735 bufsz = msgsz;
736 }
737
738 for(bi = 0, di = 0; di < ints; di++) {
739 buf[bi++] = (data[di] >> 24) & 0xff;
740 buf[bi++] = (data[di] >> 16) & 0xff;
741 buf[bi++] = (data[di] >> 8) & 0xff;
742 buf[bi++] = (data[di] ) & 0xff;
743 }
744
745 bi = 0;
746 do {
747 rc = write(FD_OUT, &buf[bi], msgsz - bi);
748 if (rc < 0) {
749 if (errno == EINTR)
750 continue;
751 error("Error writing to Erlang");
752 }
753 bi += rc;
754 } while(msgsz - bi > 0);
755
756 }
757
758 static void error(char* err_msg) {
759 /*
760 * if we get error here we have trouble,
761 * silence unnecessary warnings
762 */
763 char buffer[256] = "[os_mon] cpu supervisor port (cpu_sup): ";
764 int i = strlen(buffer), j = 0;
765 int n = strlen(err_msg);
766
767 while(i < 253 && j < n) {
768 buffer[i++] = err_msg[j++];
769 }
770 buffer[i++] = '\r';
771 buffer[i++] = '\n';
772
773 /* try to use one write only */
774 if(write(FD_ERR, buffer, i))
775 ;
776 exit(-1);
777 }
778