evil-qemacs/unix.c
Charlie Gordon d4d6f8a0f3 fixed some configure issues for mingw compile under cygwin
added CONFIG_MMAP to control availability of memory mapped files
added CONFIG_DOC to control doc rebuild
use state variables to control file mmapping and loading
default limit of 512MB for loading file
try and load the file upon mmap failure
do not use alloca in CONFIG_WIN32
use CONFIG_WIN32 instead of WIN32
update Makefile to enable win32 build under cygwin (dumps core)
renamed mouse_event to prevent compile warning
patched unix.c util.c win32.c to enable WIN32 compile
fixed kmap.c to load mapping files when mmap fails or is unavailable
2008-04-05 23:04:56 +00:00

318 lines
7.3 KiB
C

/*
* Unix main loop for QEmacs
*
* Copyright (c) 2002, 2003 Fabrice Bellard.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "qe.h"
#ifdef CONFIG_WIN32
#include <winsock.h>
/* Use a conditional typedef to avoid compilation warning */
typedef u_int fdesc_t;
#else
#include <sys/wait.h>
typedef int fdesc_t;
#endif
/* NOTE: it is strongly inspirated from the 'links' browser API */
typedef struct URLHandler {
void *read_opaque;
void (*read_cb)(void *opaque);
void *write_opaque;
void (*write_cb)(void *opaque);
} URLHandler;
typedef struct PidHandler {
struct PidHandler *next, *prev;
int pid;
void (*cb)(void *opaque, int status);
void *opaque;
} PidHandler;
typedef struct BottomHalfEntry {
struct BottomHalfEntry *next, *prev;
void (*cb)(void *opaque);
void *opaque;
} BottomHalfEntry;
struct QETimer {
void *opaque;
void (*cb)(void *opaque);
int timeout;
struct QETimer *next;
};
static fd_set url_rfds, url_wfds;
static int url_fdmax;
static URLHandler url_handlers[256];
static int url_exit_request;
static LIST_HEAD(pid_handlers);
static LIST_HEAD(bottom_halves);
static QETimer *first_timer;
void set_read_handler(int fd, void (*cb)(void *opaque), void *opaque)
{
url_handlers[fd].read_cb = cb;
url_handlers[fd].read_opaque = opaque;
if (cb) {
if (fd >= url_fdmax)
url_fdmax = fd;
FD_SET((fdesc_t)fd, &url_rfds);
} else {
FD_CLR((fdesc_t)fd, &url_rfds);
}
}
void set_write_handler(int fd, void (*cb)(void *opaque), void *opaque)
{
url_handlers[fd].write_cb = cb;
url_handlers[fd].write_opaque = opaque;
if (cb) {
if (fd >= url_fdmax)
url_fdmax = fd;
FD_SET((fdesc_t)fd, &url_wfds);
} else {
FD_CLR((fdesc_t)fd, &url_wfds);
}
}
/* register a callback which is called when process 'pid'
terminates. When the callback is set to NULL, it is deleted */
/* XXX: add consistency check ? */
int set_pid_handler(int pid,
void (*cb)(void *opaque, int status), void *opaque)
{
PidHandler *p;
if (cb == NULL) {
list_for_each(p, &pid_handlers) {
if (p->pid == pid) {
list_del(p);
qe_free(&p);
break;
}
}
} else {
p = qe_malloc(PidHandler);
if (!p)
return -1;
p->pid = pid;
p->cb = cb;
p->opaque = opaque;
list_add(p, &pid_handlers);
}
return 0;
}
/*
* add an explicit call back to avoid recursions
*/
void register_bottom_half(void (*cb)(void *opaque), void *opaque)
{
BottomHalfEntry *bh;
/* Should not fail */
bh = qe_malloc(BottomHalfEntry);
bh->cb = cb;
bh->opaque = opaque;
list_add(bh, &bottom_halves);
}
/*
* remove bottom half
*/
void unregister_bottom_half(void (*cb)(void *opaque), void *opaque)
{
BottomHalfEntry *bh, *bh1;
list_for_each_safe(bh, bh1, &bottom_halves) {
if (bh->cb == cb && bh->opaque == opaque) {
list_del(bh);
qe_free(&bh);
}
}
}
QETimer *qe_add_timer(int delay, void *opaque, void (*cb)(void *opaque))
{
QETimer *ti;
ti = qe_malloc(QETimer);
if (!ti)
return NULL;
ti->timeout = get_clock_ms() + delay;
ti->opaque = opaque;
ti->cb = cb;
ti->next = first_timer;
first_timer = ti;
return ti;
}
void qe_kill_timer(QETimer *ti)
{
QETimer **pt;
pt = &first_timer;
while (*pt != NULL) {
if (*pt == ti) {
*pt = ti->next;
qe_free(&ti);
} else {
pt = &(*pt)->next;
}
}
}
/* execute stacked bottom halves */
static void __call_bottom_halves(void)
{
BottomHalfEntry *bh;
while (!list_empty(&bottom_halves)) {
bh = (BottomHalfEntry *)bottom_halves.prev;
list_del(bh);
bh->cb(bh->opaque);
qe_free(&bh);
}
}
static inline void call_bottom_halves(void)
{
if (!list_empty(&bottom_halves))
__call_bottom_halves();
}
/* call timer callbacks and compute maximum next call time to
check_timers() */
static inline int check_timers(int max_delay)
{
QETimer *ti, **pt;
int timeout, cur_time;
cur_time = get_clock_ms();
timeout = cur_time + max_delay;
pt = &first_timer;
for (;;) {
ti = *pt;
if (ti == NULL)
break;
if ((ti->timeout - cur_time) <= 0) {
/* timer expired : suppress it from timer list and call callback */
*pt = ti->next;
/* warning: a new timer can be added in the callback */
ti->cb(ti->opaque);
qe_free(&ti);
call_bottom_halves();
} else {
if ((ti->timeout - timeout) < 0)
timeout = ti->timeout;
pt = &ti->next;
}
}
return timeout - cur_time;
}
static void url_block_reset(void)
{
FD_ZERO(&url_rfds);
FD_ZERO(&url_wfds);
url_fdmax = -1;
url_exit_request = 0;
}
#define MAX_DELAY 500
/* block until one event */
static void url_block(void)
{
URLHandler *uh;
int ret, i, delay;
fd_set rfds, wfds;
struct timeval tv;
delay = check_timers(MAX_DELAY);
#if 0
{
static int count;
printf("%5d: delay=%d\n", count++, delay);
}
#endif
tv.tv_sec = delay / 1000;
tv.tv_usec = (delay % 1000) * 1000;
rfds = url_rfds;
wfds = url_wfds;
ret = select(url_fdmax + 1, &rfds, &wfds, NULL, &tv);
/* call each handler */
if (ret > 0) {
uh = url_handlers;
for (i = 0;i <= url_fdmax; i++) {
if (FD_ISSET(i, &rfds)) {
uh->read_cb(uh->read_opaque);
call_bottom_halves();
}
if (FD_ISSET(i, &wfds)) {
uh->write_cb(uh->write_opaque);
call_bottom_halves();
}
uh++;
}
}
#ifndef CONFIG_WIN32
/* handle terminated children */
for (;;) {
int pid, status;
PidHandler *ph, *ph1;
if (list_empty(&pid_handlers))
break;
pid = waitpid(-1, &status, WNOHANG);
if (pid <= 0)
break;
list_for_each_safe(ph, ph1, &pid_handlers) {
if (ph->pid == pid) {
ph->cb(ph->opaque, status);
call_bottom_halves();
break;
}
}
}
#endif
}
void url_main_loop(void (*init)(void *opaque), void *opaque)
{
url_block_reset();
init(opaque);
for (;;) {
if (url_exit_request)
break;
url_block();
}
}
/* exit from url loop */
void url_exit(void)
{
url_exit_request = 1;
}