Cygwin: sched_setscheduler: allow changes of the priority
[newlib-cygwin.git] / winsup / cygwin / gmon.c
blob8b1c449c4e4e71ff5e82e6aa7e19f8a51b221296
1 /*-
2 * Copyright (c) 1983, 1992, 1993
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 4. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
30 #if !defined(lint) && defined(LIBC_SCCS)
31 static char rcsid[] = "$OpenBSD: gmon.c,v 1.8 1997/07/23 21:11:27 kstailey Exp $";
32 #endif
35 * This file is taken from Cygwin distribution. Please keep it in sync.
36 * The differences should be within __MINGW32__ guard.
39 #include <fcntl.h>
40 #include <stdlib.h>
41 #include <stdio.h>
42 #ifndef __MINGW32__
43 #include <unistd.h>
44 #include <sys/param.h>
45 #endif
46 #include <sys/types.h>
47 #include "gmon.h"
48 #include "profil.h"
50 /* XXX needed? */
51 //extern char *minbrk __asm ("minbrk");
53 #ifdef _WIN64
54 #define MINUS_ONE_P (-1LL)
55 #else
56 #define MINUS_ONE_P (-1)
57 #endif
59 #include <string.h>
60 #define bzero(ptr,size) memset (ptr, 0, size);
62 struct gmonparam _gmonparam = { GMON_PROF_OFF, NULL, 0, NULL, 0, NULL, 0, 0L,
63 0, 0, 0, 0};
65 static int s_scale;
66 /* see profil(2) where this is describe (incorrectly) */
67 #define SCALE_1_TO_1 0x10000L
69 #define ERR(s) write(2, s, sizeof(s))
71 void moncontrol __P((int));
73 static void *
74 fake_sbrk(int size)
76 void *rv = malloc(size);
77 if (rv)
78 return rv;
79 else
80 return (void *) MINUS_ONE_P;
83 void monstartup (size_t, size_t);
85 void
86 monstartup (size_t lowpc, size_t highpc)
88 register size_t o;
89 char *cp;
90 struct gmonparam *p = &_gmonparam;
93 * round lowpc and highpc to multiples of the density we're using
94 * so the rest of the scaling (here and in gprof) stays in ints.
96 p->lowpc = ROUNDDOWN(lowpc, HISTFRACTION * sizeof(HISTCOUNTER));
97 p->highpc = ROUNDUP(highpc, HISTFRACTION * sizeof(HISTCOUNTER));
98 p->textsize = p->highpc - p->lowpc;
99 p->kcountsize = p->textsize / HISTFRACTION;
100 p->hashfraction = HASHFRACTION;
101 p->fromssize = p->textsize / p->hashfraction;
102 p->tolimit = p->textsize * ARCDENSITY / 100;
103 if (p->tolimit < MINARCS)
104 p->tolimit = MINARCS;
105 else if (p->tolimit > MAXARCS)
106 p->tolimit = MAXARCS;
107 p->tossize = p->tolimit * sizeof(struct tostruct);
109 cp = fake_sbrk(p->kcountsize + p->fromssize + p->tossize);
110 if (cp == (char *)MINUS_ONE_P) {
111 ERR("monstartup: out of memory\n");
112 return;
115 /* zero out cp as value will be added there */
116 bzero(cp, p->kcountsize + p->fromssize + p->tossize);
118 p->tos = (struct tostruct *)cp;
119 cp += p->tossize;
120 p->kcount = (u_int16_t *)cp;
121 cp += p->kcountsize;
122 p->froms = (u_int16_t *)cp;
124 /* XXX minbrk needed? */
125 //minbrk = fake_sbrk(0);
126 p->tos[0].link = 0;
128 o = p->highpc - p->lowpc;
129 if (p->kcountsize < o) {
130 #ifndef notdef
131 s_scale = ((float)p->kcountsize / o ) * SCALE_1_TO_1;
132 #else /* avoid floating point */
133 int quot = o / p->kcountsize;
135 if (quot >= 0x10000)
136 s_scale = 1;
137 else if (quot >= 0x100)
138 s_scale = 0x10000 / quot;
139 else if (o >= 0x800000)
140 s_scale = 0x1000000 / (o / (p->kcountsize >> 8));
141 else
142 s_scale = 0x1000000 / ((o << 8) / p->kcountsize);
143 #endif
144 } else
145 s_scale = SCALE_1_TO_1;
147 moncontrol(1);
150 void _mcleanup (void);
151 void
152 _mcleanup(void)
154 int fd;
155 int hz;
156 int fromindex;
157 int endfrom;
158 size_t frompc;
159 int toindex;
160 struct rawarc rawarc;
161 struct gmonparam *p = &_gmonparam;
162 struct gmonhdr gmonhdr, *hdr;
163 char *filename = (char *) "gmon.out";
164 char *prefix;
165 #ifdef DEBUG
166 int log, len;
167 char dbuf[200];
168 #endif
170 if (p->state == GMON_PROF_ERROR)
171 ERR("_mcleanup: tos overflow\n");
173 hz = PROF_HZ;
174 moncontrol(0);
176 /* We copy an undocumented glibc feature: customizing the profiler's
177 output file name somewhat, depending on the env var GMON_OUT_PREFIX.
178 if GMON_OUT_PREFIX is unspecified, the file's name is "gmon.out".
180 if GMON_OUT_PREFIX is specified with at least one character, the
181 file's name is computed as "$GMON_OUT_PREFIX.$pid".
183 if GMON_OUT_PREFIX is specified but contains no characters, the
184 file's name is computed as "gmon.out.$pid". Cygwin-specific.
186 if ((prefix = getenv("GMON_OUT_PREFIX")) != NULL) {
187 char *buf;
188 /* Covers positive pid_t values. */
189 int32_t divisor = 1000*1000*1000;
190 pid_t pid = getpid();
191 size_t len = strlen(prefix);
193 if (len == 0)
194 len = strlen(prefix = filename);
195 buf = alloca(len + 13);// allow for '.', 10-digit pid, NUL, +1
197 memcpy(buf, prefix, len);
198 buf[len++] = '.';
200 while (divisor > pid) // skip leading zeroes
201 divisor /= 10;
202 do { // convert pid to digits and store 'em
203 buf[len++] = (pid / divisor) + '0';
204 pid %= divisor;
205 } while (divisor /= 10);
207 buf[len] = '\0';
208 filename = buf;
211 fd = open(filename, O_CREAT|O_TRUNC|O_WRONLY|O_BINARY, 0666);
212 if (fd < 0) {
213 perror(filename);
214 return;
216 #ifdef DEBUG
217 log = open("gmon.log", O_CREAT|O_TRUNC|O_WRONLY, 0664);
218 if (log < 0) {
219 perror("mcount: gmon.log");
220 return;
222 len = sprintf(dbuf, "[mcleanup1] kcount 0x%x ssiz %d\n",
223 p->kcount, p->kcountsize);
224 write(log, dbuf, len);
225 #endif
226 hdr = (struct gmonhdr *)&gmonhdr;
227 bzero(hdr, sizeof *hdr);
228 hdr->lpc = p->lowpc;
229 hdr->hpc = p->highpc;
230 hdr->ncnt = p->kcountsize + sizeof(gmonhdr);
231 hdr->version = GMONVERSION;
232 hdr->profrate = hz;
233 write(fd, (char *)hdr, sizeof *hdr);
234 write(fd, p->kcount, p->kcountsize);
235 endfrom = p->fromssize / sizeof(*p->froms);
236 for (fromindex = 0; fromindex < endfrom; fromindex++) {
237 if (p->froms[fromindex] == 0)
238 continue;
240 frompc = p->lowpc;
241 frompc += fromindex * p->hashfraction * sizeof(*p->froms);
242 for (toindex = p->froms[fromindex]; toindex != 0;
243 toindex = p->tos[toindex].link) {
244 #ifdef DEBUG
245 len = sprintf(dbuf,
246 "[mcleanup2] frompc 0x%x selfpc 0x%x count %d\n" ,
247 frompc, p->tos[toindex].selfpc,
248 p->tos[toindex].count);
249 write(log, dbuf, len);
250 #endif
251 rawarc.raw_frompc = frompc;
252 rawarc.raw_selfpc = p->tos[toindex].selfpc;
253 rawarc.raw_count = p->tos[toindex].count;
254 write(fd, &rawarc, sizeof rawarc);
257 close(fd);
261 * Control profiling
262 * profiling is what mcount checks to see if
263 * all the data structures are ready.
265 void
266 moncontrol(int mode)
268 struct gmonparam *p = &_gmonparam;
270 if (mode) {
271 /* start */
272 profil((char *)p->kcount, p->kcountsize, p->lowpc,
273 s_scale);
274 p->state = GMON_PROF_ON;
275 } else {
276 /* stop */
277 profil((char *)0, 0, 0, 0);
278 p->state = GMON_PROF_OFF;