Asterisk.org: Developer Documentation (28 Oct 2009)

Wed Oct 28 15:49:01 2009

## Asterisk developer's documentation

# io.c File Reference

I/O Managment (Derived from Cheops-NG). More...

`#include <stdio.h>`
`#include <unistd.h>`
`#include <stdlib.h>`
`#include <termios.h>`
`#include <string.h>`
`#include <sys/ioctl.h>`
`#include "asterisk.h"`
`#include "asterisk/io.h"`
`#include "asterisk/logger.h"`

Include dependency graph for io.c:

Go to the source code of this file.

## Data Structures

struct | io_context
struct | io_rec

## Defines

#define | DEBUG(a)
#define | GROW_SHRINK_SIZE 512

## Functions

int | ast_get_termcols (int fd)
int | ast_hide_password (int fd)
int * | ast_io_add (struct io_context *ioc, int fd, ast_io_cb callback, short events, void *data)
int * | ast_io_change (struct io_context *ioc, int *id, int fd, ast_io_cb callback, short events, void *data)
void | ast_io_dump (struct io_context *ioc)
int | ast_io_remove (struct io_context *ioc, int *_id)
int | ast_io_wait (struct io_context *ioc, int howlong)
int | ast_restore_tty (int fd, int oldstate)
struct io_context * | io_context_create (void)
void | io_context_destroy (struct io_context *ioc)
static int | io_grow (struct io_context *ioc)
static int | io_shrink (struct io_context *ioc)

## Detailed Description

I/O Managment (Derived from Cheops-NG).

Definition in file io.c.

## Define Documentation

#define DEBUG | ( | a |  | ) |

Definition at line 42 of file io.c.

Referenced by ast_io_add(), ast_io_wait(), ast_sched_add_variable(), ast_sched_del(), ast_sched_runq(), ast_sched_wait(), ast_sched_when(), and io_grow().

#define GROW_SHRINK_SIZE 512

Definition at line 61 of file io.c.

Referenced by io_context_create(), and io_grow().

## Function Documentation

int ast_get_termcols | ( | int | fd | ) |

Definition at line 358 of file io.c.

Referenced by ast_cli_display_match_list().

    00359 {
    00360    struct winsize win;
    00361    int cols = 0;
    00362
    00363    if (!isatty(fd))
    00364       return -1;
    00365
    00366    if ( ioctl(fd, TIOCGWINSZ, &win) != -1 ) {
    00367       if ( !cols && win.ws_col > 0 )
    00368          cols = (int) win.ws_col;
    00369    } else {
    00370       /* assume 80 characters if the ioctl fails for some reason */
    00371       cols = 80;
    00372    }
    00373
    00374    return cols;
    00375 }

int ast_hide_password | ( | int | fd | ) |

Set fd into non-echoing mode (if fd is a tty)

Definition at line 322 of file io.c.

References ECHO.

Referenced by pw_cb().

    00323 {
    00324    struct termios tios;
    00325    int res;
    00326    int old;
    00327    if (!isatty(fd))
    00328       return -1;
    00329    res = tcgetattr(fd, &tios);
    00330    if (res < 0)
    00331       return -1;
    00332    old = tios.c_lflag & (ECHO | ECHONL);
    00333    tios.c_lflag &= ~ECHO;
    00334    tios.c_lflag |= ECHONL;
    00335    res = tcsetattr(fd, TCSAFLUSH, &tios);
    00336    if (res < 0)
    00337       return -1;
    00338    return old;
    00339 }

int* ast_io_add | ( | struct io_context * | ioc,
|  | int | fd,
|  | ast_io_cb | callback,
|  | short | events,
|  | void * | data |
| ) |  |  |

Adds an IO context

Parameters:

  | ioc | which context to use
  | fd | which fd to monitor
  | callback | callback function to run
  | events | event mask of events to wait for
  | data | data to pass to the callback Watch for any of revents activites on fd, calling callback with data as callback data. Returns a pointer to ID of the IO event, or NULL on failure.

Definition at line 154 of file io.c.

References ast_log(), io_rec::callback, io_rec::data, DEBUG, pollfd::events, pollfd::fd, io_context::fdcnt, io_context::fds, io_rec::id, io_grow(), io_context::ior, LOG_DEBUG, malloc, io_context::maxfdcnt, and pollfd::revents.

Referenced by ast_netsock_bindaddr(), ast_rtp_new_with_bindaddr(), do_monitor(), and network_thread().

    00155 {
    00156    /*
    00157     * Add a new I/O entry for this file descriptor
    00158     * with the given event mask, to call callback with
    00159     * data as an argument.  Returns NULL on failure.
    00160     */
    00161    int *ret;
    00162    DEBUG(ast_log(LOG_DEBUG, "ast_io_add()\n"));
    00163    if (ioc->fdcnt >= ioc->maxfdcnt) {
    00164       /*
    00165        * We don't have enough space for this entry.  We need to
    00166        * reallocate maxfdcnt poll fd's and io_rec's, or back out now.
    00167        */
    00168       if (io_grow(ioc))
    00169          return NULL;
    00170    }
    00171
    00172    /*
    00173     * At this point, we've got sufficiently large arrays going
    00174     * and we can make an entry for it in the pollfd and io_r
    00175     * structures.
    00176     */
    00177    ioc->fds[ioc->fdcnt].fd = fd;
    00178    ioc->fds[ioc->fdcnt].events = events;
    00179    ioc->fds[ioc->fdcnt].revents = 0;
    00180    ioc->ior[ioc->fdcnt].callback = callback;
    00181    ioc->ior[ioc->fdcnt].data = data;
    00182    ioc->ior[ioc->fdcnt].id = (int *)malloc(sizeof(int));
    00183    /* Bonk if we couldn't allocate an int */
    00184    if (!ioc->ior[ioc->fdcnt].id)
    00185       return NULL;
    00186    *(ioc->ior[ioc->fdcnt].id) = ioc->fdcnt;
    00187    ret = ioc->ior[ioc->fdcnt].id;
    00188    ioc->fdcnt++;
    00189    return ret;
    00190 }

int* ast_io_change | ( | struct io_context * | ioc,
|  | int * | id,
|  | int | fd,
|  | ast_io_cb | callback,
|  | short | events,
|  | void * | data |
| ) |  |  |

Changes an IO handler

Parameters:

  | ioc | which context to use
  | id |
  | fd | the fd you wish it to contain now
  | callback | new callback function
  | events | event mask to wait for
  | data | data to pass to the callback function Change an i/o handler, updating fd if > -1, callback if non-null, and revents if >-1, and data if non-null. Returns a pointero to the ID of the IO event, or NULL on failure.

Definition at line 192 of file io.c.

References io_rec::callback, io_rec::data, pollfd::events, pollfd::fd, io_context::fds, and io_context::ior.

Referenced by do_monitor().

    00193 {
    00194    if (*id < ioc->fdcnt) {
    00195       if (fd > -1)
    00196          ioc->fds[*id].fd = fd;
    00197       if (callback)
    00198          ioc->ior[*id].callback = callback;
    00199       if (events)
    00200          ioc->fds[*id].events = events;
    00201       if (data)
    00202          ioc->ior[*id].data = data;
    00203       return id;
    00204    }
    00205    return NULL;
    00206 }

void ast_io_dump | ( | struct io_context * | ioc | ) |

Dumps the IO array

Definition at line 298 of file io.c.

References ast_log(), io_rec::callback, io_rec::data, pollfd::events, pollfd::fd, io_context::fdcnt, io_context::fds, io_rec::id, io_context::ior, LOG_DEBUG, and io_context::maxfdcnt.

    00299 {
    00300    /*
    00301     * Print some debugging information via
    00302     * the logger interface
    00303     */
    00304    int x;
    00305    ast_log(LOG_DEBUG, "Asterisk IO Dump: %d entries, %d max entries\n", ioc->fdcnt, ioc->maxfdcnt);
    00306    ast_log(LOG_DEBUG, "================================================\n");
    00307    ast_log(LOG_DEBUG, "| ID    FD     Callback    Data        Events  |\n");
    00308    ast_log(LOG_DEBUG, "+------+------+-----------+-----------+--------+\n");
    00309    for (x = 0; x < ioc->fdcnt; x++) {
    00310       ast_log(LOG_DEBUG, "| %.4d | %.4d | %p | %p | %.6x |\n",
    00311             *ioc->ior[x].id,
    00312             ioc->fds[x].fd,
    00313             ioc->ior[x].callback,
    00314             ioc->ior[x].data,
    00315             ioc->fds[x].events);
    00316    }
    00317    ast_log(LOG_DEBUG, "================================================\n");
    00318 }

int ast_io_remove | ( | struct io_context * | ioc,
|  | int * | id |
| ) |  |  |

Removes an IO context

Parameters:

  | ioc | which io_context to remove it from
  | id | which ID to remove Remove an I/O id from consideration Returns 0 on success or -1 on failure.

Definition at line 235 of file io.c.

References ast_log(), io_context::current_ioc, pollfd::events, io_context::fdcnt, io_context::fds, free, io_rec::id, io_shrink(), io_context::ior, LOG_NOTICE, LOG_WARNING, io_context::needshrink, and pollfd::revents.

Referenced by ast_io_wait(), ast_netsock_destroy(), ast_rtp_destroy(), and reload_config().

    00236 {
    00237    int x;
    00238    if (!_id) {
    00239       ast_log(LOG_WARNING, "Asked to remove NULL?\n");
    00240       return -1;
    00241    }
    00242    for (x = 0; x < ioc->fdcnt; x++) {
    00243       if (ioc->ior[x].id == _id) {
    00244          /* Free the int immediately and set to NULL so we know it's unused now */
    00245          free(ioc->ior[x].id);
    00246          ioc->ior[x].id = NULL;
    00247          ioc->fds[x].events = 0;
    00248          ioc->fds[x].revents = 0;
    00249          ioc->needshrink = 1;
    00250          if (ioc->current_ioc == -1)
    00251             io_shrink(ioc);
    00252          return 0;
    00253       }
    00254    }
    00255
    00256    ast_log(LOG_NOTICE, "Unable to remove unknown id %p\n", _id);
    00257    return -1;
    00258 }

int ast_io_wait | ( | struct io_context * | ioc,
|  | int | howlong |
| ) |  |  |

Waits for IO

Parameters:

  | ioc | which context to act upon
  | howlong | how many milliseconds to wait Wait for I/O to happen, returning after howlong milliseconds, and after processing any necessary I/O. Returns the number of I/O events which took place.

Definition at line 260 of file io.c.

References ast_io_remove(), ast_log(), io_rec::callback, io_context::current_ioc, io_rec::data, DEBUG, pollfd::fd, io_context::fdcnt, io_context::fds, io_rec::id, io_shrink(), io_context::ior, LOG_DEBUG, io_context::needshrink, poll(), and pollfd::revents.

Referenced by do_monitor(), network_thread(), and reload_config().

    00261 {
    00262    /*
    00263     * Make the poll call, and call
    00264     * the callbacks for anything that needs
    00265     * to be handled
    00266     */
    00267    int res;
    00268    int x;
    00269    int origcnt;
    00270    DEBUG(ast_log(LOG_DEBUG, "ast_io_wait()\n"));
    00271    res = poll(ioc->fds, ioc->fdcnt, howlong);
    00272    if (res > 0) {
    00273       /*
    00274        * At least one event
    00275        */
    00276       origcnt = ioc->fdcnt;
    00277       for(x = 0; x < origcnt; x++) {
    00278          /* Yes, it is possible for an entry to be deleted and still have an
    00279             event waiting if it occurs after the original calling id */
    00280          if (ioc->fds[x].revents && ioc->ior[x].id) {
    00281             /* There's an event waiting */
    00282             ioc->current_ioc = *ioc->ior[x].id;
    00283             if (ioc->ior[x].callback) {
    00284                if (!ioc->ior[x].callback(ioc->ior[x].id, ioc->fds[x].fd, ioc->fds[x].revents, ioc->ior[x].data)) {
    00285                   /* Time to delete them since they returned a 0 */
    00286                   ast_io_remove(ioc, ioc->ior[x].id);
    00287                }
    00288             }
    00289             ioc->current_ioc = -1;
    00290          }
    00291       }
    00292       if (ioc->needshrink)
    00293          io_shrink(ioc);
    00294    }
    00295    return res;
    00296 }

int ast_restore_tty | ( | int | fd,
|  | int | oldstatus |
| ) |  |  |

Restores TTY mode

Definition at line 341 of file io.c.

References ECHO.

Referenced by pw_cb().

    00342 {
    00343    int res;
    00344    struct termios tios;
    00345    if (oldstate < 0)
    00346       return 0;
    00347    res = tcgetattr(fd, &tios);
    00348    if (res < 0)
    00349       return -1;
    00350    tios.c_lflag &= ~(ECHO | ECHONL);
    00351    tios.c_lflag |= oldstate;
    00352    res = tcsetattr(fd, TCSAFLUSH, &tios);
    00353    if (res < 0)
    00354       return -1;
    00355    return 0;
    00356 }

struct io_context* io_context_create | ( | void |  | ) | `[read]`

Creates a context

Create a context for I/O operations Basically mallocs an IO structure and sets up some default values. Returns an allocated io_context structure

Definition at line 80 of file io.c.

References io_context::current_ioc, io_context::fdcnt, io_context::fds, free, GROW_SHRINK_SIZE, io_context::ior, malloc, io_context::maxfdcnt, and io_context::needshrink.

Referenced by load_module().

    00081 {
    00082    /* Create an I/O context */
    00083    struct io_context *tmp;
    00084    tmp = malloc(sizeof(struct io_context));
    00085    if (tmp) {
    00086       tmp->needshrink = 0;
    00087       tmp->fdcnt = 0;
    00088       tmp->maxfdcnt = GROW_SHRINK_SIZE/2;
    00089       tmp->current_ioc = -1;
    00090       tmp->fds = malloc((GROW_SHRINK_SIZE/2) * sizeof(struct pollfd));
    00091       if (!tmp->fds) {
    00092          free(tmp);
    00093          tmp = NULL;
    00094       } else {
    00095          memset(tmp->fds, 0, (GROW_SHRINK_SIZE / 2) * sizeof(struct pollfd));
    00096          tmp->ior =  malloc((GROW_SHRINK_SIZE / 2) * sizeof(struct io_rec));
    00097          if (!tmp->ior) {
    00098             free(tmp->fds);
    00099             free(tmp);
    00100             tmp = NULL;
    00101          } else {
    00102             memset(tmp->ior, 0, (GROW_SHRINK_SIZE / 2) * sizeof(struct io_rec));
    00103          }
    00104       }
    00105    }
    00106    return tmp;
    00107 }

void io_context_destroy | ( | struct io_context * | ioc | ) |

Destroys a context

Definition at line 109 of file io.c.

References io_context::fds, free, and io_context::ior.

Referenced by unload_module().

    00110 {
    00111    /* Free associated memory with an I/O context */
    00112    if (ioc->fds)
    00113       free(ioc->fds);
    00114    if (ioc->ior)
    00115       free(ioc->ior);
    00116    free(ioc);
    00117 }

static int io_grow | ( | struct io_context * | ioc | ) | `[static]`

Definition at line 119 of file io.c.

References ast_log(), DEBUG, io_context::fds, GROW_SHRINK_SIZE, io_context::ior, LOG_DEBUG, io_context::maxfdcnt, and realloc.

Referenced by ast_io_add().

    00120 {
    00121    /*
    00122     * Grow the size of our arrays.  Return 0 on success or
    00123     * -1 on failure
    00124     */
    00125    void *tmp;
    00126    DEBUG(ast_log(LOG_DEBUG, "io_grow()\n"));
    00127    ioc->maxfdcnt += GROW_SHRINK_SIZE;
    00128    tmp = realloc(ioc->ior, (ioc->maxfdcnt + 1) * sizeof(struct io_rec));
    00129    if (tmp) {
    00130       ioc->ior = (struct io_rec *)tmp;
    00131       tmp = realloc(ioc->fds, (ioc->maxfdcnt + 1) * sizeof(struct pollfd));
    00132       if (tmp) {
    00133          ioc->fds = tmp;
    00134       } else {
    00135          /*
    00136           * Not enough memory for the pollfd.  Not really any need
    00137           * to shrink back the iorec's as we'll probably want to
    00138           * grow them again soon when more memory is available, and
    00139           * then they'll already be the right size
    00140           */
    00141          ioc->maxfdcnt -= GROW_SHRINK_SIZE;
    00142          return -1;
    00143       }
    00144    } else {
    00145       /*
    00146        * Out of memory.  We return to the old size, and return a failure
    00147        */
    00148       ioc->maxfdcnt -= GROW_SHRINK_SIZE;
    00149       return -1;
    00150    }
    00151    return 0;
    00152 }

static int io_shrink | ( | struct io_context * | ioc | ) | `[static]`

Definition at line 208 of file io.c.

References io_context::fdcnt, io_context::fds, io_rec::id, io_context::ior, and io_context::needshrink.

Referenced by ast_io_remove(), and ast_io_wait().

    00209 {
    00210    int getfrom;
    00211    int putto = 0;
    00212    /*
    00213     * Bring the fields from the very last entry to cover over
    00214     * the entry we are removing, then decrease the size of the
    00215     * arrays by one.
    00216     */
    00217    for (getfrom = 0; getfrom < ioc->fdcnt; getfrom++) {
    00218       if (ioc->ior[getfrom].id) {
    00219          /* In use, save it */
    00220          if (getfrom != putto) {
    00221             ioc->fds[putto] = ioc->fds[getfrom];
    00222             ioc->ior[putto] = ioc->ior[getfrom];
    00223             *(ioc->ior[putto].id) = putto;
    00224          }
    00225          putto++;
    00226       }
    00227    }
    00228    ioc->fdcnt = putto;
    00229    ioc->needshrink = 0;
    00230    /* FIXME: We should free some memory if we have lots of unused
    00231       io structs */
    00232    return 0;
    00233 }