DarwinProcessList.c 3.92 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
/*
htop - DarwinProcessList.c
(C) 2014 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/

#include "ProcessList.h"
#include "DarwinProcess.h"
#include "DarwinProcessList.h"

#include <stdlib.h>
#include <string.h>
David Hunt's avatar
David Hunt committed
14
15
16
#include <unistd.h>
#include <stdio.h>
#include <libproc.h>
David Hunt's avatar
David Hunt committed
17
18
#include <mach/vm_page_size.h>
#include <sys/mman.h>
19
20

/*{
David Hunt's avatar
David Hunt committed
21
22
23
24
25
26
#include <mach/mach_host.h>
#include <sys/sysctl.h>

typedef struct DarwinProcessList_ {
   ProcessList super;

David Hunt's avatar
David Hunt committed
27
28
   host_basic_info_data_t host_info;
   processor_cpu_load_info_t cpu_load;
David Hunt's avatar
David Hunt committed
29
} DarwinProcessList;
30
31
32

}*/

David Hunt's avatar
David Hunt committed
33
34
35
36
37
38
39
40
41
void ProcessList_getHostInfo(host_basic_info_data_t *p) {
   mach_msg_type_number_t info_size = HOST_BASIC_INFO_COUNT;

   if(0 != host_info(mach_host_self(), HOST_BASIC_INFO, (host_info_t)p, &info_size)) {
       fprintf(stderr, "Unable to retrieve host info\n");
       exit(2);
   }
}

David Hunt's avatar
David Hunt committed
42
43
unsigned ProcessList_updateCPULoadInfo(processor_cpu_load_info_t *p) {
   mach_msg_type_number_t info_size = sizeof(processor_cpu_load_info_t);
David Hunt's avatar
David Hunt committed
44
45
   unsigned cpu_count;

David Hunt's avatar
David Hunt committed
46
47
48
49
50
51
52
   if(NULL != p) {
       if(0 != munmap(*p, vm_page_size)) {
           fprintf(stderr, "Unable to free old CPU load information\n");
           exit(8);
       }
   }

David Hunt's avatar
David Hunt committed
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
   if(0 != host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &cpu_count, (processor_info_array_t *)p, &info_size)) {
       fprintf(stderr, "Unable to retrieve CPU info\n");
       exit(4);
   }

   return cpu_count;
}

struct kinfo_proc *ProcessList_getKInfoProcs(size_t *count) {
   int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0 };
   struct kinfo_proc *processes = NULL;

   /* Note the two calls to sysctl(). One to get length and one to get the
    * data. This -does- mean that the second call could end up with a missing
    * process entry or two.
    */
   *count = 0;
   if(0 > sysctl(mib, 4, NULL, count, NULL, 0)) {
      fprintf(stderr, "Unable to get size of kproc_infos");
      exit(5);
   }

   processes = (struct kinfo_proc *)malloc(*count);
   if(NULL == processes) {
      fprintf(stderr, "Out of memory for kproc_infos\n");
      exit(6);
   }

   if(0 > sysctl(mib, 4, processes, count, NULL, 0)) {
      fprintf(stderr, "Unable to get kinfo_procs\n");
      exit(7);
   }

   *count = *count / sizeof(struct kinfo_proc);

   return processes;
}


92
ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidWhiteList, uid_t userId) {
David Hunt's avatar
David Hunt committed
93
94
95
   DarwinProcessList* this = calloc(1, sizeof(DarwinProcessList));

   ProcessList_init(&this->super, Class(Process), usersTable, pidWhiteList, userId);
96
   
David Hunt's avatar
David Hunt committed
97
   /* Initialize the previous information */
David Hunt's avatar
David Hunt committed
98
99
100
   this->cpu_load = NULL;
   this->super.cpuCount = ProcessList_updateCPULoadInfo(&this->cpu_load);
   ProcessList_getHostInfo(&this->host_info);
David Hunt's avatar
David Hunt committed
101
102

   return &this->super;
103
104
105
106
107
108
109
110
}

void ProcessList_delete(ProcessList* this) {
   ProcessList_done(this);
   free(this);
}

void ProcessList_goThroughEntries(ProcessList* super) {
David Hunt's avatar
David Hunt committed
111
    DarwinProcessList *dpl = (DarwinProcessList *)super;
112
	bool preExisting = true;
David Hunt's avatar
David Hunt committed
113
114
	struct kinfo_proc *ps;
	size_t count;
115
    Process *proc;
David Hunt's avatar
David Hunt committed
116
117
118
119
    struct timeval tv;

    gettimeofday(&tv, NULL); /* Start processing time */

David Hunt's avatar
David Hunt committed
120
121
122
    /* Update the global data (CPU times) */
    ProcessList_updateCPULoadInfo(&dpl->cpu_load);

David Hunt's avatar
David Hunt committed
123
124
125
126
127
128
129
130
131
132
133
134
135
    /* We use kinfo_procs for initial data since :
     *
     * 1) They always succeed.
     * 2) The contain the basic information.
     *
     * We attempt to fill-in additional information with libproc.
     */
    ps = ProcessList_getKInfoProcs(&count);

    for(size_t i = 0; i < count; ++i) {
       proc = ProcessList_getProcess(super, ps[i].kp_proc.p_pid, &preExisting, DarwinProcess_new);

       DarwinProcess_setFromKInfoProc(proc, ps + i, tv.tv_sec, preExisting);
David Hunt's avatar
David Hunt committed
136
       DarwinProcess_setFromLibprocPidinfo(proc, dpl->host_info.max_mem, preExisting);
David Hunt's avatar
David Hunt committed
137
138
139
140
141
142
143

       if(!preExisting) {
           proc->user = UsersTable_getRef(super->usersTable, proc->st_uid);

           ProcessList_add(super, proc);
       }
    }
144

David Hunt's avatar
David Hunt committed
145
    free(ps);
146
}