lio_listio.c raw

   1  #include <aio.h>
   2  #include <errno.h>
   3  #include <unistd.h>
   4  #include <string.h>
   5  #include "pthread_impl.h"
   6  
   7  struct lio_state {
   8  	struct sigevent *sev;
   9  	int cnt;
  10  	struct aiocb *cbs[];
  11  };
  12  
  13  static 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  
  40  static 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  
  52  static 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  
  69  int 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  }
 142  
 143  weak_alias(lio_listio, lio_listio64);
 144