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_contextio_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 (  ) 

#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 }


Generated on Wed Oct 28 15:49:01 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.6