DarwinProcessList.c 5.42 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>
David Hunt's avatar
David Hunt committed
19
#include <utmpx.h>
20
21

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

typedef struct DarwinProcessList_ {
   ProcessList super;

David Hunt's avatar
David Hunt committed
29
   host_basic_info_data_t host_info;
David Hunt's avatar
David Hunt committed
30
   vm_statistics64_data_t vm_stats;
David Hunt's avatar
David Hunt committed
31
32
   processor_cpu_load_info_t prev_load;
   processor_cpu_load_info_t curr_load;
David Hunt's avatar
David Hunt committed
33
34
   uint64_t kernel_threads;
   uint64_t user_threads;
David Hunt's avatar
David Hunt committed
35
   uint64_t global_diff;
David Hunt's avatar
David Hunt committed
36
} DarwinProcessList;
37
38
39

}*/

David Hunt's avatar
David Hunt committed
40
41
42
43
44
45
46
47
48
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
49
50
void ProcessList_freeCPULoadInfo(processor_cpu_load_info_t *p) {
   if(NULL != p && NULL != *p) {
David Hunt's avatar
David Hunt committed
51
52
53
54
55
56
       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
57
58
59
60
61
62
63
   *p = NULL;
}

unsigned ProcessList_allocateCPULoadInfo(processor_cpu_load_info_t *p) {
   mach_msg_type_number_t info_size = sizeof(processor_cpu_load_info_t);
   unsigned cpu_count;

David Hunt's avatar
David Hunt committed
64
   // TODO Improving the accuracy of the load counts woule help a lot.
David Hunt's avatar
David Hunt committed
65
66
67
68
69
70
71
72
   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;
}

David Hunt's avatar
David Hunt committed
73
74
75
76
77
78
79
80
81
void ProcessList_getVMStats(vm_statistics64_t p) {
    mach_msg_type_number_t info_size = HOST_VM_INFO64_COUNT;

    if(0 != host_statistics64(mach_host_self(), HOST_VM_INFO64, (host_info_t)p, &info_size)) {
       fprintf(stderr, "Unable to retrieve VM statistics\n");
       exit(9);
    }
}

David Hunt's avatar
David Hunt committed
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
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;
}


113
ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidWhiteList, uid_t userId) {
David Hunt's avatar
David Hunt committed
114
115
116
   DarwinProcessList* this = calloc(1, sizeof(DarwinProcessList));

   ProcessList_init(&this->super, Class(Process), usersTable, pidWhiteList, userId);
David Hunt's avatar
David Hunt committed
117
118

   /* Initialize the CPU information */
David Hunt's avatar
David Hunt committed
119
   this->super.cpuCount = ProcessList_allocateCPULoadInfo(&this->prev_load);
David Hunt's avatar
David Hunt committed
120
   ProcessList_getHostInfo(&this->host_info);
David Hunt's avatar
David Hunt committed
121
   ProcessList_allocateCPULoadInfo(&this->curr_load);
David Hunt's avatar
David Hunt committed
122

David Hunt's avatar
David Hunt committed
123
124
125
126
127
128
129
130
   /* Initialize the VM statistics */
   ProcessList_getVMStats(&this->vm_stats);

   this->super.kernelThreads = 0;
   this->super.userlandThreads = 0;
   this->super.totalTasks = 0;
   this->super.runningTasks = 0;

David Hunt's avatar
David Hunt committed
131
   return &this->super;
132
133
134
135
136
137
138
139
}

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

void ProcessList_goThroughEntries(ProcessList* super) {
David Hunt's avatar
David Hunt committed
140
    DarwinProcessList *dpl = (DarwinProcessList *)super;
141
	bool preExisting = true;
David Hunt's avatar
David Hunt committed
142
143
	struct kinfo_proc *ps;
	size_t count;
David Hunt's avatar
David Hunt committed
144
    DarwinProcess *proc;
David Hunt's avatar
David Hunt committed
145
146
147
148
    struct timeval tv;

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

David Hunt's avatar
David Hunt committed
149
    /* Update the global data (CPU times and VM stats) */
David Hunt's avatar
David Hunt committed
150
151
152
    ProcessList_freeCPULoadInfo(&dpl->prev_load);
    dpl->prev_load = dpl->curr_load;
    ProcessList_allocateCPULoadInfo(&dpl->curr_load);
David Hunt's avatar
David Hunt committed
153
154
    ProcessList_getVMStats(&dpl->vm_stats);

David Hunt's avatar
David Hunt committed
155
156
157
158
159
160
161
162
    /* Get the time difference */
    dpl->global_diff = 0;
    for(int i = 0; i < dpl->super.cpuCount; ++i) {
        for(size_t j = 0; j < CPU_STATE_MAX; ++j) {
            dpl->global_diff += dpl->curr_load[i].cpu_ticks[j] - dpl->prev_load[i].cpu_ticks[j];
        }
    }

David Hunt's avatar
David Hunt committed
163
164
165
166
167
    /* Clear the thread counts */
    super->kernelThreads = 0;
    super->userlandThreads = 0;
    super->totalTasks = 0;
    super->runningTasks = 0;
David Hunt's avatar
David Hunt committed
168

David Hunt's avatar
David Hunt committed
169
170
171
172
173
174
175
176
177
178
    /* 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) {
David Hunt's avatar
David Hunt committed
179
       proc = (DarwinProcess *)ProcessList_getProcess(super, ps[i].kp_proc.p_pid, &preExisting, (Process_New)DarwinProcess_new);
David Hunt's avatar
David Hunt committed
180

David Hunt's avatar
David Hunt committed
181
182
       DarwinProcess_setFromKInfoProc(&proc->super, ps + i, tv.tv_sec, preExisting);
       DarwinProcess_setFromLibprocPidinfo(proc, dpl);
David Hunt's avatar
David Hunt committed
183
184

       super->totalTasks += 1;
David Hunt's avatar
David Hunt committed
185
186

       if(!preExisting) {
David Hunt's avatar
David Hunt committed
187
           proc->super.user = UsersTable_getRef(super->usersTable, proc->super.st_uid);
David Hunt's avatar
David Hunt committed
188

David Hunt's avatar
David Hunt committed
189
           ProcessList_add(super, &proc->super);
David Hunt's avatar
David Hunt committed
190
191
       }
    }
192

David Hunt's avatar
David Hunt committed
193
    free(ps);
194
}