DarwinProcessList.c 4.17 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
   host_basic_info_data_t host_info;
David Hunt's avatar
David Hunt committed
28
29
   processor_cpu_load_info_t prev_load;
   processor_cpu_load_info_t curr_load;
David Hunt's avatar
David Hunt committed
30
} DarwinProcessList;
31
32
33

}*/

David Hunt's avatar
David Hunt committed
34
35
36
37
38
39
40
41
42
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
43
44
void ProcessList_freeCPULoadInfo(processor_cpu_load_info_t *p) {
   if(NULL != p && NULL != *p) {
David Hunt's avatar
David Hunt committed
45
46
47
48
49
50
       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
51
52
53
54
55
56
57
   *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
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
92
93
94
95
96
   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;
}


97
ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidWhiteList, uid_t userId) {
David Hunt's avatar
David Hunt committed
98
99
100
   DarwinProcessList* this = calloc(1, sizeof(DarwinProcessList));

   ProcessList_init(&this->super, Class(Process), usersTable, pidWhiteList, userId);
101
   
David Hunt's avatar
David Hunt committed
102
   /* Initialize the previous information */
David Hunt's avatar
David Hunt committed
103
   this->super.cpuCount = ProcessList_allocateCPULoadInfo(&this->prev_load);
David Hunt's avatar
David Hunt committed
104
   ProcessList_getHostInfo(&this->host_info);
David Hunt's avatar
David Hunt committed
105
   ProcessList_allocateCPULoadInfo(&this->curr_load);
David Hunt's avatar
David Hunt committed
106
107

   return &this->super;
108
109
110
111
112
113
114
115
}

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

void ProcessList_goThroughEntries(ProcessList* super) {
David Hunt's avatar
David Hunt committed
116
    DarwinProcessList *dpl = (DarwinProcessList *)super;
117
	bool preExisting = true;
David Hunt's avatar
David Hunt committed
118
119
	struct kinfo_proc *ps;
	size_t count;
120
    Process *proc;
David Hunt's avatar
David Hunt committed
121
122
123
124
    struct timeval tv;

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

David Hunt's avatar
David Hunt committed
125
    /* Update the global data (CPU times) */
David Hunt's avatar
David Hunt committed
126
127
128
    ProcessList_freeCPULoadInfo(&dpl->prev_load);
    dpl->prev_load = dpl->curr_load;
    ProcessList_allocateCPULoadInfo(&dpl->curr_load);
David Hunt's avatar
David Hunt committed
129

David Hunt's avatar
David Hunt committed
130
131
132
133
134
135
136
137
138
139
140
141
142
    /* 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
143
       DarwinProcess_setFromLibprocPidinfo(proc, dpl->host_info.max_mem, preExisting);
David Hunt's avatar
David Hunt committed
144
145
146
147
148
149
150

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

           ProcessList_add(super, proc);
       }
    }
151

David Hunt's avatar
David Hunt committed
152
    free(ps);
153
}