3 * cpulimit - a cpu limiter for Linux
5 * Copyright (C) 2005-2008, by: Angelo Marletta <marlonx80@hotmail.com>
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 #include <sys/utsname.h>
23 #include "procutils.h"
25 /* PROCESS STATISTICS FUNCTIONS */
27 // returns pid of the parent process
28 static int getppid_of(int pid)
32 sprintf(file, "/proc/%d/stat", pid);
33 FILE *fd = fopen(file, "r");
34 if (fd==NULL) return -1;
35 fgets(buffer, sizeof(buffer), fd);
38 p = memchr(p+1,')', sizeof(buffer) - (p-buffer));
41 p = memchr(p+1,' ',sizeof(buffer) - (p-buffer));
42 //pid of the parent process
47 // returns the start time of a process (used with pid to identify a process)
48 static int get_starttime(int pid)
52 sprintf(file, "/proc/%d/stat", pid);
53 FILE *fd = fopen(file, "r");
54 if (fd==NULL) return -1;
55 fgets(buffer, sizeof(buffer), fd);
58 p = memchr(p+1,')', sizeof(buffer) - (p-buffer));
61 p = memchr(p+1,' ',sizeof(buffer) - (p-buffer));
62 //start time of the process
67 // detects whether a process is a kernel thread or not
68 static int is_kernel_thread(int pid)
70 static char statfile[20];
71 static char buffer[64];
73 sprintf(statfile, "/proc/%d/statm", pid);
74 FILE *fd = fopen(statfile, "r");
75 if (fd==NULL) return -1;
76 fgets(buffer, sizeof(buffer), fd);
77 ret = strncmp(buffer,"0 0 0",3)==0;
82 // returns 1 if pid is a user process, 0 otherwise
83 static int process_exists(int pid) {
84 static char statfile[20];
85 static char buffer[64];
87 sprintf(statfile, "/proc/%d/statm", pid);
88 FILE *fd = fopen(statfile, "r");
89 if (fd==NULL) return 0;
90 fgets(buffer, sizeof(buffer), fd);
91 ret = strncmp(buffer,"0 0 0",3)!=0;
96 /* PID HASH FUNCTIONS */
98 static int hash_process(struct process_family *f, struct process *p)
101 struct list **l = &(f->hashtable[pid_hashfn(p->pid)]);
103 //there is no process in this hashtable item
105 *l = malloc(sizeof(struct list));
112 //list already exists
113 struct process *tmp = (struct process*)locate_elem(*l, p);
115 //update process info
116 memcpy(tmp, p, sizeof(struct process));
129 static void unhash_process(struct process_family *f, int pid) {
130 //remove process from hashtable
131 struct list **l = &(f->hashtable[pid_hashfn(pid)]);
133 return; //nothing done
134 struct list_node *node = locate_node(*l, &pid);
136 destroy_node(*l, node);
140 static struct process *find_process(struct process_family *f, int pid)
142 struct list **l = &(f->hashtable[pid_hashfn(pid)]);
143 return (*l != NULL) ? (struct process*)locate_elem(*l, &pid) : NULL;
147 static int is_member(struct process_family *f, int pid) {
148 struct process *p = find_process(f, pid);
149 return (p!=NULL && p->member);
152 static int exists(struct process_family *f, int pid) {
153 struct process *p = find_process(f, pid);
158 /* PROCESS ITERATOR STUFF */
160 // creates an object that browse all running processes
161 static int init_process_iterator(struct process_iterator *i) {
162 //open a directory stream to /proc directory
163 if ((i->dip = opendir("/proc")) == NULL) {
170 // reads the next user process from /process
171 // automatic closing if the end of the list is reached
172 static int read_next_process(struct process_iterator *i) {
173 //read in from /proc and seek for process dirs
175 while ((i->dit = readdir(i->dip)) != NULL) {
176 pid = atoi(i->dit->d_name);
177 if (pid<=0 || is_kernel_thread(pid))
179 //return the first found process
183 //no more processes, release resources
189 /* PUBLIC FUNCTIONS */
191 // searches for all the processes derived from father and stores them
192 // in the process family struct
193 int create_process_family(struct process_family *f, int father)
195 //process list initialization
196 init_list(&(f->members), 4);
197 //hashtable initialization
198 memset(&(f->hashtable), 0, sizeof(f->hashtable));
202 struct process_iterator iter;
203 init_process_iterator(&iter);
205 while ((pid = read_next_process(&iter))) {
206 //check if process belongs to the family
208 //TODO: optimize (add also parents)
209 while(ppid!=1 && ppid!=father) {
210 ppid = getppid_of(ppid);
212 //allocate and insert the process
213 struct process *p = malloc(sizeof(struct process));
215 p->starttime = get_starttime(pid);
219 else if (pid != getpid()) {
220 //add to members (only if it's not the current cpulimit process!)
222 add_elem(&(f->members), p);
225 p->history = malloc(sizeof(struct process_history));
226 process_init(p->history, pid);
233 // checks if there are new processes born in the specified family
234 // if any they are added to the members list
235 // the number of new born processes is returned
236 int check_new_members(struct process_family *f)
240 struct process_iterator iter;
241 init_process_iterator(&iter);
243 while ((pid = read_next_process(&iter))) {
244 struct process *newp = find_process(f, pid);
245 if (newp != NULL) continue; //already known
246 //the process is new, check if it belongs to the family
247 int ppid = getppid_of(pid);
248 //search the youngest known ancestor of the process
249 struct process *ancestor = NULL;
250 while((ancestor=find_process(f, ppid))==NULL) {
251 ppid = getppid_of(ppid);
253 if (ancestor == NULL) {
254 //this should never happen! if does, find and correct the bug
255 printf("Fatal bug! Process %d is without parent\n", pid);
258 //allocate and insert the process
259 struct process *p = malloc(sizeof(struct process));
261 p->starttime = get_starttime(pid);
263 if (ancestor->member) {
266 add_elem(&(f->members), p);
270 p->history = malloc(sizeof(struct process_history));
271 process_init(p->history, pid);
278 // removes a process from the family by its pid
279 void remove_process_from_family(struct process_family *f, int pid)
281 struct list_node *node = locate_node(&(f->members), &pid);
283 struct process *p = (struct process*)(node->data);
286 destroy_node(&(f->members), node);
288 unhash_process(f, pid);
291 // free the heap memory used by a process family
292 void cleanup_process_family(struct process_family *f)
295 int size = sizeof(f->hashtable) / sizeof(struct process*);
296 for (i=0; i<size; i++) {
297 if (f->hashtable[i] != NULL) {
298 //free() history for each process
299 struct list_node *node = NULL;
300 for (node=f->hashtable[i]->first; node!=NULL; node=node->next) {
301 struct process *p = (struct process*)(node->data);
305 destroy_list(f->hashtable[i]);
306 free(f->hashtable[i]);
307 f->hashtable[i] = NULL;
310 flush_list(&(f->members));
315 // look for a process by pid
316 // search_pid : pid of the wanted process
317 // return: pid of the found process, if it is found
318 // 0, if it's not found
319 // negative pid, if it is found but it's not possible to control it
320 int look_for_process_by_pid(int pid)
322 if (process_exists(pid))
323 return (kill(pid,SIGCONT)==0) ? pid : -pid;
327 // look for a process with a given name
328 // process: the name of the wanted process. it can be an absolute path name to the executable file
329 // or just the file name
330 // return: pid of the found process, if it is found
331 // 0, if it's not found
332 // negative pid, if it is found but it's not possible to control it
333 int look_for_process_by_name(const char *process)
335 //the name of /proc/pid/exe symbolic link pointing to the executable file
337 //the name of the executable file
338 char exepath[PATH_MAX+1];
339 //whether the variable process is the absolute path or not
340 int is_absolute_path = process[0] == '/';
341 //flag indicating if the a process with given name was found
345 struct process_iterator iter;
346 init_process_iterator(&iter);
348 while ((pid = read_next_process(&iter))) {
349 //read the executable link
350 sprintf(exelink,"/proc/%d/exe",pid);
351 int size = readlink(exelink, exepath, sizeof(exepath));
354 if (is_absolute_path && strncmp(exepath, process, size)==0 && size==strlen(process)) {
360 if (strncmp(exepath + size - strlen(process), process, strlen(process))==0) {
365 if (kill(pid,SIGCONT)==0) {
370 //we don't have permission to send signal to that process
371 //so, don't exit from the loop and look for another one with the same name
378 //ok, the process was found
381 else if (found == 0) {
385 else if (found == -1) {
386 //the process was found, but we haven't permission to control it
389 //this MUST NOT happen