blob: d398341973c709d50e728ac3b3c90225c80713cf [file] [log] [blame]
#define NOPLAN9DEFINES
#include <u.h>
#include <libc.h>
#include <thread.h>
#include "threadimpl.h"
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
void
fdwait()
{
fd_set rfd, wfd, efd;
FD_ZERO(&rfd);
FD_ZERO(&wfd);
FD_ZERO(&efd);
if(mode=='w')
FD_SET(&wfd, fd);
else
FD_SET(&rfd, fd);
FD_SET(&efd, fd);
select(fd+1, &rfd, &wfd, &efd, nil);
}
void
threadfdwaitsetup(void)
{
}
void
_threadfdwait(int fd, int rw, ulong pc)
{
int i;
struct {
Channel c;
ulong x;
Alt *qentry[2];
} s;
threadfdwaitsetup();
chaninit(&s.c, sizeof(ulong), 1);
s.c.qentry = (volatile Alt**)s.qentry;
s.c.nentry = 2;
memset(s.qentry, 0, sizeof s.qentry);
for(i=0; i<npoll; i++)
if(pfd[i].fd == -1)
break;
if(i==npoll){
if(npoll >= nelem(polls)){
fprint(2, "Too many polled fds.\n");
abort();
}
npoll++;
}
pfd[i].fd = fd;
pfd[i].events = rw=='r' ? POLLIN : POLLOUT;
polls[i].c = &s.c;
if(0) fprint(2, "%s [%3d] fdwait %d %c list *0x%lux\n",
argv0, threadid(), fd, rw, pc);
if(pollpid)
postnote(PNPROC, pollpid, "interrupt");
recvul(&s.c);
}
void
threadfdwait(int fd, int rw)
{
_threadfdwait(fd, rw, getcallerpc(&fd));
}
void
threadsleep(int ms)
{
struct {
Channel c;
ulong x;
Alt *qentry[2];
} s;
threadfdwaitsetup();
chaninit(&s.c, sizeof(ulong), 1);
s.c.qentry = (volatile Alt**)s.qentry;
s.c.nentry = 2;
memset(s.qentry, 0, sizeof s.qentry);
sleepchan[nsleep] = &s.c;
sleeptime[nsleep++] = p9nsec()/1000000+ms;
recvul(&s.c);
}
void
threadfdnoblock(int fd)
{
fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0)|O_NONBLOCK);
}
long
threadread(int fd, void *a, long n)
{
int nn;
threadfdnoblock(fd);
again:
/*
* Always call wait (i.e. don't optimistically try the read)
* so that the scheduler gets a chance to run other threads.
*/
_threadfdwait(fd, 'r', getcallerpc(&fd));
errno = 0;
nn = read(fd, a, n);
if(nn <= 0){
if(errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
goto again;
}
return nn;
}
int
threadrecvfd(int fd)
{
int nn;
threadfdnoblock(fd);
again:
/*
* Always call wait (i.e. don't optimistically try the recvfd)
* so that the scheduler gets a chance to run other threads.
*/
_threadfdwait(fd, 'r', getcallerpc(&fd));
nn = recvfd(fd);
if(nn < 0){
if(errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
goto again;
}
return nn;
}
int
threadsendfd(int fd, int sfd)
{
int nn;
threadfdnoblock(fd);
again:
/*
* Always call wait (i.e. don't optimistically try the sendfd)
* so that the scheduler gets a chance to run other threads.
*/
_threadfdwait(fd, 'w', getcallerpc(&fd));
nn = sendfd(fd, sfd);
if(nn < 0){
if(errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
goto again;
}
return nn;
}
long
threadreadn(int fd, void *a, long n)
{
int tot, nn;
for(tot = 0; tot<n; tot+=nn){
nn = threadread(fd, (char*)a+tot, n-tot);
if(nn <= 0){
if(tot == 0)
return nn;
return tot;
}
}
return tot;
}
long
_threadwrite(int fd, const void *a, long n)
{
int nn;
threadfdnoblock(fd);
again:
/*
* Always call wait (i.e. don't optimistically try the write)
* so that the scheduler gets a chance to run other threads.
*/
_threadfdwait(fd, 'w', getcallerpc(&fd));
nn = write(fd, a, n);
if(nn < 0){
if(errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
goto again;
}
return nn;
}
long
threadwrite(int fd, const void *a, long n)
{
int tot, nn;
for(tot = 0; tot<n; tot+=nn){
nn = _threadwrite(fd, (char*)a+tot, n-tot);
if(nn <= 0){
if(tot == 0)
return nn;
return tot;
}
}
return tot;
}
int
threadannounce(char *addr, char *dir)
{
return p9announce(addr, dir);
}
int
threadlisten(char *dir, char *newdir)
{
int fd, ret;
extern int _p9netfd(char*);
fd = _p9netfd(dir);
if(fd < 0){
werrstr("bad 'directory' in listen: %s", dir);
return -1;
}
threadfdnoblock(fd);
while((ret = p9listen(dir, newdir)) < 0 && errno==EAGAIN)
_threadfdwait(fd, 'r', getcallerpc(&dir));
return ret;
}
int
threadaccept(int cfd, char *dir)
{
return p9accept(cfd, dir);
}