Tue Aug 20 16:35:05 2013

Asterisk developer's documentation


io.c File Reference

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

#include "asterisk.h"
#include <termios.h>
#include <sys/ioctl.h>
#include "asterisk/io.h"
#include "asterisk/utils.h"

Go to the source code of this file.

Data Structures

struct  io_context
 Global IO variables are now in a struct in order to be made threadsafe. More...
struct  io_rec
 Kept for each file descriptor. More...

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)
 Add a new I/O entry for this file descriptor with the given event mask, to call callback with data as an argument.
int * ast_io_change (struct io_context *ioc, int *id, int fd, ast_io_cb callback, short events, void *data)
 Changes an IO handler.
void ast_io_dump (struct io_context *ioc)
 Dumps the IO array. Debugging: Dump everything in the I/O array.
int ast_io_remove (struct io_context *ioc, int *_id)
 Removes an IO context.
int ast_io_wait (struct io_context *ioc, int howlong)
 Make the poll call, and call the callbacks for anything that needs to be handled.
int ast_restore_tty (int fd, int oldstate)
 Restores TTY mode. Call with result from previous ast_hide_password.
struct io_contextio_context_create (void)
 Create an I/O context.
void io_context_destroy (struct io_context *ioc)
 Destroys a context.
static int io_grow (struct io_context *ioc)
 Grow the size of our arrays.
static int io_shrink (struct io_context *ioc)

Detailed Description

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

Author:
Mark Spencer <markster@digium.com>

Definition in file io.c.


Define Documentation

#define DEBUG (  ) 

Definition at line 43 of file io.c.

#define GROW_SHRINK_SIZE   512

Definition at line 62 of file io.c.

Referenced by io_context_create(), and io_grow().


Function Documentation

int ast_get_termcols ( int  fd  ) 

Definition at line 368 of file io.c.

Referenced by ast_cli_display_match_list().

00369 {
00370    struct winsize win;
00371    int cols = 0;
00372 
00373    if (!isatty(fd))
00374       return -1;
00375 
00376    if ( ioctl(fd, TIOCGWINSZ, &win) != -1 ) {
00377       if ( !cols && win.ws_col > 0 )
00378          cols = (int) win.ws_col;
00379    } else {
00380       /* assume 80 characters if the ioctl fails for some reason */
00381       cols = 80;
00382    }
00383 
00384    return cols;
00385 }

int ast_hide_password ( int  fd  ) 

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

Definition at line 332 of file io.c.

References ECHO.

Referenced by pw_cb().

00333 {
00334    struct termios tios;
00335    int res;
00336    int old;
00337    if (!isatty(fd))
00338       return -1;
00339    res = tcgetattr(fd, &tios);
00340    if (res < 0)
00341       return -1;
00342    old = tios.c_lflag & (ECHO | ECHONL);
00343    tios.c_lflag &= ~ECHO;
00344    tios.c_lflag |= ECHONL;
00345    res = tcsetattr(fd, TCSAFLUSH, &tios);
00346    if (res < 0)
00347       return -1;
00348    return old;
00349 }

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

Add a new I/O entry for this file descriptor with the given event mask, to call callback with data as an argument.

Adds an IO context.

Returns:
Returns NULL on failure.

Definition at line 157 of file io.c.

References ast_debug, ast_malloc, io_rec::callback, io_rec::data, DEBUG, io_context::fdcnt, io_context::fds, io_rec::id, io_grow(), io_context::ior, and io_context::maxfdcnt.

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

00158 {
00159    int *ret;
00160 
00161    DEBUG(ast_debug(1, "ast_io_add()\n"));
00162 
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 
00183    if (!(ioc->ior[ioc->fdcnt].id = ast_malloc(sizeof(*ioc->ior[ioc->fdcnt].id)))) {
00184       /* Bonk if we couldn't allocate an int */
00185       return NULL;
00186    }
00187 
00188    *(ioc->ior[ioc->fdcnt].id) = ioc->fdcnt;
00189    ret = ioc->ior[ioc->fdcnt].id;
00190    ioc->fdcnt++;
00191 
00192    return ret;
00193 }

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.
Return values:
a pointer to the ID of the IO event
NULL on failure

Definition at line 195 of file io.c.

References io_rec::callback, io_rec::data, io_context::fdcnt, io_context::fds, and io_context::ior.

Referenced by do_monitor().

00196 {
00197    /* If this id exceeds our file descriptor count it doesn't exist here */
00198    if (*id > ioc->fdcnt)
00199       return NULL;
00200 
00201    if (fd > -1)
00202       ioc->fds[*id].fd = fd;
00203    if (callback)
00204       ioc->ior[*id].callback = callback;
00205    if (events)
00206       ioc->fds[*id].events = events;
00207    if (data)
00208       ioc->ior[*id].data = data;
00209 
00210    return id;
00211 }

void ast_io_dump ( struct io_context ioc  ) 

Dumps the IO array. Debugging: Dump everything in the I/O array.

Definition at line 307 of file io.c.

References ast_debug, io_rec::callback, io_rec::data, io_context::fdcnt, io_context::fds, io_rec::id, io_context::ior, and io_context::maxfdcnt.

00308 {
00309    /*
00310     * Print some debugging information via
00311     * the logger interface
00312     */
00313    int x;
00314 
00315    ast_debug(1, "Asterisk IO Dump: %d entries, %d max entries\n", ioc->fdcnt, ioc->maxfdcnt);
00316    ast_debug(1, "================================================\n");
00317    ast_debug(1, "| ID    FD     Callback    Data        Events  |\n");
00318    ast_debug(1, "+------+------+-----------+-----------+--------+\n");
00319    for (x = 0; x < ioc->fdcnt; x++) {
00320       ast_debug(1, "| %.4d | %.4d | %p | %p | %.6x |\n", 
00321             *ioc->ior[x].id,
00322             ioc->fds[x].fd,
00323             ioc->ior[x].callback,
00324             ioc->ior[x].data,
00325             ioc->fds[x].events);
00326    }
00327    ast_debug(1, "================================================\n");
00328 }

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
Return values:
0 on success
-1 on failure

Definition at line 240 of file io.c.

References ast_free, ast_log(), io_context::current_ioc, io_context::fdcnt, io_context::fds, io_rec::id, io_shrink(), io_context::ior, LOG_NOTICE, LOG_WARNING, and io_context::needshrink.

Referenced by ast_io_wait(), ast_netsock_destroy(), ast_udptl_destroy(), do_monitor(), and reload_config().

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

int ast_io_wait ( struct io_context ioc,
int  howlong 
)

Make the poll call, and call the callbacks for anything that needs to be handled.

Waits for IO.

Definition at line 273 of file io.c.

References ast_debug, ast_io_remove(), ast_poll, io_rec::callback, io_context::current_ioc, io_rec::data, DEBUG, io_context::fdcnt, io_context::fds, io_rec::id, io_shrink(), io_context::ior, and io_context::needshrink.

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

00274 {
00275    int res, x, origcnt;
00276 
00277    DEBUG(ast_debug(1, "ast_io_wait()\n"));
00278 
00279    if ((res = ast_poll(ioc->fds, ioc->fdcnt, howlong)) <= 0) {
00280       return res;
00281    }
00282 
00283    /* At least one event tripped */
00284    origcnt = ioc->fdcnt;
00285    for (x = 0; x < origcnt; x++) {
00286       /* Yes, it is possible for an entry to be deleted and still have an
00287          event waiting if it occurs after the original calling id */
00288       if (ioc->fds[x].revents && ioc->ior[x].id) {
00289          /* There's an event waiting */
00290          ioc->current_ioc = *ioc->ior[x].id;
00291          if (ioc->ior[x].callback) {
00292             if (!ioc->ior[x].callback(ioc->ior[x].id, ioc->fds[x].fd, ioc->fds[x].revents, ioc->ior[x].data)) {
00293                /* Time to delete them since they returned a 0 */
00294                ast_io_remove(ioc, ioc->ior[x].id);
00295             }
00296          }
00297          ioc->current_ioc = -1;
00298       }
00299    }
00300 
00301    if (ioc->needshrink)
00302       io_shrink(ioc);
00303 
00304    return res;
00305 }

int ast_restore_tty ( int  fd,
int  oldstate 
)

Restores TTY mode. Call with result from previous ast_hide_password.

Definition at line 351 of file io.c.

References ECHO.

Referenced by pw_cb().

00352 {
00353    int res;
00354    struct termios tios;
00355    if (oldstate < 0)
00356       return 0;
00357    res = tcgetattr(fd, &tios);
00358    if (res < 0)
00359       return -1;
00360    tios.c_lflag &= ~(ECHO | ECHONL);
00361    tios.c_lflag |= oldstate;
00362    res = tcsetattr(fd, TCSAFLUSH, &tios);
00363    if (res < 0)
00364       return -1;
00365    return 0;
00366 }

struct io_context* io_context_create ( void   )  [read]

Create an I/O context.

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

Definition at line 76 of file io.c.

References ast_calloc, ast_free, ast_malloc, io_context::current_ioc, io_context::fdcnt, io_context::fds, GROW_SHRINK_SIZE, io_context::ior, io_context::maxfdcnt, and io_context::needshrink.

Referenced by load_module().

00077 {
00078    struct io_context *tmp = NULL;
00079 
00080    if (!(tmp = ast_malloc(sizeof(*tmp))))
00081       return NULL;
00082    
00083    tmp->needshrink = 0;
00084    tmp->fdcnt = 0;
00085    tmp->maxfdcnt = GROW_SHRINK_SIZE/2;
00086    tmp->current_ioc = -1;
00087    
00088    if (!(tmp->fds = ast_calloc(1, (GROW_SHRINK_SIZE / 2) * sizeof(*tmp->fds)))) {
00089       ast_free(tmp);
00090       tmp = NULL;
00091    } else {
00092       if (!(tmp->ior = ast_calloc(1, (GROW_SHRINK_SIZE / 2) * sizeof(*tmp->ior)))) {
00093          ast_free(tmp->fds);
00094          ast_free(tmp);
00095          tmp = NULL;
00096       }
00097    }
00098 
00099    return tmp;
00100 }

void io_context_destroy ( struct io_context ioc  ) 

Destroys a context.

Parameters:
ioc structure to destroy Destroy a context for I/O operations Frees all memory associated with the given io_context structure along with the structure itself

Definition at line 102 of file io.c.

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

Referenced by load_module(), and unload_module().

00103 {
00104    /* Free associated memory with an I/O context */
00105    if (ioc->fds)
00106       ast_free(ioc->fds);
00107    if (ioc->ior)
00108       ast_free(ioc->ior);
00109 
00110    ast_free(ioc);
00111 }

static int io_grow ( struct io_context ioc  )  [static]

Grow the size of our arrays.

Returns:
0 on success or -1 on failure

Definition at line 117 of file io.c.

References ast_debug, ast_realloc, DEBUG, io_context::fds, GROW_SHRINK_SIZE, io_context::ior, and io_context::maxfdcnt.

Referenced by ast_io_add().

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

static int io_shrink ( struct io_context ioc  )  [static]

Definition at line 213 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().

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


Generated on 20 Aug 2013 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1