DarwinProcessList.c 5.01 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
} DarwinProcessList;
36
37
38

}*/

David Hunt's avatar
David Hunt committed
39
40
41
42
43
44
45
46
47
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
48
49
void ProcessList_freeCPULoadInfo(processor_cpu_load_info_t *p) {
   if(NULL != p && NULL != *p) {
David Hunt's avatar
David Hunt committed
50
51
52
53
54
55
       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
56
57
58
59
60
61
62
   *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
63
64
65
66
67
68
69
70
   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
71
72
73
74
75
76
77
78
79
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
80
81
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
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;
}


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

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

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

David Hunt's avatar
David Hunt committed
121
122
123
124
125
126
127
128
   /* 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
129
   return &this->super;
130
131
132
133
134
135
136
137
}

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

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

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

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

    /* Clear the thread counts */
    super->kernelThreads = 0;
    super->userlandThreads = 0;
    super->totalTasks = 0;
    super->runningTasks = 0;
David Hunt's avatar
David Hunt committed
158

David Hunt's avatar
David Hunt committed
159
160
161
162
163
164
165
166
167
168
169
170
171
    /* 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
172
173
174
       DarwinProcess_setFromLibprocPidinfo(proc, dpl, preExisting);

       super->totalTasks += 1;
David Hunt's avatar
David Hunt committed
175
176
177
178
179
180
181

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

           ProcessList_add(super, proc);
       }
    }
182

David Hunt's avatar
David Hunt committed
183
    free(ps);
184
}