[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

MINTOS: Porting Library !?



Micheal Hohmuth writes:

> Rather, we should concentrate on things that have to be generalized
> in order to reach a state where Unix software con be compiled out of
> the box.

Yes, I would love that state, too. But obviously there are some problems,
which cannot be solved transparently in the library without changing the
MiNT kernel. Probably everyone who ever ported unix software to MiNT came
across those things.

I think we should try to find general solutions for those problems which
require only minimal changes to the source code (ie no mayor rewrites).
Any other opinions, I think not :-).

So I'm going to start a list of what I call 'elegant solutions' to some
of the above problems. Probably there are lots of such 'workarounds' out
there. It would be great to have a look at and collect them.
Perhaps we could even build a nonstandart library containing useful code
for porting unix software.

Here are my suggestions:

(1)	Mint's fork() blocks the parent until the child exec()'s or
	exit()'s. This is a problem in constructs like:

		if (!fork()) exit();

	Here is a workaround, which uses tfork() and requires only
	minimal changes to the source. Using tfork() directly often
	requires restructuring of the source.

------------------------ cut ----------------------------
#include <unistd.h>
#include <fcntl.h>
#include <ioctl.h>
#include <setjmp.h>
#include <signal.h>

static int fd_flags[32];
static jmp_buf jmpbuf;
static long sigmask;
static struct sigaction sigacts[32];

int
child_proc (long pip)
{
	char buf;
	int i;

	sigsetmask (~0L);
	if (read (pip, &buf, 1)) exit (0);
	close (pip);
	for (i = 0; i < 32; ++i) {
		if (fd_flags[i] >= 0)
			fcntl (i, F_SETFD, fd_flags[i]);
	}
	for (i = 0; i < 32; ++i) {
		sigaction (i, &sigacts[i], 0);
	}
	longjmp (jmpbuf, 1);
}
	
int
__fork_and_exit (void)
{
	int i, pip[2];

	sigmask = sigsetmask (~0L);
	if (pipe (pip) < 0) return -1;
	for (i = 0; i < 32; ++i) {
		fd_flags[i] = fcntl (i, F_GETFD, 0);
		fcntl (i, F_SETFD, i == pip[1] ? FD_CLOEXEC : 0);
	}
	for (i = 0; i < 32; ++i) {
		sigaction (i, 0, &sigacts[i]);
	}
	if (!setjmp (jmpbuf)) {
		/* parent */
		tfork (child_proc, pip[0]);
		exit (0);
	}
	/* child */
	sigsetmask (sigmask);
	return 0;
}
--------------------------- cut ----------------------------

	__fork_and_exit() preserves file handles, signal handlers
	and the set of masked signals to the child, much like fork()
	does.
	Its functionlity is the same as for if (!fork()) exit().
	
(2)	Another problem is that Mint/MintLibs read()/write() have
	no POSIX nonblocking mode (activated with the O_NONBLOCK
	fcntl()) flags. The difference to O_NDELAY nonblocking mode
	is that read()/write() return -1 and EWOULDBLOCK/EAGAIN in
	errno if no data/space is available at all (instead of
	returning 0 when O_NDELAY is actice).
	I know Entropy worked on this, but in the MintLibs this stuff
	is commented out.
	My solution is probably not more than a hack. Improvements
	are appreciated.

-------------------------- cut -------------------------------
#include <fcntl.h>
#include <errno.h>
#include <ioctl.h>
#include <osbind.h>
#include <mintbind.h>

#define UNLIMITED	1000000000L

int
__posixish_read (int fd, void *buffer, unsigned int buflen)
{
	int r, s;
	unsigned long buf;
	extern int errno;

	r = Fread (fd, buflen, buffer);
	if (r <= 0) {
		if (r < 0) {
			errno = -r;
			return -1;
		}
		if (buflen && Fcntl (fd, 0, F_GETFL) & O_NDELAY) {
			s = Fcntl (fd, &buf, FIONREAD);
			if (!s && buf < UNLIMITED) {
				errno = EWOULDBLOCK;
				return -1;
			}
		}
	}
	return r;
}

int
__posixish_write (int fd, void *buffer, unsigned int buflen)
{
	int r, s;
	unsigned long buf;
	extern int errno;

	r = Fwrite (fd, buflen, buffer);
	if (r <= 0) {
		if (r < 0) {
			errno = -r;
			return -1;
		}
		if (buflen && Fcntl (fd, 0, F_GETFL) & O_NDELAY) {
			s = Fcntl (fd, &buf, FIONWRITE);
			if (!s && buf < UNLIMITED) {
				errno = EWOULDBLOCK;
				return -1;
			}
		}
	}
	return r;
}

------------------------- cut -----------------------------------

	When only O_NONBLOCK nonblocking mode is used, you could
	then
	#define read(a,b,c)	__posixish_read(a,b,c)
	#define write(a,b,c)	__posixish_write(a,b,c)
	#define O_NONBLOCK	O_NDELAY
	and use this as a reasonabe emulation.
	
(3)	select()ing for exceptional conditions does not work.
	This is a pitty for sockets (TCP) and out of band data.
	Perhaps we could do a workaround using SIGURG.
	Any suggestions?

Waiting for your opinion and suggestions,
Kay.