chiark / gitweb /
merge changes from trunk into our branch; cvs up -j branchpoint-hostside-wip-2006...
[trains.git] / hostside / obc.c
1 /*
2  * daemons
3  * output buffer chains
4  */
5
6 #include <assert.h>
7 #include <stdlib.h>
8 #include <errno.h>
9 #include <stdarg.h>
10 #include <string.h>
11
12 #include "daemons.h"
13 #include "../layout/dlist.h"
14
15 struct OutBuffer {
16   OutBuffer *back, *next;
17   char *m;
18   int l;
19 };
20
21 int obc_tryflush(OutBufferChain *ch) {
22   OutBuffer *ob;
23   int r;
24   
25   for (;;) {
26     ob= ch->obs.head;
27     if (!ob) {
28       events->cancel_fd(events, ch->fd, OOP_WRITE);
29       return 0;
30     }
31     if (ch->done_of_head == ob->l) {
32       LIST_UNLINK(ch->obs, ob);
33       free(ob);
34       free(ob->m);
35       ch->done_of_head= 0;
36       continue;
37     }
38     r= write(ch->fd, ob->m + ch->done_of_head, ob->l - ch->done_of_head);
39     if (r==-1) {
40       if (errno==EINTR) continue;
41       if (errno==EWOULDBLOCK) return errno;
42       ch->error(ch,"write",strerror(errno));
43       return errno;
44     }
45     assert(r>=0);
46     ch->done_of_head += r;
47     assert(ch->done_of_head <= ob->l);
48   }
49 }
50
51 static void *writeable(oop_source *evts, int fd,
52                        oop_event evt, void *ch_v) {
53   OutBufferChain *ch= ch_v;
54   assert(fd == ch->fd);
55   assert(evt == OOP_WRITE);
56   obc_tryflush(ch);
57   return OOP_CONTINUE;
58 }
59
60 static void addlink(OutBufferChain *ch, OutBuffer *ob) {
61   if (!ch->obs.head)
62     events->on_fd(events, ch->fd, OOP_WRITE, writeable, ch);
63   LIST_LINK_TAIL(ch->obs, ob);
64 }
65
66 void obc_init(OutBufferChain *ch) {
67   int r;
68   ch->done_of_head= 0;
69   r= oop_fd_nonblock(ch->fd, 1);
70   if (r) diee("nonblock(OutBufferChain->fd,1)");
71   LIST_INIT(ch->obs);
72 }
73
74 void ovprintf(OutBufferChain *ch, const char *fmt, va_list al) {
75   OutBuffer *ob;
76
77   ob= mmalloc(sizeof(*ob));
78   ob->l= vasprintf(&ob->m, fmt, al);  if (ob->l <= 0) diem();
79   addlink(ch, ob);
80 }
81
82 void oprintf(OutBufferChain *ch, const char *msg, ...) {
83   va_list al;
84   va_start(al,msg);
85   ovprintf(ch,msg,al);
86   va_end(al);
87 }
88
89 void voerror(OutBufferChain *ch, const char *fmt, va_list al) {
90   oprintf(ch,"error ");
91   ovprintf(ch,fmt,al);
92   owrite(ch,"\n",1);
93 }
94
95 void owrite(OutBufferChain *ch, const char *data, int l) {
96   OutBuffer *ob;
97   ob= mmalloc(sizeof(*ob));
98   ob->l= l;
99   ob->m= mmalloc(l);
100   memcpy(ob->m, data, l);
101   addlink(ch,ob);
102 }