⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sys_select.c

📁 OTP是开放电信平台的简称
💻 C
📖 第 1 页 / 共 2 页
字号:
/* ``The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in * compliance with the License. You should have received a copy of the * Erlang Public License along with this software. If not, it can be * retrieved via the world wide web at http://www.erlang.org/. *  * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. *  * The Initial Developer of the Original Code is Ericsson Utvecklings AB. * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings * AB. All Rights Reserved.'' *  *     $Id$ *//* * Purpose: driver_select() and friends. *//***********************************************************************  Roadmap to driver_select() & friends.  The driver_select() function is basically a call to  WaitForMultipleObjects().  But there are two problems  with the WFMO() function: It can only handle 64 objects,  and it will only point out the first element selected.  To work around these problems, this module uses one or  more threads (called "waiters"), each of which waits for 63 objects.  One object (the first one in the array) is use to force  the thread into a standby mode, when objects need to be  inspected, added or removed.  Each threads keeps two parallell arrays, one with events  and the other the port number and other needed information.  These arrays are organized as follows:     +-------------------+ \                \ 0   | Enter standby     |  |		     |     +-------------------+  |		     | 1   | Object 1   	 |  |		     |     +-------------------+  |		     | 2   | Object 2   	 |   > active_events |     +-------------------+  |		     |           .                |		     |	   .                |		     |	   .                |		      > total_events     +-------------------+  |		     |N-1  | Object N-1   	 | /		     |     +-------------------+  		     | N   | Object N          |		     |     +-------------------+		     |           .              		     |	   .               		     |	   .				     |     +-------------------+		     |N+M  | Object N+M        |		    /     +-------------------+  The first N objects are active, i.e. part of the array passed  to the WFMO().  The rest are objects already signaled.  When the thread discovers a new signaled object, it will swap it  with another object and decrement active_events.  The main emulator thread periodically orders all waiter threads  to enter standby mode.  Then the main thread call the callback  functions for all signaled objects in the upper end of each  array.  Finally, it sets active_events = total_events and  order all threads to start.***********************************************************************/#include "sys.h"#include "erl_alloc.h"#include "erl_driver.h"#if defined(__GNUC__)#  define WIN_SYS_INLINE __inline__#elif defined(__WIN32__)#  define WIN_SYS_INLINE __forceinline#endif/* * The following values are non-zero, constant, odd, large, and atypical. *      Non-zero values help find bugs assuming zero filled data. *      Constant values are good so that memory filling is deterministic *          (to help make bugs reproducable).  Of course it is bad if *          the constant filling of weird values masks a bug. *      Mathematically odd numbers are good for finding bugs assuming a cleared *          lower bit, as well as useful for trapping on the Mac. *      Large numbers (byte values at least) are less typical, and are good *          at finding bad addresses. *      Atypical values (i.e. not too often) are good since they typically *          cause early detection in code. *      For the case of no-man's land and free blocks, if you store to any *          of these locations, the memory integrity checker will detect it. */#define NoMansLandFill 0xFD	/* fill no-man's land with this */#define DeadLandFill   0xDD	/* fill free objects with this */#define CleanLandFill  0xCD	/* fill new objects with this */#define START_WAITER(w) \  if (in_win_check_io) \    ; \  else { \    SetEvent((w)->go_ahead); \  }#define STOP_WAITER(w) \  if (in_win_check_io) \    ; \  else { \    setup_standby_wait(1); \    SetEvent((w)->events[0]); \    wait_standby(); \  }#define START_WAITERS() \  if (in_win_check_io) \    ; \  else { \    int i; \    for (i = 0; i < num_waiters; i++) { \	SetEvent(waiter[i]->go_ahead); \    } \ }#define STOP_WAITERS() \  if (in_win_check_io) \    ; \  else { \    int i; \    setup_standby_wait(num_waiters); \    for (i = 0; i < num_waiters; i++) { \	SetEvent(waiter[i]->events[0]); \    } \    wait_standby(); \ } while (0)typedef void (*IoHandler)(int, int);typedef struct _EventData EventData;/* * Private functions. */static int set_driver_select(int port, HANDLE event, IoHandler handler);static int cancel_driver_select(HANDLE event);static void new_waiter(void);static void my_do_break(int, int);static DWORD WINAPI threaded_waiter(LPVOID param);#ifdef DEBUGstatic void consistency_check(struct _Waiter* w);static void* debug_alloc(ErtsAlcType_t, Uint);static void* debug_realloc(ErtsAlcType_t, void *, Uint);#  define SEL_ALLOC	debug_alloc#  define SEL_REALLOC	debug_realloc#  define SEL_FREE	erts_free#else#  define SEL_ALLOC	erts_alloc#  define SEL_REALLOC	realloc_wrap#  define SEL_FREE	erts_freestatic WIN_SYS_INLINE void *realloc_wrap(ErtsAlcType_t t, void *p, Uint ps, Uint s){    return erts_realloc(t, p, s);}#endifBOOL WINAPI ctrl_handler(DWORD);/* * External functions. */EXTERN_FUNCTION(void, input_ready, (int, int));EXTERN_FUNCTION(void, output_ready, (int, int));EXTERN_FUNCTION(void, erl_exit, (int n, char*, _DOTS_));EXTERN_FUNCTION(void, do_break, (void));/* * External variables. */extern int nohup;extern HANDLE erts_service_event;typedef struct _EventData {    HANDLE event;		/* For convenience. */    int port;			/* Port that the event belongs to, or -1 if no				 * no port. */        IoHandler handler;		/* The function be called when selected. */    int to_be_deleted;		/* Non-zero if a delayed cancellation is active. */    EventData* next;		/* Next in free or delete lists. */};typedef struct _Waiter {    /*     * In the events and evdata arrays, the 0th entry is used for getting     * the thread out of the WaitForMultipleObjects() call (auto-reset).     */    HANDLE events[MAXIMUM_WAIT_OBJECTS]; /* The events. */    EventData* evdata[MAXIMUM_WAIT_OBJECTS]; /* Pointers to associated data. */    int active_events;		/* Number of events to take part in				 * WaitForMultipleObjects().				 */    int total_events;		/* Total number of events in the arrays. */    /*     * This is an heap of EventData objects.  This is so that the evdata     * array can contain only pointers (for speed of exchanging events).     */    EventData evdata_heap[MAXIMUM_WAIT_OBJECTS];    EventData* first_free_evdata; /* Index of first free EventData object. */    /*     * The following event is set by the main emulator thread.     */    HANDLE go_ahead;		/* The waiter may continue. (Auto-reset) */} Waiter;static Waiter** waiter;static EventData* to_delete = NULL; /* List of delayed cancellations. */static int allocated_waiters;  /* Size ow waiter array */ static int num_waiters;		/* Number of waiter threads. */volatile int sys_io_ready;		/* Some I/O is ready. */HANDLE event_io_ready;	/* Same meaning as the variable. (Manual reset) */static volatile int in_win_check_io = FALSE;static void (*break_func)();static void (*quit_func)();static HANDLE break_event;static volatile int standby_wait_counter;static CRITICAL_SECTION standby_crit;static HANDLE standby_wait_event;void init_sys_select(void){    num_waiters = 0;    allocated_waiters = 64;    waiter = SEL_ALLOC(ERTS_ALC_T_WAITER_OBJ,		       sizeof(Waiter *)*allocated_waiters);    InitializeCriticalSection(&standby_crit);    standby_wait_counter = 0;    event_io_ready = CreateManualEvent(FALSE);    standby_wait_event = CreateManualEvent(FALSE);    break_event = CreateAutoEvent(FALSE);    set_driver_select(0, break_event, my_do_break);}static void setup_standby_wait(int num_threads){    EnterCriticalSection(&standby_crit);    standby_wait_counter = num_threads;    ResetEvent(standby_wait_event);    LeaveCriticalSection(&standby_crit);}static void signal_standby(void) {    EnterCriticalSection(&standby_crit);    --standby_wait_counter;    if (standby_wait_counter < 0) {	LeaveCriticalSection(&standby_crit);	erl_exit(1,"Standby signalled by more threads than expected");    }    if (!standby_wait_counter) {	SetEvent(standby_wait_event);    }    LeaveCriticalSection(&standby_crit);}static void wait_standby(void){    WaitForSingleObject(standby_wait_event,INFINITE);}/* ---------------------------------------------------------------------- * driver_select -- * 	Orders the emulator to inform the driver owning *	the filedescriptor when there is input available or output is possible. *   int port;      The port number.  *   HANDLE event;  The event to wait for.  *   int mode;	    Read or write mode.  *   int on;	    TRUE for enabling, FALSE for disabling. * * Results: *	None. * ---------------------------------------------------------------------- */int driver_select(ErlDrvPort xport, ErlDrvEvent xevent, int mode, int on){    unsigned long port = (unsigned long) xport;    HANDLE event = (HANDLE) xevent;    DEBUGF(("driver_select(%d, 0x%x, %d, %d)\n", port, event, mode, on));    ASSERT(event != INVALID_HANDLE_VALUE);    if (on) {	IoHandler func = 0;	if (mode & DO_READ) {	    func = input_ready;	} else if (mode & DO_WRITE) {	    func = output_ready;	}	ASSERT(func != 0);	if (func) {	    return set_driver_select(port, event, func);	}	return 0;    } else {	int result;	STOP_WAITERS();	result = cancel_driver_select(event);	START_WAITERS();	return result;    }}int driver_event(ErlDrvPort port, ErlDrvEvent event, ErlDrvEventData event_data){    return -1;}static int set_driver_select(int port, HANDLE event, IoHandler handler)     /*      * int port;			 The port number.      * HANDLE event;		         The event to wait for.       * IoHandler handler;		 Handler function to be called      *                                  when selected.      */{    int i;    int best_waiter = -1;	/* The waiter with lowest number of events. */    int lowest = MAXIMUM_WAIT_OBJECTS; /* Lowest number of events					* in any waiter.					*/    EventData* ev;    Waiter* w;    /*     * Find the waiter which is least busy.     */    for (i = 0; i < num_waiters; i++) {	if (waiter[i]->total_events < lowest) {	    lowest = waiter[i]->total_events;	    best_waiter = i;	}    }    /*     * Stop the selected waiter, or start a new waiter if all were busy.     */    if (best_waiter >= 0) {	w = waiter[best_waiter];	STOP_WAITER(w);    } else {	new_waiter();	w = waiter[num_waiters-1];    }#ifdef DEBUG    consistency_check(w);#endif    /*     * Allocate and initialize an EventData structure.     */    ev = w->first_free_evdata;    w->first_free_evdata = ev->next;    ev->event = event;    ev->port = port;    ev->handler = handler;    ev->to_be_deleted = FALSE;    ev->next = NULL;    /*     * At this point, the selected waiter (newly-created or not) is     * standing by.  Put the new event into the active part of the array.     */    if (w->active_events < w->total_events) {	/*	 * Move the first event beyond the active part of the array to	 * the very end to make place for the new event.	 */	w->events[w->total_events] = w->events[w->active_events];	w->evdata[w->total_events] = w->evdata[w->active_events];    }    w->events[w->active_events] = event;    w->evdata[w->active_events] = ev;    w->active_events++;    w->total_events++;#ifdef DEBUG    consistency_check(w);#endif    START_WAITER(w);    return 0;}static int cancel_driver_select(HANDLE event){    int i;    int result = -1;    ASSERT(event != INVALID_HANDLE_VALUE);    for (i = 0; i < num_waiters; i++) {	Waiter* w = waiter[i];	int j;#ifdef DEBUG	consistency_check(w);#endif	for (j = 0; j < w->total_events; j++) {	    if (w->events[j] == event) {		/*		 * If win_check_io() is active, we must delay the deletion.		 */		if (in_win_check_io) {		    /*		     * Note that an event might be cancelled several times.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -