Chet Ramey wrote:
Linda Walsh wrote:
When under linux (2.6.30.x), I type
ulimit -p and get a return value of "8".
from the man page this is in 512-byte blocks and may not be set.
It's set at build time. Look at builtins/ulimit.def:pipesize() and
builtins/psize.sh (which uses builtins/psize.c).
Chet
----
What is supposed to be controlling?
When I create a pipe with the pipe system call, and try writing
blocks of data from a master(parent) to a child, I get very large values for
bytes sent in one write or read in one read from the pipe.
More like it's a limitation on some physical memory constraint.
When I think of a pipe size for reads/writes, I am thinking creating
a pipe with the system call 'pipe', and optionally using the dup2 operation
to connect one processes writes to stdout to another processes stdin -- but
they still both are talking to a plain unix pipe, no?
The first limit I hit is on a read or write of a 2GB block
(the write returns about 4K short of writing 2GB, and the child receives
the same block of len 2GB-4K).
That's alot more than 8 512-Byte blocks.
Test program is attached (to compile you'd need
to pass "-lrt" to gcc as it uses the real-time clock to time the writes).
#define __USE_LARGEFILE64 1
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <strings.h>
#include <time.h>
#define PAR_WAIT_TO_HUP 3
int pipefd[2];
int controlfd[2];
int pid;
void getout(int stat, char * msg) {
char errmsg[128];
char *id;
id=(pid>0)?"parent":" child";
snprintf(errmsg, sizeof(errmsg), "%s: %s", id, msg);
perror(errmsg);
if (pid>0) {
close(pipefd[1]);
close(controlfd[0]);
sleep(PAR_WAIT_TO_HUP);
kill(pid, 1); /* SIGHUP */
} else {
close(pipefd[0]);
close(controlfd[1]);
}
exit(stat);
}
void sighandler() {
char errmsg[128];
char *id;
id=(pid>0)?"parent":" child";
snprintf(errmsg, sizeof(errmsg), "%s: %s", id,
"SIGPIPE: We are talking, but nobody's listening!\n");
getout(8, "pipe write");
}
typedef struct timespec * timeval;
timeval get_elapsed(timeval elapsed, timeval start, timeval end) {
int borrow=0;
double result;
if (start->tv_nsec >end->tv_nsec) {
end->tv_nsec += 1000*1000*1000;
borrow=1;
}
elapsed->tv_nsec = end->tv_nsec - start->tv_nsec;
if (borrow) --end->tv_sec;
elapsed->tv_sec = end->tv_sec - start->tv_sec;
return elapsed;
}
char * ht (char *buff, int bufflen, timeval tv) {
bzero(buff, bufflen);
/* if time sex and nsecs both equal 0 return zero */
if (tv->tv_sec==0 && tv->tv_nsec==0) {
snprintf(buff, bufflen, "0.0 seconds");
return buff;
}
/* if < 1 sec, display fraction in nano, micro or milli- seconds */
if (tv->tv_sec==0 && tv->tv_nsec!=0) {
char * unit;
int nanos=tv->tv_nsec;
if (nanos<1000) {
unit="ns";
} else if (nanos < 1000000 && nanos>=1000) {
nanos/=1000;
unit="µs";
} else {
nanos/=1000000;
unit="ms";
}
snprintf(buff, bufflen, "%d%s", nanos, unit);
} else if (tv->tv_sec > 0) {
double t = ((double) tv->tv_sec) + ((double)
tv->tv_nsec)/(double)1000000000.0;
snprintf(buff, bufflen, "%-5.3lf seconds", t);
}
return buff;
}
typedef const char * String;
static const String suffixes [] = {"B", "KB", "MB", "GB", "TB"};
static const int num_suffixes = sizeof(suffixes)/sizeof(String);
char * h (char *buff, int bufflen, unsigned long nb) {
int si=0;
int index_of_last_suffix = num_suffixes-1;
bzero(buff, bufflen);
for (si=0; si<index_of_last_suffix && nb>1023 && (nb % 1024)==0; ++si) {
nb >>= 10;
}
snprintf(buff, bufflen, "%d%s", nb, suffixes[si]);
return buff;
}
child_pipe_reader() {
unsigned long buffsize; /* units of 1K */
unsigned long bytes_read;
char * cbuff;
/* child reader */
close(pipefd[1]);
close(controlfd[0]);
while (1) {
char lbuff[20];
char fbuff[20];
struct timespec start, end, elapsed;
double secs;
bytes_read=read(pipefd[0], &buffsize, sizeof(buffsize));
if (bytes_read <0 ) {
getout(14, "reading size of buffer from parent");
}
if (bytes_read != sizeof(buffsize)) {
getout(15, "wrong number of bytes read for
sizeof(buffsize)");
}
cbuff = malloc(buffsize*1024);
if ((long int) cbuff <0) {
getout(13, "child malloc");
}
printf(" child: reading %s from parent\n",
h(lbuff, sizeof(lbuff), buffsize*1024));
if (clock_gettime(CLOCK_REALTIME, &start)<0) {
perror(" child: clock_gettime start");
exit(18);
}
bytes_read=read(pipefd[0], cbuff, buffsize*1024);
if (clock_gettime(CLOCK_REALTIME, &end)<0) {
perror(" child: clock_gettime end");
exit(19);
}
get_elapsed(&elapsed, &start, &end);
free(cbuff);
if (bytes_read <0 ) {
getout(16, "reading from parent");
}
if (bytes_read != buffsize*1024) {
char errmsg[128];
char lbuff1[20];
char lbuff2[20];
snprintf(errmsg, sizeof(errmsg),
"read of %s only returned %s. Exiting\n",
h(lbuff1, sizeof(lbuff1), buffsize*1024),
h(lbuff2, sizeof(lbuff2), bytes_read)
);
getout(17, errmsg);
}
printf(" child: successfully read %s from parent\n",
h(lbuff, sizeof(lbuff), buffsize*1024));
write(controlfd[1], &bytes_read, sizeof(bytes_read) );
}
}
parent_pipe_writer() {
unsigned long buffsize=1; /* units of 1K */
unsigned long bytes_written;
char * pbuff;
close(pipefd[0]);
close(controlfd[1]);
/* parent writer */
while (1) {
char lbuff[20];
char fbuff[20];
int child_read_bytes;
struct timespec start, end, elapsed;
double secs;
/* first try to allocate buffer to write from */
pbuff = malloc(buffsize*1024);
if ((long int) pbuff <0) { /* die if can't alloc */
getout(3, "malloc");
}
/* write size of buffer to child */
bytes_written=write(pipefd[1], &buffsize, sizeof(buffsize));
if (bytes_written <0 ) {
free(pbuff);
getout(4, "writing size of buffer to child");
}
if (bytes_written != sizeof(buffsize)) { /* would be bad
if
couldn't write size */
free(pbuff);
getout(5,
"wrong number of bytes written for
sizeof(buffsize)");
}
printf("parent: writing %s to child\n",
h(lbuff, sizeof(lbuff), buffsize*1024));
if (clock_gettime(CLOCK_REALTIME, &start)<0) {
perror("parent: clock_gettime start");
exit(9);
}
bytes_written=write(pipefd[1], pbuff, buffsize*1024);
if (clock_gettime(CLOCK_REALTIME, &end)<0) {
perror("parent: clock_gettime end");
exit(10);
}
get_elapsed(&elapsed, &start, &end);
free(pbuff);
if (bytes_written <0 ) {
getout(6, "writing buff to child");
}
if (bytes_written != buffsize*1024) {
char errmsg[128];
char lbuff1[20],lbuff2[20];
snprintf(errmsg, sizeof(errmsg),
"write of %s only wrote %s. Exiting\n",
h(lbuff1, sizeof(lbuff1),
buffsize*1024),
h(lbuff2, sizeof(lbuff2), bytes_written)
);
getout(7, errmsg);
}
printf("parent: successfullly wrote %s to child in %s\n",
h(lbuff, sizeof(lbuff), buffsize*1024),
ht(fbuff, sizeof(fbuff), &elapsed));
buffsize <<=1;
read(controlfd[0], &child_read_bytes, sizeof(child_read_bytes));
}
}
main ()
{
/* only 1 instance of parent writer and child reader in this
* test case, so only 1 pair of pipe descriptors */
if (pipe(pipefd)<0) {
perror("pipefd pipe");
exit(1);
}
if (pipe(controlfd)<0) {
perror("controlfd pipe");
exit(1);
}
signal(SIGPIPE, sighandler);
pid=fork();
if (pid<0) {
perror("fork");
exit(2);
}
/* no lvalue as neither sub should return */
pid ? parent_pipe_writer(): child_pipe_reader();
perror("FATAL: unexpected return from proc");
exit(-1);
}
/* vim:ts=4:sw=4
*/