void
str_cli(FILE *fp, int sockfd)
{
    int				kq, i, n, nev, stdineof = 0, isfile;
    char			buf[MAXLINE];
    struct kevent	kev[2];
    struct timespec	ts;
    struct stat		st;

    isfile = ((fstat(fileno(fp), &st) == 0) &&
              (st.st_mode & S_IFMT) == S_IFREG);

    EV_SET(&kev[0], fileno(fp), EVFILT_READ, EV_ADD, 0, 0, NULL);
    EV_SET(&kev[1], sockfd, EVFILT_READ, EV_ADD, 0, 0, NULL);

    kq = Kqueue();
    ts.tv_sec = ts.tv_nsec = 0;
    Kevent(kq, kev, 2, NULL, 0, &ts);

    for ( ; ; ) {
        nev = Kevent(kq, NULL, 0, kev, 2, NULL);

        for (i = 0; i < nev; i++) {
            if (kev[i].ident == sockfd) {	/* socket is readable */
                if ( (n = Read(sockfd, buf, MAXLINE)) == 0) {
                    if (stdineof == 1)
                        return;		/* normal termination */
                    else
                        err_quit("str_cli: server terminated prematurely");
                }

                Write(fileno(stdout), buf, n);
            }

            if (kev[i].ident == fileno(fp)) {  /* input is readable */
                n = Read(fileno(fp), buf, MAXLINE);
                if (n > 0)
                    Writen(sockfd, buf, n);

                if (n == 0 || (isfile && n == kev[i].data)) {
                    stdineof = 1;
                    Shutdown(sockfd, SHUT_WR);	/* send FIN */
                    kev[i].flags = EV_DELETE;
                    Kevent(kq, &kev[i], 1, NULL, 0, &ts);	/* remove kevent */
                    continue;
                }
            }
        }
    }
}
示例#2
0
// Parameters are taken from EV_SET (see kevent(2))
static int
enqueue_kqueue_change(poller *p,uintptr_t ident,short filter,u_short flags,
			u_int fflags,intptr_t data,void *udata){
	// This unlikely event could occur if, for instance, every fd is being
	// used, and on the last sysdep_poll() every one had event changes,
	// and then a verdict was injected while the poller was blocked.... or
	// (far more likely) in the case of programming error, heheh
	if(p->kchanges >= p->csize){
		typeof(p->csize) tmpcsize = p->csize * 2;
		typeof(*p->cv) *tmpcv;

		// If we've not yet been initialized, or reset, don't start
		// growing buffers...that's a serious problem. Should this be
		// changed, insert a p->csize check around the Kevent() failure
		// case involving vector dump and reuse of implied first slot!
		if(p->csize == 0){
			bitch("Used with uninitialized poller\n");
			return -1;
		}
		if((tmpcv = Realloc("kchange vector",p->cv,sizeof(*tmpcv) * tmpcsize)) == NULL){
			// If the realloc failed, dump the current vector...
			if(Kevent(p->kq,p->cv,p->kchanges,NULL,0,NULL)){
				inc_stateexceptions();
				return -1;
			}
			// Reinitialize the buffer. We're assured that there's
			// room for at least one of us now by p->csize check
			p->kchanges = 0;
		}else{
			p->cv = tmpcv;
			p->csize = tmpcsize;
		}
	}
	EV_SET(&p->cv[p->kchanges++],ident,filter,flags,fflags,data,udata);
	return 0;
}
示例#3
0
static inline void
handle_event(torque_ctx *ctx,const kevententry *e){
#ifdef TORQUE_LINUX
	if(e->events & EVREAD){
#else
	if(e->filter == EVFILT_READ){
#endif
		handle_evsource_read(ctx->eventtables.fdarray,KEVENTENTRY_ID(e));
	}
#ifdef TORQUE_LINUX
	if(e->events & EVWRITE){
#else
	else if(e->filter == EVFILT_WRITE){
#endif
		handle_evsource_write(ctx->eventtables.fdarray,KEVENTENTRY_ID(e));
	}
#ifdef TORQUE_FREEBSD
	else if(e->filter == EVFILT_SIGNAL){
		handle_evsource_read(ctx->eventtables.sigarray,KEVENTENTRY_ID(e));
        }else if(e->filter == EVFILT_TIMER){
		timer_curry(KEVENTENTRY_IDPTR(e));
	}
#endif
}

void rxcommonsignal(int sig,void *cbstate){
	if(sig == EVTHREAD_TERM || sig == EVTHREAD_INT){
		const torque_ctx *ctx = cbstate;
		void *ret = PTHREAD_CANCELED;
		evhandler *e = get_thread_evh();
		struct rusage ru;
		int r;

		// There's no POSIX thread cancellation going on here, nor are
		// we terminating due to signal; we're catching the signal and
		// exiting from this thread only. The trigger signal might be
		// delivered to any one of our threads; if we're here, though,
		// we cannot be holding the efd. Progress is thus assured.
		pthread_kill(e->nexttid,sig);
		// We rely on EDEADLK to cut off our circular join()list
		if((r = pthread_join(e->nexttid,&ret)) && r != EDEADLK){
			ret = NULL;
		}
		// FIXME this is kind of lame. I'd like to emulate
		// RUSAGE_THREAD when it's unavailable, and either way the test
		// ought be based on whether RUSAGE_THREAD is *expected*, not
		// *defined* (Linux 2.6.26+) for future-proofing.
#ifdef RUSAGE_THREAD
		getrusage(RUSAGE_THREAD,&ru);
#else
		getrusage(RUSAGE_SELF,&ru);
#endif
		e->stats.utimeus = ru.ru_utime.tv_sec * 1000000 + ru.ru_utime.tv_usec;
		e->stats.stimeus = ru.ru_stime.tv_sec * 1000000 + ru.ru_stime.tv_usec;
		e->stats.vctxsw = ru.ru_nvcsw;
		e->stats.ictxsw = ru.ru_nivcsw;
		destroy_evhandler(ctx,e);
		pthread_exit(ret); // FIXME need clean up stack
	}
}

#if defined(TORQUE_LINUX) && !defined(TORQUE_LINUX_SIGNALFD)
static sig_atomic_t sem_rxcommonsignal;

static inline void
check_for_termination(void){
	if(sem_rxcommonsignal){
		int s;

		s = sem_rxcommonsignal;
		sem_rxcommonsignal = 0;
		rxcommonsignal(s,get_thread_ctx());
	}
}

static void
rxcommonsignal_handler(int sig,void *cbstate __attribute__ ((unused))){
	sem_rxcommonsignal = sig;
}
#else
#define check_for_termination(...)
#endif

void event_thread(torque_ctx *ctx,evhandler *e){
	tsd_evhandler = e;
	tsd_ctx = ctx;
	while(1){
		int events;

		check_for_termination();
		events = Kevent(e->evq->efd,NULL,0,PTR_TO_EVENTV(&e->evec),e->evec.vsizes);
		++e->stats.rounds;
		if(events < 0){
			if(errno != EINTR){
				++e->stats.pollerr;
			}
			continue;
		}
		while(events--){
#ifdef TORQUE_LINUX
			handle_event(ctx,&PTR_TO_EVENTV(&e->evec)->events[events]);
#else
			handle_event(ctx,&PTR_TO_EVENTV(&e->evec)[events]);
#endif
			++e->stats.events;
		}
	}
}

static int
#ifdef TORQUE_LINUX
create_evector(struct kevent *kv,int n){
	if((kv->events = malloc(n * sizeof(*kv->events))) == NULL){
		return -1;
	}
	if((kv->ctldata = malloc(n * sizeof(*kv->ctldata))) == NULL){
		free(kv->events);
		return -1;
	}
	return 0;
#else
create_evector(struct kevent **kv,int n){
	if((*kv = malloc(n * sizeof(**kv))) == NULL){
		return -1;
	}
	return 0;
#endif
}

static void
#ifdef TORQUE_LINUX
destroy_evector(struct kevent *kv){
	free(kv->events);
	free(kv->ctldata);
#else
destroy_evector(struct kevent **kv){
	free(*kv);
#endif
}

static int
init_evectors(evectors *ev){
	// We probably want about a half (small) page's worth...? FIXME
	ev->vsizes = 512;
	if(create_evector(&ev->eventv,ev->vsizes)){
		return -1;
	}
	return 0;
}