github.com/afumu/libc@v0.0.6/musl/src/aio/lio_listio.c (about)

     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);