File: io_tryread.c

package info (click to toggle)
libowfat 0.34-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 5,288 kB
  • sloc: ansic: 20,181; makefile: 16
file content (138 lines) | stat: -rw-r--r-- 3,461 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
#include <unistd.h>
#include <sys/time.h>
#ifdef __MINGW32__
#include <windows.h>
#include <stdio.h>
#else
#include <poll.h>
#endif
#include <errno.h>
#include "io_internal.h"
#include "byte.h"

#ifdef __MINGW32__
/* In Windows, I/O works differently. */
/* Instead of calling read until it says EAGAIN, you call read in
 * overlapping mode, and then wait for it to finish.
 * We map this to our API by having the first call to io_tryread always
 * return EAGAIN, wait for the I/O completion port to tell us the read
 * is finished, and then return the data we actually read the next time
 * we are called. */

int64 io_tryread(int64 d,char* buf,int64 len) {
  io_entry* e=iarray_get(&io_fds,d);
  if (!e) { errno=EBADF; return -3; }
  if (len<0) { errno=EINVAL; return -3; }
  if (e->readqueued==2) {
    int x=e->bytes_read;
    if (e->errorcode) {
      errno=e->errorcode;
      e->canread=0;
      return -3;
    }
    if (x>len) x=len;
    if (x) {
      byte_copy(buf,x,e->inbuf);
      byte_copy(e->inbuf,e->bytes_read-x,e->inbuf+x);
      e->bytes_read-=x;
    }
    if (!e->bytes_read) {
      e->canread=0;
      if (len>x) {
	/* queue next read */
	if (len>sizeof(e->inbuf)) len=sizeof(e->inbuf);
	fprintf(stderr,"Queueing ReadFile on handle %p...",d);
	if (ReadFile((HANDLE)d,e->inbuf,len,0,&e->or)) {
	  fprintf(stderr," got immediate answer\n");
	  e->canread=1;
	  e->readqueued=2;
	  e->next_write=first_writeable;
	  first_writeable=d;
	} else if ((e->errorcode=GetLastError())==ERROR_IO_PENDING) {
	  fprintf(stderr," OK\n");
	  e->readqueued=1;
	  e->errorcode=0;
	} else {
	  fprintf(stderr," error!\n");
	  e->canread=1;
	  e->readqueued=2;
	  e->next_write=first_writeable;
	  first_writeable=d;
	}
      }
    }
    return x;
  }
  if (!e->readqueued) {
    fprintf(stderr,"!e->readqueued\n");
    if (len>sizeof(e->inbuf)) len=sizeof(e->inbuf);
    if (ReadFile((HANDLE)d,e->inbuf,len,0,&e->or)) {
      e->readqueued=1;
      fprintf(stderr,"ReadFile returned nonzero\n");
    } else
      fprintf(stderr,"ReadFile returned zero\n");
  }
  errno=EAGAIN;
  return -1;
}

#else

int64 io_tryread(int64 d,char* buf,int64 len) {
  long r;
  struct itimerval old,new;
  struct pollfd p;
  io_entry* e=iarray_get(&io_fds,d);
  if (!e) { errno=EBADF; return -3; }
  if (!e->nonblock) {
    p.fd=d;
    if (p.fd!=d) { errno=EBADF; return -3; }	/* catch integer truncation */
    p.events=POLLIN;
    switch (poll(&p,1,0)) {
    case -1: return -3;
    case 0: errno=EAGAIN;
	    e->canread=0;
	    e->next_read=-1;
	    return -1;
    }
    new.it_interval.tv_usec=10000;
    new.it_interval.tv_sec=0;
    new.it_value.tv_usec=10000;
    new.it_value.tv_sec=0;
    setitimer(ITIMER_REAL,&new,&old);
  }
  r=read(d,buf,len);
  if (!e->nonblock) {
    setitimer(ITIMER_REAL,&old,0);
  }
  if (r==-1 && errno==EAGAIN) {
    if (e->goterror) r=-3;
    io_eagain_read(d);
    return r;
  }
  if (r==-1) {
    if (errno==EINTR) errno=EAGAIN;
    if (errno!=EAGAIN)
      r=-3;
    return r;
  }
  if (r!=len) {
    e->canread=0;
    io_eagain_read(d);
#if defined(HAVE_SIGIO)
#if 0
    debug_printf(("io_tryread: dequeueing %ld from alt read queue (next is %ld)\n",d,alt_firstread));
    alt_firstread=e->next_read;
    e->next_read=-1;
#else
  } else {
    debug_printf(("io_tryread: enqueueing %ld into alt read queue (next is %ld)\n",d,alt_firstread));
    e->next_read=alt_firstread;
    alt_firstread=d;
#endif
#endif
  }
  return r;
}

#endif