This is the mail archive of the cygwin mailing list for the Cygwin project.
| Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
|---|---|---|
| Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |
| Other format: | [Raw text] | |
The subjects says it all: when a process has a large memory space,
a popen() triggers a long disk thrashing. The result can clearly be
seen iwth the allegated cygtharsh program (running with 1GB of memory,
change the size of the malloc to roughly half your memory size):
% ./cygthrash
0.000 Before std
48.318 After std
67.654 Result: Tue Nov 14 11:29:03 2006
67.700 After close std
0.000 Before new
0.720 After new
1.106 Result: Tue Nov 14 11:29:04 2006
1.107 After close new
0.000 Before std
122.989 After std
131.007 Result: Tue Nov 14 11:31:15 2006
131.008 After close std
Namely: 48 seconds for the first popen
19 fgets
123 second popen
8 fgets
The _popen function is a proposition for popen. Namely, I suggest to
change in the popen function the lines:
switch (pid = vfork()) {
case -1: /* Error. */
(void)close(pdes[0]);
(void)close(pdes[1]);
free(cur);
return (NULL);
/* NOTREACHED */
case 0: /* Child. */
if (*type == 'r') {
if (pdes[1] != STDOUT_FILENO) {
(void)dup2(pdes[1], STDOUT_FILENO);
(void)close(pdes[1]);
}
if (pdes[0] != STDOUT_FILENO) {
(void) close(pdes[0]);
}
} else {
if (pdes[0] != STDIN_FILENO) {
(void)dup2(pdes[0], STDIN_FILENO);
(void)close(pdes[0]);
}
(void)close(pdes[1]);
}
execl(_PATH_BSHELL, "sh", "-c", program, NULL);
#ifdef __CYGWIN__
/* On cygwin32, we may not have /bin/sh. In that
case, try to find sh on PATH. */
execlp("sh", "sh", "-c", program, NULL);
#endif
_exit(127);
/* NOTREACHED */
}
to something similar to (warning: untested, needs a char *cmd; at the
beggining):
if (cmd = malloc(strlen(program)+64)) == NULL) {
(void)close(pdes[1]);
(void)close(pdes[2]);
free(cur);
return (NULL);
}
if (*type == 'r') {
if (pdes[1] != STDOUT_FILENO)
sprintf(cmd, "sh -c '%s' >&%d %d>&-", program, pdes[1], pdes[1]);
else
sprintf(cmd, "sh -c '%s'", program);
if (pdes[0] != STDOUT_FILENO)
sprintf(cmd+strlen(cmd), " %d>&-", pdes[0]);
}
else {
if (pdes[0] != STDIN_FILENO)
sprintf(cmd, "sh -c '%s' <&%d %d>&- %d>&-", program,
pdes[0], pdes[0], pdes[1]);
else
sprintf(cmd, "sh -c '%s' %d>&-", program, pdes[1])
}
pid = spawnl(_P_NOWAIT, _PATH_BSHELL, "sh", "-c", cmd, NULL);
With lots of thanks from the community who made that happen,
Loïc#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <time.h>
#include <sys/time.h>
/*******START*******/
#include <process.h>
#include <string.h>
#include <unistd.h>
static int newpid;
static FILE *
_popen(char *cmd, char *mode)
{
int fd[2];
if (!pipe(fd)) {
char *str;
str = malloc(strlen(cmd)+64);
if (*mode == 'r')
sprintf(str, "%s >&%d %d>&-", cmd, fd[1], fd[1]);
else
sprintf(str, "%s <&%d %d>&-", cmd, fd[0], fd[0]);
newpid=spawnlp(_P_NOWAIT, "sh", "sh", "-c", str, NULL);
free(str);
if (*mode == 'r') {
close(fd[1]);
return fdopen(fd[0], "r");
}
else {
close(fd[0]);
return fdopen(fd[1], "w");
}
}
return NULL;
}
/******* END *******/
#define GET(tc) gettimeofday(&tc, NULL); \
if (tc.tv_usec < ts.tv_usec) { \
tc.tv_usec += 1000000; \
tc.tv_sec -= 1; \
} \
tc.tv_sec -= ts.tv_sec; \
tc.tv_usec -= ts.tv_usec
int
main()
{
FILE *f;
char buf[1024];
struct timeval ts, tc;
malloc(1<<29); /* 512 MB */
gettimeofday(&ts, NULL);
printf("%3d.%03d Before std\n", 0, 0);
f = popen("date", "r");
GET(tc);
printf("%3d.%03d After std\n", (int)tc.tv_sec, (int)tc.tv_usec/1000);
fgets(buf, sizeof buf, f);
GET(tc);
printf("%3d.%03d Result: %s", (int)tc.tv_sec, (int)tc.tv_usec/1000, buf);
pclose(f);
GET(tc);
printf("%3d.%03d After close std\n", (int)tc.tv_sec, (int)tc.tv_usec/1000);
gettimeofday(&ts, NULL);
printf("%3d.%03d Before new\n", 0, 0);
f = _popen("date", "r");
GET(tc);
printf("%3d.%03d After new\n", (int)tc.tv_sec, (int)tc.tv_usec/1000);
fgets(buf, sizeof buf, f);
GET(tc);
printf("%3d.%03d Result: %s", (int)tc.tv_sec, (int)tc.tv_usec/1000, buf);
kill(newpid, SIGTERM);
fclose(f);
kill(newpid, SIGKILL);
GET(tc);
printf("%3d.%03d After close new\n", (int)tc.tv_sec, (int)tc.tv_usec/1000);
gettimeofday(&ts, NULL);
printf("%3d.%03d Before std\n", 0, 0);
f = popen("date", "r");
GET(tc);
printf("%3d.%03d After std\n", (int)tc.tv_sec, (int)tc.tv_usec/1000);
fgets(buf, sizeof buf, f);
GET(tc);
printf("%3d.%03d Result: %s", (int)tc.tv_sec, (int)tc.tv_usec/1000, buf);
pclose(f);
GET(tc);
printf("%3d.%03d After close std\n", (int)tc.tv_sec, (int)tc.tv_usec/1000);
exit(0);
}
Attachment:
cygcheck.out
Description: Text document
-- Unsubscribe info: http://cygwin.com/ml/#unsubscribe-simple Problem reports: http://cygwin.com/problems.html Documentation: http://cygwin.com/docs.html FAQ: http://cygwin.com/faq/
| Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
|---|---|---|
| Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |