]> mj.ucw.cz Git - libucw.git/blob - ucw/main-block.c
bgets_mp(): Added a non-intuitive warning to documentation.
[libucw.git] / ucw / main-block.c
1 /*
2  *      UCW Library -- Main Loop: Block I/O
3  *
4  *      (c) 2004--2011 Martin Mares <mj@ucw.cz>
5  *
6  *      This software may be freely distributed and used according to the terms
7  *      of the GNU Lesser General Public License.
8  */
9
10 #undef LOCAL_DEBUG
11
12 #include <ucw/lib.h>
13 #include <ucw/mainloop.h>
14
15 #include <stdio.h>
16 #include <string.h>
17 #include <stdlib.h>
18 #include <unistd.h>
19 #include <errno.h>
20
21 static void
22 block_io_timer_expired(struct main_timer *tm)
23 {
24   struct main_block_io *bio = tm->data;
25   timer_del(&bio->timer);
26   if (bio->error_handler)
27     bio->error_handler(bio, BIO_ERR_TIMEOUT);
28 }
29
30 void
31 block_io_add(struct main_block_io *bio, int fd)
32 {
33   bio->file.fd = fd;
34   file_add(&bio->file);
35   bio->timer.handler = block_io_timer_expired;
36   bio->timer.data = bio;
37 }
38
39 void
40 block_io_del(struct main_block_io *bio)
41 {
42   timer_del(&bio->timer);
43   file_del(&bio->file);
44 }
45
46 static int
47 block_io_read_handler(struct main_file *fi)
48 {
49   struct main_block_io *bio = (struct main_block_io *) fi;
50
51   while (bio->rpos < bio->rlen)
52     {
53       int l = read(fi->fd, bio->rbuf + bio->rpos, bio->rlen - bio->rpos);
54       DBG("BIO: FD %d: read %d", fi->fd, l);
55       if (l < 0)
56         {
57           if (errno != EINTR && errno != EAGAIN && bio->error_handler)
58             bio->error_handler(bio, BIO_ERR_READ);
59           return HOOK_IDLE;
60         }
61       else if (!l)
62         break;
63       bio->rpos += l;
64     }
65   DBG("BIO: FD %d done read %d of %d", fi->fd, bio->rpos, bio->rlen);
66   fi->read_handler = NULL;
67   file_chg(fi);
68   bio->read_done(bio);
69   return HOOK_RETRY;
70 }
71
72 static int
73 block_io_write_handler(struct main_file *fi)
74 {
75   struct main_block_io *bio = (struct main_block_io *) fi;
76
77   while (bio->wpos < bio->wlen)
78     {
79       int l = write(fi->fd, bio->wbuf + bio->wpos, bio->wlen - bio->wpos);
80       DBG("BIO: FD %d: write %d", fi->fd, l);
81       if (l < 0)
82         {
83           if (errno != EINTR && errno != EAGAIN && bio->error_handler)
84             bio->error_handler(bio, BIO_ERR_WRITE);
85           return HOOK_IDLE;
86         }
87       bio->wpos += l;
88     }
89   DBG("BIO: FD %d done write %d", fi->fd, bio->wpos);
90   fi->write_handler = NULL;
91   file_chg(fi);
92   bio->write_done(bio);
93   return HOOK_RETRY;
94 }
95
96 void
97 block_io_read(struct main_block_io *bio, void *buf, uint len)
98 {
99   ASSERT(bio->file.n.next);
100   if (len)
101     {
102       bio->file.read_handler = block_io_read_handler;
103       bio->rbuf = buf;
104       bio->rpos = 0;
105       bio->rlen = len;
106     }
107   else
108     {
109       bio->file.read_handler = NULL;
110       bio->rbuf = NULL;
111       bio->rpos = bio->rlen = 0;
112     }
113   file_chg(&bio->file);
114 }
115
116 void
117 block_io_write(struct main_block_io *bio, void *buf, uint len)
118 {
119   ASSERT(bio->file.n.next);
120   if (len)
121     {
122       bio->file.write_handler = block_io_write_handler;
123       bio->wbuf = buf;
124       bio->wpos = 0;
125       bio->wlen = len;
126     }
127   else
128     {
129       bio->file.write_handler = NULL;
130       bio->wbuf = NULL;
131       bio->wpos = bio->wlen = 0;
132     }
133   file_chg(&bio->file);
134 }
135
136 void
137 block_io_set_timeout(struct main_block_io *bio, timestamp_t expires_delta)
138 {
139   if (!expires_delta)
140     timer_del(&bio->timer);
141   else
142     timer_add_rel(&bio->timer, expires_delta);
143 }