2 * Copyright (c) 1998,1999,2000
3 * Traakan, Inc., Los Altos, CA
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice unmodified, this list of conditions, and the following
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
43 * Initialize a channel. Make sure it won't be confused for active.
46 ndmchan_initialize (struct ndmchan *ch, char *name)
48 NDMOS_MACRO_ZEROFILL(ch);
49 ch->name = name ? name : "???";
51 ch->mode = NDMCHAN_MODE_IDLE;
58 ndmchan_setbuf (struct ndmchan *ch, char *data, unsigned data_size)
61 ch->data_size = data_size;
73 * Interfaces for starting a channel in various modes.
76 ndmchan_start_mode (struct ndmchan *ch, int fd, int chan_mode)
84 ndmchan_start_read (struct ndmchan *ch, int fd)
86 return ndmchan_start_mode (ch, fd, NDMCHAN_MODE_READ);
90 ndmchan_start_write (struct ndmchan *ch, int fd)
92 return ndmchan_start_mode (ch, fd, NDMCHAN_MODE_WRITE);
96 ndmchan_start_readchk (struct ndmchan *ch, int fd)
98 return ndmchan_start_mode (ch, fd, NDMCHAN_MODE_READCHK);
102 ndmchan_start_listen (struct ndmchan *ch, int fd)
104 return ndmchan_start_mode (ch, fd, NDMCHAN_MODE_LISTEN);
108 ndmchan_start_resident (struct ndmchan *ch)
110 return ndmchan_start_mode (ch, -1, NDMCHAN_MODE_RESIDENT);
114 ndmchan_start_pending (struct ndmchan *ch, int fd)
116 return ndmchan_start_mode (ch, fd, NDMCHAN_MODE_PENDING);
120 * Change a PENDING channel to an active (READ/WRITE) channel
123 ndmchan_pending_to_mode (struct ndmchan *ch, int chan_mode)
125 ch->mode = chan_mode;
130 ndmchan_pending_to_read (struct ndmchan *ch)
132 return ndmchan_pending_to_mode (ch, NDMCHAN_MODE_READ);
136 ndmchan_pending_to_write (struct ndmchan *ch)
138 return ndmchan_pending_to_mode (ch, NDMCHAN_MODE_WRITE);
145 * Interfaces for stopping (close()ing) a channel.
146 * This is a bit of a hodge-podge. Could probably be cleaner.
150 ndmchan_set_eof (struct ndmchan *ch)
156 ndmchan_close_set_errno (struct ndmchan *ch, int err_no)
163 ch->mode = NDMCHAN_MODE_CLOSED;
164 ch->saved_errno = err_no;
165 ch->beg_ix = ch->end_ix = 0;
169 ndmchan_close (struct ndmchan *ch) {
170 ndmchan_close_set_errno (ch, 0);
174 ndmchan_abort (struct ndmchan *ch) {
175 ndmchan_close_set_errno (ch,
176 ch->saved_errno == 0 ? EINTR : ch->saved_errno);
180 ndmchan_close_as_is (struct ndmchan *ch) {
181 ndmchan_close_set_errno (ch, ch->saved_errno);
185 ndmchan_cleanup (struct ndmchan *ch) {
186 if (ch->mode != NDMCHAN_MODE_IDLE) {
187 ndmchan_close_as_is (ch);
195 * CPU Quantum for a set of channels. There are three
197 * 1) Identify the channels to check for ready to do I/O.
198 * For example, a READ channel with no buffer space
199 * need not be checked.
200 * 2) Call the OS dependent function that performs the
201 * actual select()/poll()/whatever.
202 * 3) Based on the results, perform actual read()/write().
203 * EOF and errors are detected.
205 * This is constructed so that applications which can not use
206 * ndmchan_quantum() directly have access to the helper functions
207 * ndmchan_pre_poll() and ndmchan_post_poll().
211 ndmchan_quantum (struct ndmchan *chtab[], unsigned n_chtab, int milli_timo)
215 ndmchan_pre_poll (chtab, n_chtab);
217 rc = ndmos_chan_poll (chtab, n_chtab, milli_timo);
221 rc = ndmchan_post_poll (chtab, n_chtab);
227 ndmchan_pre_poll (struct ndmchan *chtab[], unsigned n_chtab)
230 unsigned int i, n_check;
233 for (i = 0; i < n_chtab; i++) {
243 case NDMCHAN_MODE_IDLE:
244 case NDMCHAN_MODE_PENDING:
245 case NDMCHAN_MODE_RESIDENT:
246 case NDMCHAN_MODE_CLOSED:
249 case NDMCHAN_MODE_LISTEN:
250 case NDMCHAN_MODE_READCHK:
253 case NDMCHAN_MODE_READ:
256 if (ndmchan_n_avail (ch) == 0)
260 case NDMCHAN_MODE_WRITE:
261 if (ndmchan_n_ready (ch) == 0)
274 ndmchan_post_poll (struct ndmchan *chtab[], unsigned n_chtab)
278 int rc, len, n_ready;
282 for (i = 0; i < n_chtab; i++) {
289 case NDMCHAN_MODE_READ:
290 len = ndmchan_n_avail (ch);
291 if (len <= 0) continue;
294 rc = read (ch->fd, &ch->data[ch->end_ix], len);
296 if (errno != NDMOS_CONST_EWOULDBLOCK) {
297 ch->error = ch->eof = 1;
298 ch->saved_errno = errno;
299 if (!ch->saved_errno)
300 ch->saved_errno = -1;
304 } else if (rc == 0) {
313 case NDMCHAN_MODE_WRITE:
314 len = ndmchan_n_ready (ch);
315 if (len <= 0) continue;
318 rc = write (ch->fd, &ch->data[ch->beg_ix], len);
320 if (errno != NDMOS_CONST_EWOULDBLOCK) {
323 ch->saved_errno = errno;
324 if (!ch->saved_errno)
325 ch->saved_errno = -1;
327 /* no bytes written */
328 /* EWOULDBLOCK but ready? */
330 } else if (rc == 0) {
331 /* NDMOS_CONST_EWOULDBLOCK? */
349 * Channel data buffer space manipulation.
353 ndmchan_compress (struct ndmchan *ch) {
354 unsigned len = ch->end_ix - ch->beg_ix;
356 if (ch->beg_ix > 0 && len > 0) {
357 bcopy (&ch->data[ch->beg_ix], ch->data, len);
359 if (len > ch->data_size)
367 ndmchan_n_avail (struct ndmchan *ch) {
368 if (ch->end_ix == ch->beg_ix)
369 ch->end_ix = ch->beg_ix = 0;
371 if (ch->end_ix >= ch->data_size) {
372 ndmchan_compress (ch);
374 return ch->data_size - ch->end_ix;
378 ndmchan_n_avail_record (struct ndmchan *ch, unsigned long size) {
379 if (ch->end_ix == ch->beg_ix)
380 ch->end_ix = ch->beg_ix = 0;
382 if (ch->end_ix >= ch->data_size - size) {
383 ndmchan_compress (ch);
385 return ch->data_size - ch->end_ix;
389 ndmchan_n_avail_total (struct ndmchan *ch) {
390 if (ch->end_ix == ch->beg_ix)
391 ch->end_ix = ch->beg_ix = 0;
393 if (ch->end_ix >= ch->data_size) {
394 ndmchan_compress (ch);
396 return ch->data_size - ch->end_ix + ch->beg_ix;
400 ndmchan_n_ready (struct ndmchan *ch) {
401 return ch->end_ix - ch->beg_ix;
408 * Interfaces for interpreting channel state, obtaining pointers, lengths
411 enum ndmchan_read_interpretation
412 ndmchan_read_interpret (struct ndmchan *ch, char **data_p,
417 n_ready = *n_ready_p = ndmchan_n_ready (ch);
418 *data_p = &ch->data[ch->beg_ix];
422 return NDMCHAN_RI_DONE_ERROR;
424 return NDMCHAN_RI_DRAIN_ERROR;
430 return NDMCHAN_RI_DONE_EOF;
432 return NDMCHAN_RI_DRAIN_EOF;
437 return NDMCHAN_RI_EMPTY;
440 if (n_ready == ch->data_size) {
441 return NDMCHAN_RI_READY_FULL;
444 return NDMCHAN_RI_READY;
447 enum ndmchan_write_interpretation
448 ndmchan_write_interpret (struct ndmchan *ch, char **data_p,
453 n_avail = *n_avail_p = ndmchan_n_avail (ch);
454 *data_p = &ch->data[ch->end_ix];
457 /* We don't use WI_DRAIN_ERROR. If it's kaput, it's kaput */
458 return NDMCHAN_WI_DONE_ERROR;
462 if (n_avail == ch->data_size) {
463 return NDMCHAN_WI_DONE_EOF;
465 return NDMCHAN_WI_DRAIN_EOF;
470 return NDMCHAN_WI_FULL;
473 if (n_avail == ch->data_size) {
474 return NDMCHAN_WI_AVAIL_EMPTY;
477 return NDMCHAN_WI_AVAIL;
487 ndmchan_pp (struct ndmchan *ch, char *buf)
493 sprintf (bp, "name=%s", ch->name); while (*bp) bp++;
496 case NDMCHAN_MODE_IDLE: p = "idle"; break;
497 case NDMCHAN_MODE_RESIDENT: p = "resident"; show_ra = 1; break;
498 case NDMCHAN_MODE_READ: p = "read"; show_ra = 1; break;
499 case NDMCHAN_MODE_WRITE: p = "write"; show_ra = 1; break;
500 case NDMCHAN_MODE_READCHK: p = "readchk"; break;
501 case NDMCHAN_MODE_LISTEN: p = "listen"; break;
502 case NDMCHAN_MODE_PENDING: p = "pending"; break;
503 case NDMCHAN_MODE_CLOSED: p = "closed"; break;
504 default: p = "mode=???"; break;
507 sprintf (bp, " %s ", p);
511 sprintf (bp, "ready=%d avail=%d ",
512 ndmchan_n_ready(ch), ndmchan_n_avail(ch));
516 if (ch->ready) strcat (bp, "-rdy");
517 if (ch->check) strcat (bp, "-chk");
518 if (ch->eof) strcat (bp, "-eof");
519 if (ch->error) strcat (bp, "-err");
525 #ifdef NDMOS_OPTION_USE_SELECT_FOR_CHAN_POLL
527 * Here because it is almost always used
531 ndmos_chan_poll (struct ndmchan *chtab[], unsigned n_chtab, int milli_timo)
542 timo.tv_sec = milli_timo / 1000;
543 timo.tv_usec = (milli_timo%1000) * 1000;
545 for (i = 0; i < n_chtab; i++) {
551 case NDMCHAN_MODE_LISTEN:
552 case NDMCHAN_MODE_READCHK:
553 case NDMCHAN_MODE_READ:
554 FD_SET (ch->fd, &rfds);
557 case NDMCHAN_MODE_WRITE:
558 FD_SET (ch->fd, &wfds);
565 rc = select (nfd, &rfds, &wfds, (void*)0, &timo);
569 for (i = 0; i < n_chtab; i++) {
575 case NDMCHAN_MODE_LISTEN:
576 case NDMCHAN_MODE_READCHK:
577 case NDMCHAN_MODE_READ:
578 if (FD_ISSET (ch->fd, &rfds))
582 case NDMCHAN_MODE_WRITE:
583 if (FD_ISSET (ch->fd, &wfds))
592 #endif /* NDMOS_OPTION_USE_SELECT_FOR_CHAN_POLL */
594 #ifdef NDMOS_OPTION_USE_POLL_FOR_CHAN_POLL
596 * Here because it is common, and because poll(2) is
597 * INFINITELY SUPERIOR to select(2).
601 ndmos_chan_poll (struct ndmchan *chtab[], unsigned n_chtab, int milli_timo)
604 struct pollfd pfdtab[20];
608 NDMOS_MACRO_ZEROFILL (pfdtab);
610 for (i = 0; i < n_chtab; i++) {
616 case NDMCHAN_MODE_LISTEN:
617 case NDMCHAN_MODE_READCHK:
618 case NDMCHAN_MODE_READ:
619 pfdtab[n_pfdtab].fd = ch->fd;
620 pfdtab[n_pfdtab].events = POLLIN;
623 case NDMCHAN_MODE_WRITE:
624 pfdtab[n_pfdtab].fd = ch->fd;
625 pfdtab[n_pfdtab].events = POLLOUT;
631 rc = poll (pfdtab, n_pfdtab, milli_timo);
633 @@@ TODO: post them back. Not easy @@@
638 #endif /* NDMOS_OPTION_USE_POLL_FOR_CHAN_POLL */