Tizen 2.1 base
[platform/upstream/gcd.git] / pthread_workqueue-0.8.2 / src / posix / thread_info.c
1 /*
2  * Copyright (c) 2011, Joakim Johansson <jocke@tbricks.com>
3  *
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice unmodified, this list of conditions, and the following
11  *    disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  *
27  */
28
29 #include "platform.h"
30 #include "private.h"
31
32 #if defined(__sun)
33
34 #include <stdio.h>
35 #include <procfs.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <sys/syscall.h>
39 #include <fcntl.h>
40
41 /* 
42  
43  /proc for Solaris
44  
45  STRUCTURE OF /proc/pid
46  A given directory /proc/pid contains the following  entries.
47  A  process  can  use  the  invisible  alias /proc/self if it
48  wishes to open one of its own /proc files (invisible in  the
49  sense  that the name ``self'' does not appear in a directory
50  listing  of  /proc  obtained  from  ls(1),  getdents(2),  or
51  readdir(3C)).
52 ...
53  lstatus
54  Contains a  prheader  structure  followed  by  an  array  of
55  lwpstatus structures, one for each active lwp in the process
56  (see   also   /proc/pid/lwp/lwpid/lwpstatus,   below).   The
57  prheader  structure  describes  the  number  and size of the
58  array entries that follow.
59  
60  typedef struct prheader {
61  long pr_nent;        // number of entries 
62  size_t pr_entsize;   // size of each entry, in bytes 
63  } prheader_t;
64
65  The lwpstatus structure may grow by the addition of elements
66  at  the  end in future releases of the system. Programs must
67  use pr_entsize in the  file  header  to  index  through  the
68  array.  These comments apply to all /proc files that include
69  a prheader structure (lpsinfo and lusage, below).
70  
71  /proc/self/lstatus
72  */
73
74 int threads_runnable(unsigned int *threads_running)
75 {
76     const char *path = "/proc/self/lstatus";
77         int read_fd, retval = -1, i;
78     unsigned int running_count = 0;
79     char *lwp_buffer;
80     ssize_t actual_read;
81     lwpstatus_t *lwpstatus;
82     prheader_t prheader;
83             
84     read_fd = open(path, O_RDONLY);
85         if (read_fd == -1) 
86     {
87         dbg_perror("open()");
88         return retval;
89         }
90
91         if (fcntl(read_fd, F_SETFL, O_NONBLOCK) != 0) 
92     {
93         dbg_perror("fcntl()");
94         goto errout;
95         }
96
97     actual_read = read(read_fd, &prheader, sizeof(prheader_t));
98
99     if (actual_read != sizeof(prheader_t))
100     {
101         dbg_printf("read returned wrong number of bytes - %ld instead of %ld", actual_read, sizeof(prheader_t));
102         goto errout;
103     }
104
105     dbg_printf("read prheader, pr_nent = %ld, pr_entsize = %ld, sizeof(lwpstatus_t) = %ld",prheader.pr_nent, prheader.pr_entsize, sizeof(lwpstatus_t));
106
107     lwp_buffer = malloc(prheader.pr_nent * prheader.pr_entsize);
108
109     if (!lwp_buffer)
110     {
111         dbg_perror("malloc(prheader.pr_nent * prheader.pr_entsize)");
112         goto errout;
113     }
114
115     actual_read = read(read_fd, lwp_buffer, (prheader.pr_nent * prheader.pr_entsize));
116
117     if (actual_read != (prheader.pr_nent * prheader.pr_entsize))
118     {
119         dbg_printf("read returned wrong number of bytes - %ld instead of %ld", actual_read, prheader.pr_nent * prheader.pr_entsize);
120         free(lwp_buffer);
121         goto errout;
122     }
123
124     for (i = 0; i < prheader.pr_nent; i++)
125     {
126         lwpstatus = (lwpstatus_t *) (lwp_buffer + (i * prheader.pr_entsize));
127         dbg_printf("lwp %d, syscall = %d", lwpstatus->pr_lwpid, lwpstatus->pr_syscall);
128         
129         if (lwpstatus->pr_flags & PR_ASLEEP)
130         {            
131             dbg_printf("lwp %d is sleeping",lwpstatus->pr_lwpid);
132         }   
133         else
134         {
135             running_count++;
136             dbg_printf("lwp %d is running",lwpstatus->pr_lwpid);
137         }        
138     }
139
140     free(lwp_buffer);
141     retval = 0;
142     *threads_running = running_count;
143     
144 errout:
145     if (close(read_fd) != 0)
146     {
147         dbg_perror("close()");
148     }
149     
150     return retval;
151 }
152
153 #elif defined(__linux__)
154
155 /* 
156  
157  /proc for Linux
158  
159  /proc/self
160  This directory refers to the process accessing the /proc filesystem, and is identical to the /proc directory named by the process ID of the same process.
161  
162  ÑÑÑÑÑÑÑ
163  
164  /proc/[number]/stat
165  Status information about the process. This is used by ps(1). It is defined in /usr/src/linux/fs/proc/array.c.
166  The fields, in order, with their proper scanf(3) format specifiers, are:
167  
168  pid %d
169  The process ID.
170  
171  comm %s
172  The filename of the executable, in parentheses. This is visible whether or not the executable is swapped out.
173  
174  state %c
175  One character from the string "RSDZTW" where R is running, S is sleeping in an interruptible wait, D is waiting in uninterruptible disk sleep, Z is zombie, T is traced or stopped (on a signal), and W is paging.
176  
177  ---------------
178  
179  /proc/[number]/task (since kernel 2.6.0-test6)
180  This is a directory that contains one subdirectory for each thread in the process. The name of each subdirectory is the numerical thread ID of the thread (see gettid(2)). Within each of these subdirectories, there is a set of files with the same names and contents as under the /proc/[number] directories. For attributes that are shared by all threads, the contents for each of the files under the task/[thread-ID] subdirectories will be the same as in the corresponding file in the parent /proc/[number] directory (e.g., in a multithreaded process, all of the task/[thread-ID]/cwd files will have the same value as the /proc/[number]/cwd file in the parent directory, since all of the threads in a process share a working directory). For attributes that are distinct for each thread, the corresponding files under task/[thread-ID] may have different values (e.g., various fields in each of the task/[thread-ID]/status files may be different for each thread).
181  In a multithreaded process, the contents of the /proc/[number]/task directory are not available if the main thread has already terminated (typically by calling pthread_exit(3)).
182  
183  ---------------
184
185  Example:
186  read data from /proc/self/task/11019/stat: [11019 (lt-dispatch_sta) D 20832 10978 20832 34819 10978 4202560 251 3489 0 0 0 2 2 5 20 0 37 0 138715543 2538807296 13818 18446744073709551615 4194304 4203988 140736876632592 139770298610200 139771956665732 0 0 0 0 0 0 0 -1 2 0 0 0 0 0
187
188 */
189
190 #include <stdio.h>
191 #include <sys/types.h>
192 #include <dirent.h>
193 #include <errno.h>
194 #include <fcntl.h>
195
196 #define MAX_RESULT_SIZE 4096
197
198 static int _read_file(const char *path, char *result)
199 {
200         int read_fd, retval = -1;
201     ssize_t actual_read;
202     
203     read_fd = open(path, O_RDONLY);
204         if (read_fd == -1) 
205     {
206         dbg_perror("open()");
207         return retval;
208         }
209     
210         if (fcntl(read_fd, F_SETFL, O_NONBLOCK) != 0) 
211     {
212         dbg_perror("fcntl()");
213         goto errout;
214         }
215         
216
217     actual_read = read(read_fd, result, MAX_RESULT_SIZE);
218         
219 # ifdef __ia64__
220     dbg_printf("read %ld from %s", actual_read, path);
221 # else
222     dbg_printf("read %zd from %s", actual_read, path);
223 #endif
224
225     if (actual_read == 0)
226     {
227         goto errout;
228     }
229     
230     retval = 0;
231     
232 errout:
233     if (close(read_fd) != 0)
234     {
235         dbg_perror("close()");
236     }
237     
238     return retval;
239 }
240
241
242 int threads_runnable(unsigned int *threads_running)
243 {
244     DIR             *dip;
245     struct dirent   *dit;
246     const char *task_path = "/proc/self/task";
247     char thread_path[1024];
248     char thread_data[MAX_RESULT_SIZE+1];
249     char dummy[MAX_RESULT_SIZE+1];
250     char state;
251     int pid;
252     unsigned int running_count = 0;
253
254     dbg_puts("Checking threads_runnable()");
255
256     if ((dip = opendir(task_path)) == NULL)
257     {
258         dbg_perror("opendir");
259         return -1;
260     }
261         
262     while ((dit = readdir(dip)) != NULL)
263     {
264         memset(thread_data, 0, sizeof(thread_data));
265         
266         sprintf(thread_path, "%s/%s/stat",task_path, dit->d_name);
267
268         if (_read_file(thread_path, thread_data) == 0)
269         {
270             if (sscanf(thread_data, "%d %s %c", &pid, dummy, &state) == 3)
271             {
272                 dbg_printf("The state for thread %s is %c", dit->d_name, state);
273                 switch (state)
274                 {
275                     case 'R':
276                         running_count++;
277                         break;
278                     default:
279                         break;
280                 }
281             }
282             else
283             {
284                 dbg_printf("Failed to scan state for thread %s (%s)", dit->d_name, thread_data);
285             }
286         }
287     }
288
289     if (closedir(dip) == -1)
290     {
291         perror("closedir");
292     }
293
294     dbg_printf("Running count is %d", running_count);
295     *threads_running = running_count;
296     
297     return 0;
298 }
299
300 #else
301
302 int threads_runnable(unsigned int *threads_running)
303 {
304     return -1;
305 }
306
307 #endif