master
  1#include <aio.h>
  2#include <errno.h>
  3#include <unistd.h>
  4#include <string.h>
  5#include "pthread_impl.h"
  6
  7struct lio_state {
  8	struct sigevent *sev;
  9	int cnt;
 10	struct aiocb *cbs[];
 11};
 12
 13static int lio_wait(struct lio_state *st)
 14{
 15	int i, err, got_err = 0;
 16	int cnt = st->cnt;
 17	struct aiocb **cbs = st->cbs;
 18
 19	for (;;) {
 20		for (i=0; i<cnt; i++) {
 21			if (!cbs[i]) continue;
 22			err = aio_error(cbs[i]);
 23			if (err==EINPROGRESS)
 24				break;
 25			if (err) got_err=1;
 26			cbs[i] = 0;
 27		}
 28		if (i==cnt) {
 29			if (got_err) {
 30				errno = EIO;
 31				return -1;
 32			}
 33			return 0;
 34		}
 35		if (aio_suspend((void *)cbs, cnt, 0))
 36			return -1;
 37	}
 38}
 39
 40static void notify_signal(struct sigevent *sev)
 41{
 42	siginfo_t si = {
 43		.si_signo = sev->sigev_signo,
 44		.si_value = sev->sigev_value,
 45		.si_code = SI_ASYNCIO,
 46		.si_pid = getpid(),
 47		.si_uid = getuid()
 48	};
 49	__syscall(SYS_rt_sigqueueinfo, si.si_pid, si.si_signo, &si);
 50}
 51
 52static void *wait_thread(void *p)
 53{
 54	struct lio_state *st = p;
 55	struct sigevent *sev = st->sev;
 56	lio_wait(st);
 57	free(st);
 58	switch (sev->sigev_notify) {
 59	case SIGEV_SIGNAL:
 60		notify_signal(sev);
 61		break;
 62	case SIGEV_THREAD:
 63		sev->sigev_notify_function(sev->sigev_value);
 64		break;
 65	}
 66	return 0;
 67}
 68
 69int lio_listio(int mode, struct aiocb *restrict const *restrict cbs, int cnt, struct sigevent *restrict sev)
 70{
 71	int i, ret;
 72	struct lio_state *st=0;
 73
 74	if (cnt < 0) {
 75		errno = EINVAL;
 76		return -1;
 77	}
 78
 79	if (mode == LIO_WAIT || (sev && sev->sigev_notify != SIGEV_NONE)) {
 80		if (!(st = malloc(sizeof *st + cnt*sizeof *cbs))) {
 81			errno = EAGAIN;
 82			return -1;
 83		}
 84		st->cnt = cnt;
 85		st->sev = sev;
 86		memcpy(st->cbs, (void*) cbs, cnt*sizeof *cbs);
 87	}
 88
 89	for (i=0; i<cnt; i++) {
 90		if (!cbs[i]) continue;
 91		switch (cbs[i]->aio_lio_opcode) {
 92		case LIO_READ:
 93			ret = aio_read(cbs[i]);
 94			break;
 95		case LIO_WRITE:
 96			ret = aio_write(cbs[i]);
 97			break;
 98		default:
 99			continue;
100		}
101		if (ret) {
102			free(st);
103			errno = EAGAIN;
104			return -1;
105		}
106	}
107
108	if (mode == LIO_WAIT) {
109		ret = lio_wait(st);
110		free(st);
111		return ret;
112	}
113
114	if (st) {
115		pthread_attr_t a;
116		sigset_t set, set_old;
117		pthread_t td;
118
119		if (sev->sigev_notify == SIGEV_THREAD) {
120			if (sev->sigev_notify_attributes)
121				a = *sev->sigev_notify_attributes;
122			else
123				pthread_attr_init(&a);
124		} else {
125			pthread_attr_init(&a);
126			pthread_attr_setstacksize(&a, PAGE_SIZE);
127			pthread_attr_setguardsize(&a, 0);
128		}
129		pthread_attr_setdetachstate(&a, PTHREAD_CREATE_DETACHED);
130		sigfillset(&set);
131		pthread_sigmask(SIG_BLOCK, &set, &set_old);
132		if (pthread_create(&td, &a, wait_thread, st)) {
133			free(st);
134			errno = EAGAIN;
135			return -1;
136		}
137		pthread_sigmask(SIG_SETMASK, &set_old, 0);
138	}
139
140	return 0;
141}