1#include <sys/param.h>
2#include <sys/user.h>
3#include <sys/time.h>
4#include <sys/resource.h>
5#include <sys/stat.h>
6#include <sys/ioctl.h>
7#include <sys/sysctl.h>
8
9#include <ctype.h>
10#include <err.h>
11#include <errno.h>
12#include <fcntl.h>
13#include <limits.h>
14#include <nlist.h>
15#include <paths.h>
16#include <stdio.h>
17#include <stdlib.h>
18#include <string.h>
19#include <unistd.h>
20#include <locale.h>
21#include <pwd.h>
22
23#include "ps.h"
24#include <mach/shared_memory_server.h>
25
26extern kern_return_t task_for_pid(task_port_t task, pid_t pid, task_port_t *target);
27
28#define STATE_MAX       7
29
30int
31mach_state_order(s, sleep_time)
32int s;
33long sleep_time;
34{
35switch (s) {
36case TH_STATE_RUNNING:      return(1);
37case TH_STATE_UNINTERRUPTIBLE:
38                                return(2);
39    case TH_STATE_WAITING:      return((sleep_time > 20) ? 4 : 3);
40    case TH_STATE_STOPPED:      return(5);
41    case TH_STATE_HALTED:       return(6);
42    default:                    return(7);
43    }
44}
45                            /*01234567 */
46char    mach_state_table[] = " RUSITH?";
47
48
49int
50thread_schedinfo(
51	KINFO *ki,
52	thread_port_t		thread,
53	policy_t		pol,
54	void * buf)
55{
56	unsigned int		count;
57	int ret = KERN_FAILURE;
58
59	switch (pol) {
60
61	case POLICY_TIMESHARE:
62		count = POLICY_TIMESHARE_INFO_COUNT;
63		ret = thread_info(thread, THREAD_SCHED_TIMESHARE_INFO,
64					(thread_info_t)buf, &count);
65		if((ret == KERN_SUCCESS) && (ki->curpri < (((struct policy_timeshare_info *)buf)->cur_priority)))
66			ki->curpri  = ((struct policy_timeshare_info *)buf)->cur_priority;
67		break;
68
69	case POLICY_FIFO:
70		count = POLICY_FIFO_INFO_COUNT;
71		ret = thread_info(thread, THREAD_SCHED_FIFO_INFO,
72					buf, &count);
73		if((ret == KERN_SUCCESS) && (ki->curpri < (((struct policy_fifo_info *)buf)->base_priority)))
74			ki->curpri  = ((struct policy_fifo_info *)buf)->base_priority;
75		break;
76
77	case POLICY_RR:
78		count = POLICY_RR_INFO_COUNT;
79		ret = thread_info(thread, THREAD_SCHED_RR_INFO,
80					buf, &count);
81		if((ret == KERN_SUCCESS) && (ki->curpri < (((struct policy_rr_info *)buf)->base_priority)))
82			ki->curpri  = ((struct policy_rr_info *)buf)->base_priority;
83		break;
84	}
85	return(ret);
86}
87
88int get_task_info (KINFO *ki)
89{
90	kern_return_t   	error;
91	unsigned int		info_count = TASK_BASIC_INFO_COUNT;
92        unsigned int 		thread_info_count = THREAD_BASIC_INFO_COUNT;
93        pid_t				pid;
94	int j, err = 0;
95
96	ki->state = STATE_MAX;
97
98	pid = KI_PROC(ki)->p_pid;
99	if (task_for_pid(mach_task_self(), pid, &ki->task) != KERN_SUCCESS) {
100                return(1);
101	}
102	info_count = TASK_BASIC_INFO_COUNT;
103	 error = task_info(ki->task, TASK_BASIC_INFO, (task_info_t)&ki->tasks_info, &info_count);
104	 if (error != KERN_SUCCESS) {
105		 ki->invalid_tinfo=1;
106#ifdef DEBUG
107		 mach_error("Error calling task_info()", error);
108#endif
109		return(1);
110	}
111	{
112	        vm_region_basic_info_data_64_t    b_info;
113		vm_address_t	                  address = GLOBAL_SHARED_TEXT_SEGMENT;
114		vm_size_t		          size;
115		mach_port_t		          object_name;
116
117		/*
118		 * try to determine if this task has the split libraries
119		 * mapped in... if so, adjust its virtual size down by
120		 * the 2 segments that are used for split libraries
121		 */
122		info_count = VM_REGION_BASIC_INFO_COUNT_64;
123		error = vm_region_64(ki->task, &address, &size, VM_REGION_BASIC_INFO,
124				     (vm_region_info_t)&b_info, &info_count, &object_name);
125	        if (error == KERN_SUCCESS) {
126		        if (b_info.reserved && size == (SHARED_TEXT_REGION_SIZE) &&
127			    ki->tasks_info.virtual_size > (SHARED_TEXT_REGION_SIZE + SHARED_DATA_REGION_SIZE))
128			        ki->tasks_info.virtual_size -= (SHARED_TEXT_REGION_SIZE + SHARED_DATA_REGION_SIZE);
129		}
130	}
131	info_count = TASK_THREAD_TIMES_INFO_COUNT;
132        error = task_info(ki->task, TASK_THREAD_TIMES_INFO, (task_info_t)&ki->times, &info_count);
133        if (error != KERN_SUCCESS) {
134                 ki->invalid_tinfo=1;
135#ifdef DEBUG
136                 mach_error("Error calling task_info()", error);
137#endif
138                return(1);
139        }
140	switch(ki->tasks_info.policy) {
141		case POLICY_TIMESHARE :
142		info_count = POLICY_TIMESHARE_INFO_COUNT;
143		error = task_info(ki->task, TASK_SCHED_TIMESHARE_INFO, (task_info_t)&ki->schedinfo.tshare, &info_count);
144			if (error != KERN_SUCCESS) {
145				ki->invalid_tinfo=1;
146#ifdef DEBUG
147				mach_error("Error calling task_info()", error);
148#endif
149				return(1);
150				}
151
152			ki->curpri = ki->schedinfo.tshare.cur_priority;
153			ki->basepri = ki->schedinfo.tshare.base_priority;
154			break;
155		case POLICY_RR :
156 		info_count = POLICY_RR_INFO_COUNT;
157		error = task_info(ki->task, TASK_SCHED_RR_INFO, (task_info_t)&ki->schedinfo.rr, &info_count);
158			if (error != KERN_SUCCESS) {
159				ki->invalid_tinfo=1;
160#ifdef DEBUG
161				mach_error("Error calling task_info()", error);
162#endif
163				return(1);
164				}
165
166                        ki->curpri = ki->schedinfo.rr.base_priority;
167                        ki->basepri = ki->schedinfo.rr.base_priority;
168                        break;
169
170		case POLICY_FIFO :
171  		info_count = POLICY_FIFO_INFO_COUNT;
172		error = task_info(ki->task, TASK_SCHED_FIFO_INFO, (task_info_t)&ki->schedinfo.fifo, &info_count);
173			if (error != KERN_SUCCESS) {
174				ki->invalid_tinfo=1;
175#ifdef DEBUG
176				mach_error("Error calling task_info()", error);
177#endif
178				return(1);
179				}
180
181                        ki->curpri = ki->schedinfo.fifo.base_priority;
182                        ki->basepri = ki->schedinfo.fifo.base_priority;
183                        break;
184	}
185
186	 ki->invalid_tinfo=0;
187
188	ki->cpu_usage=0;
189	error = task_threads(ki->task, &ki->thread_list, &ki->thread_count);
190	if (error != KERN_SUCCESS) {
191		mach_port_deallocate(mach_task_self(),ki->task);
192#ifdef DEBUG
193		mach_error("Call to task_threads() failed", error);
194#endif
195		return(1);
196	}
197	err=0;
198	//ki->curpri = 255;
199	//ki->basepri = 255;
200	ki->swapped = 1;
201	ki->thval = malloc(ki->thread_count * sizeof(struct thread_values));
202	for (j = 0; j < ki->thread_count; j++) {
203		int tstate;
204        	thread_info_count = THREAD_BASIC_INFO_COUNT;
205		error = thread_info(ki->thread_list[j], THREAD_BASIC_INFO,
206			 (thread_info_t)&ki->thval[j].tb,
207			&thread_info_count);
208		if (error != KERN_SUCCESS) {
209#ifdef DEBUG
210			mach_error("Call to thread_info() failed", error);
211#endif
212			err=1;
213			}
214		error = thread_schedinfo(ki, ki->thread_list[j],
215			ki->thval[j].tb.policy, &ki->thval[j].schedinfo);
216		if (error != KERN_SUCCESS) {
217#ifdef DEBUG
218			mach_error("Call to thread_info() failed", error);
219#endif
220			err=1;
221			}
222		ki->cpu_usage += ki->thval[j].tb.cpu_usage;
223		tstate = mach_state_order(ki->thval[j].tb.run_state,
224				ki->thval[j].tb.sleep_time);
225		if (tstate < ki->state)
226			ki->state = tstate;
227		if ((ki->thval[j].tb.flags & TH_FLAGS_SWAPPED ) == 0)
228			ki->swapped = 0;
229		mach_port_deallocate(mach_task_self(),
230			ki->thread_list[j]);
231	}
232	ki->invalid_thinfo = err;
233	 /* Deallocate the list of threads. */
234	error = vm_deallocate(mach_task_self(),
235		(vm_address_t)(ki->thread_list),
236		 sizeof(*ki->thread_list) * ki->thread_count);
237	if (error != KERN_SUCCESS) {
238#ifdef DEBUG
239		 mach_error("Trouble freeing thread_list", error);
240#endif
241	}
242
243	mach_port_deallocate(mach_task_self(),ki->task);
244	return(0);
245}
246