diff -r 1d754a4ad350 -r 14b148d759ae linux-2.6-xen-sparse/arch/xen/Kconfig --- a/linux-2.6-xen-sparse/arch/xen/Kconfig Wed Nov 23 11:32:44 2005 +++ b/linux-2.6-xen-sparse/arch/xen/Kconfig Wed Nov 23 15:08:28 2005 @@ -38,6 +38,14 @@ (e.g., hard drives, network cards). This allows you to configure such devices and also includes some low-level support that is otherwise not compiled into the kernel. + +config XEN_IDC_TRACE + bool "Inter-domain communication code tracing" + default n + help + This option causes the IDC code to output a continual trace of its + activity. + Say N here unless you are trying to debug this code. config XEN_BLKDEV_BACKEND bool "Block-device backend driver" diff -r 1d754a4ad350 -r 14b148d759ae linux-2.6-xen-sparse/drivers/xen/Makefile --- a/linux-2.6-xen-sparse/drivers/xen/Makefile Wed Nov 23 11:32:44 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/Makefile Wed Nov 23 15:08:28 2005 @@ -7,6 +7,7 @@ obj-y += balloon/ obj-y += privcmd/ obj-y += xenbus/ +obj-y += xenidc/ obj-$(CONFIG_XEN_BLKDEV_BACKEND) += blkback/ obj-$(CONFIG_XEN_NETDEV_BACKEND) += netback/ diff -r 1d754a4ad350 -r 14b148d759ae linux-2.6-xen-sparse/drivers/xen/xenidc/Makefile --- /dev/null Wed Nov 23 11:32:44 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/Makefile Wed Nov 23 15:08:28 2005 @@ -0,0 +1,5 @@ +obj-y += xenidc.o + +xenidc-objs = +xenidc-objs += xenidc_callback.o +xenidc-objs += xenidc_work.o diff -r 1d754a4ad350 -r 14b148d759ae linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_callback.c --- /dev/null Wed Nov 23 11:32:44 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_callback.c Wed Nov 23 15:08:28 2005 @@ -0,0 +1,46 @@ +/*****************************************************************************/ +/* A callback object for use in scheduling completion of asynchronous */ +/* requests. */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program 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 General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +#include +#include "xenidc_callback.h" + +void xenidc_callback_serialiser_function(void *context) +{ + struct xenidc_callback_serialiser *serialiser = + (struct xenidc_callback_serialiser *)context; + unsigned long flags; + + spin_lock_irqsave(&serialiser->lock, flags); + while (!list_empty(&serialiser->list) && !serialiser->running) { + struct xenidc_callback *callback = + xenidc_callback_link_to(serialiser->list.next); + list_del_init(xenidc_callback_to_link(callback)); + serialiser->running = 1; + spin_unlock_irqrestore(&serialiser->lock, flags); + xenidc_callback_complete_synchronously(callback); + spin_lock_irqsave(&serialiser->lock, flags); + serialiser->running = 0; + } + spin_unlock_irqrestore(&serialiser->lock, flags); +} + +EXPORT_SYMBOL(xenidc_callback_serialiser_function); diff -r 1d754a4ad350 -r 14b148d759ae linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_trace.h --- /dev/null Wed Nov 23 11:32:44 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_trace.h Wed Nov 23 15:08:28 2005 @@ -0,0 +1,45 @@ +/*****************************************************************************/ +/* Simple trace macros. */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program 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 General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +#ifndef XENIDC_TRACE_H +#define XENIDC_TRACE_H + +#include +#include + +#if (defined(CONFIG_XEN_IDC_TRACE) || defined(XEN_IDC_TRACE)) + +#define trace_info(format, ...) \ +printk(KERN_INFO "xenidc %s: " format "\n", __FUNCTION__, ## __VA_ARGS__) +#define trace() trace_info( "" ) +/* The traceonly macro is used to enclose code which should only be compiled */ +/* in when tracing is enabled. */ +#define traceonly(S) S + +#else + +#define trace_info(format, ...) +#define trace() +#define traceonly(S) + +#endif + +#endif diff -r 1d754a4ad350 -r 14b148d759ae linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_work.c --- /dev/null Wed Nov 23 11:32:44 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_work.c Wed Nov 23 15:08:28 2005 @@ -0,0 +1,84 @@ +/*****************************************************************************/ +/* Enhanced work queue service */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program 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 General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +#include +#include "xenidc_work.h" + +static void xenidc_work_function(void *ignored); + +DEFINE_SPINLOCK(xenidc_work_list_lock); +LIST_HEAD(xenidc_work_list); +DECLARE_WORK(xenidc_work_work, xenidc_work_function, NULL); +DECLARE_WAIT_QUEUE_HEAD(xenidc_work_waitqueue); +LIST_HEAD(xenidc_work_condition); + +void xenidc_work_wake_up(void) +{ + unsigned long flags; + + spin_lock_irqsave(&xenidc_work_list_lock, flags); + while (!list_empty(&xenidc_work_condition)) + list_del_init(xenidc_work_condition.next); + spin_unlock_irqrestore(&xenidc_work_list_lock, flags); + wake_up(&xenidc_work_waitqueue); +} + +int xenidc_work_schedule(struct xenidc_work *work) +{ + int scheduled = 0; + unsigned long flags; + + spin_lock_irqsave(&xenidc_work_list_lock, flags); + if (list_empty(&work->link)) { + list_add_tail(&work->link, &xenidc_work_list); + scheduled = 1; + } + spin_unlock_irqrestore(&xenidc_work_list_lock, flags); + + if (scheduled) { + xenidc_work_wake_up(); + schedule_work(&xenidc_work_work); + } + + return scheduled; +} + +static void xenidc_work_function(void *ignored) +{ + unsigned long flags; + + spin_lock_irqsave(&xenidc_work_list_lock, flags); + while (!list_empty(&xenidc_work_list)) { + struct xenidc_work *work = list_entry(xenidc_work_list.next, + struct xenidc_work, + link); + list_del_init(&work->link); + spin_unlock_irqrestore(&xenidc_work_list_lock, flags); + xenidc_work_perform_synchronously(work); + spin_lock_irqsave(&xenidc_work_list_lock, flags); + } + spin_unlock_irqrestore(&xenidc_work_list_lock, flags); +} + +EXPORT_SYMBOL(xenidc_work_schedule); +EXPORT_SYMBOL(xenidc_work_list); +EXPORT_SYMBOL(xenidc_work_condition); +EXPORT_SYMBOL(xenidc_work_waitqueue); +EXPORT_SYMBOL(xenidc_work_wake_up); diff -r 1d754a4ad350 -r 14b148d759ae linux-2.6-xen-sparse/include/asm-xen/xenidc_callback.h --- /dev/null Wed Nov 23 11:32:44 2005 +++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_callback.h Wed Nov 23 15:08:28 2005 @@ -0,0 +1,152 @@ +/*****************************************************************************/ +/* A callback object for use in scheduling completion of asynchronous */ +/* requests. */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program 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 General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +#ifndef XENIDC_CALLBACK_H +#define XENIDC_CALLBACK_H + +#include +#include "xenidc_error.h" +#include "xenidc_work.h" + +/* Service parameter blocks contain callbacks for asynchronous completions. */ + +struct xenidc_callback { + struct xenidc_work work; + xenidc_error error; +}; + +#define XENIDC_CALLBACK_LINK work.XENIDC_WORK_LINK + +/* Client of service initialises callback with its callback function. */ + +typedef void xenidc_callback_function(struct xenidc_callback *callback); + +static inline void +xenidc_callback_init(struct xenidc_callback *callback, +xenidc_callback_function *function) +{ + xenidc_work_init(&callback->work, (void (*)(void *))function, + callback); + callback->error = XENIDC_ERROR_SUCCESS; +} + +/* Client may use link whilst it owns parameter block. Service may use link */ +/* whilst it owns parameter block. Link is reserved whilst callback is */ +/* scheduled for completion. */ + +static inline struct list_head * +xenidc_callback_to_link(struct xenidc_callback *callback) +{ + return xenidc_work_to_link(&callback->work); +} + +/* Cast back from contained link of callback to callback. */ + +static inline struct xenidc_callback * +xenidc_callback_link_to(struct list_head *link) +{ + return container_of(xenidc_work_link_to(link), struct xenidc_callback, + work); +} + +/* Service which completes requests concurrently may call */ +/* xenidc_callback_complete or xenidc_callback_success to complete the */ +/* callback. */ + +static inline void +xenidc_callback_complete(struct xenidc_callback *callback, xenidc_error error) +{ + callback->error = error; + xenidc_work_schedule(&callback->work); +} + +static inline void +xenidc_callback_success(struct xenidc_callback *callback) +{ + xenidc_callback_complete(callback, 0); +} + +/* These functions used by serialiser below. */ + +static inline void +xenidc_callback_set_error(struct xenidc_callback *callback, +xenidc_error error) +{ + callback->error = error; +} + +static inline void +xenidc_callback_complete_synchronously(struct xenidc_callback *callback) +{ + xenidc_work_perform_synchronously(&callback->work); +} + +/* When callback completes, client may call xenidc_callback_query_error to */ +/* get the error code. */ + +static inline xenidc_error +xenidc_callback_query_error(struct xenidc_callback *callback) +{ + return callback->error; +} + +/* Services which must serialise completions to preserve submission order */ +/* can use one of these. */ + +struct xenidc_callback_serialiser { + spinlock_t lock; + struct list_head list; + struct xenidc_work work; + int running; +}; + +void xenidc_callback_serialiser_function(void *context); + +#define XENIDC_CALLBACK_SERIALISER_INIT( name ) { \ + .lock = SPIN_LOCK_UNLOCKED, \ + .list = LIST_HEAD_INIT( name.list ), \ + .work = XENIDC_WORK_INIT \ + ( name.work, xenidc_callback_serialiser_function, &name ),\ + .running = 0 \ +} + +#define XENIDC_CALLBACK_SERIALISER( name ) \ +struct xenidc_callback_serialiser name = \ +XENIDC_CALLBACK_SERIALISER_INIT( name ) + +/* The service completes the callback to the serialiser which serialises the */ +/* completions to the client, performing them in submission order. */ + +static inline void +xenidc_callback_serialiser_complete_callback( +struct xenidc_callback_serialiser *serialiser, +struct xenidc_callback *callback, xenidc_error error) +{ + unsigned long flags; + xenidc_callback_set_error(callback, error); + spin_lock_irqsave(&serialiser->lock, flags); + list_add_tail(xenidc_callback_to_link(callback), &serialiser->list); + spin_unlock_irqrestore(&serialiser->lock, flags); + xenidc_work_schedule(&serialiser->work); +} + +#endif diff -r 1d754a4ad350 -r 14b148d759ae linux-2.6-xen-sparse/include/asm-xen/xenidc_error.h --- /dev/null Wed Nov 23 11:32:44 2005 +++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_error.h Wed Nov 23 15:08:28 2005 @@ -0,0 +1,121 @@ +/*****************************************************************************/ +/* The xenidc_error type is supposed to be safe for use on the wire between */ +/* different operating systems which may use different values for the posix */ +/* error types or may not even use the posix error types at all. */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program 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 General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ +/* */ +/* Ideally, we'd simply define all the error values we needed here and map */ +/* the local error values to those and back again. In practice, we are */ +/* building on top of another operating system which has its own set of */ +/* error values and driver interfaces which don't define precisely which */ +/* ones may be returned under what conditions. */ +/* */ +/* Some error return values are significant for the operation of the */ +/* inter-domain protocols and some are not. In general, the correct mapping */ +/* of protocol-significant error values between operating systems may be a */ +/* function of the protocol. */ +/* */ +/* The strategy adopted here is to allow individual protocols to extract the */ +/* error return values which are significant to them and map them into a */ +/* range of error values reserved for protocol use. Any values not */ +/* specifically significant to a protocol are handled by the fallback */ +/* mapping code in this file. */ +/* */ +/* This makes it possible to construct a mapping as a function of protocol */ +/* and allows us to avoid discarding potentially useful error code */ +/* information in the general case. */ +/* */ +/* For the fallback case of any error codes we are not specifically */ +/* interested in for a protocol-specific purpose we use the linux definition */ +/* of the posix error values. Other operating systems will need their own */ +/* equivalent of this file to map their error values to and from these. */ + +#ifndef __ASM_XEN_XENIDC_ERROR_H__ +#define __ASM_XEN_XENIDC_ERROR_H__ + +#include +#include + +typedef s32 xenidc_error; + +/* The error values we single out with some OS independent, protocol */ +/* specific meaning are all positive. The negative ones are all potentially */ +/* OS specific and might not have an exact representation in the local OS. */ +/* Assuming we have singled out the right ones in the protocol specific code */ +/* this shouldn't matter. */ + +/* The first few error numbers are reserved for success and transport errors */ +/* which are common to all IDC protocols. */ + +#define XENIDC_ERROR_SUCCESS (xenidc_error)0 +#define XENIDC_ERROR_FAILURE (xenidc_error)1 +#define XENIDC_ERROR_DISCONNECT (xenidc_error)2 +/* Unexpected transaction/transaction in wrong sequence, underlength etc: */ +#define XENIDC_ERROR_INVALID_PROTOCOL (xenidc_error)3 +/* Parameter value wrong: */ +#define XENIDC_ERROR_INVALID_PARAMETER (xenidc_error)4 +/* Something about a request exceeded a hard-coded limit: */ +#define XENIDC_ERROR_TOO_BIG (xenidc_error)5 + +/* Protocols can define their own set of protocol specific errors starting */ +/* at this one. The driver code on either side must translate between the */ +/* local OS specific error codes and the protocol specific error codes. */ + +#define XENIDC_ERROR_PROTOCOL_SPECIFIC_FIRST (xenidc_error)1024 + +/* These functions map between the wire error type and the local error type. */ + +static inline xenidc_error xenidc_error_map_local_to(int error) +{ + switch (error) { + case 0: + return XENIDC_ERROR_SUCCESS; + case -ENOTCONN: + return XENIDC_ERROR_DISCONNECT; + case -EPROTO: + return XENIDC_ERROR_INVALID_PROTOCOL; + case -EINVAL: + return XENIDC_ERROR_INVALID_PARAMETER; + case -E2BIG: + return XENIDC_ERROR_TOO_BIG; + default: + return (xenidc_error)error; + } +} + +static inline int xenidc_error_map_to_local(xenidc_error error) +{ + switch (error) { + case XENIDC_ERROR_SUCCESS: + return 0; + case XENIDC_ERROR_DISCONNECT: + return -ENOTCONN; + case XENIDC_ERROR_INVALID_PROTOCOL: + return -EPROTO; + case XENIDC_ERROR_INVALID_PARAMETER: + return -EINVAL; + case XENIDC_ERROR_TOO_BIG: + return -E2BIG; + default: + return (int)error; + } +} + +#endif diff -r 1d754a4ad350 -r 14b148d759ae linux-2.6-xen-sparse/include/asm-xen/xenidc_work.h --- /dev/null Wed Nov 23 11:32:44 2005 +++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_work.h Wed Nov 23 15:08:28 2005 @@ -0,0 +1,153 @@ +/*****************************************************************************/ +/* Enhanced work queue service which allows work items to wait for */ +/* conditions met by other work items. */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program 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 General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +/* This work queue service is a lot like the linux work queue service except */ +/* that it provides the interface xenidc_work_until which allows the client */ +/* to wait for a condition to be met even when the client is executing on a */ +/* work thread and the condition will only be satisfied by execution of */ +/* another work item. */ +/* */ +/* The other significant difference is that xenidc_work work items are run */ +/* by multiple threads (threads waiting in xenidc_work_until() run */ +/* work_items until their condition is met) so it's possible for a work item */ +/* to be executed multiple times concurrently and clients must use locking */ +/* to protect against this where necessary. */ + +#ifndef XENIDC_WORK_H +#define XENIDC_WORK_H + +#include +#include +#include +#include +#include + +/* Clients allocate xenidc_work work items to use the service. */ + +struct xenidc_work { + struct list_head link; + void (*function) (void *context); + void *context; +}; + +/* The xenidc_work object contains a link for use by the service whist the */ +/* work item is scheduled. The link may be used by the client whilst the */ +/* work item is not scheduled. The link is initialised by the init function */ +/* and must be left initialised if used by the client. */ + +#define XENIDC_WORK_LINK link + +/* Macro for initialisation of static xenidc_work objects. */ + +#define XENIDC_WORK_INIT( name, fn, ctx ) \ +{ .link = LIST_HEAD_INIT( name.link ), .function = fn, .context = ctx } + +/* Macro to declare a static xenidc_work object. */ + +#define XENIDC_WORK( name, fn, ctx ) \ +struct xenidc_work name = XENIDC_WORK_INIT( name, fn, ctx ) + +static inline void +xenidc_work_init(struct xenidc_work *work, void (*function) (void *context), +void *context) +{ + INIT_LIST_HEAD(&work->link); + work->function = function; + work->context = context; +} + +/* Cast xenidc_work object to contained link. */ + +static inline struct list_head *xenidc_work_to_link(struct xenidc_work *work) +{ + return &work->link; +} + +/* Cast contained link of xenidc_work object back to xenidc_work object. */ + +static inline struct xenidc_work *xenidc_work_link_to(struct list_head *link) +{ + return container_of(link, struct xenidc_work, link); +} + +/* Schedule a xenidc_work object for later execution. It is legal to call */ +/* this even if the object is already scheduled. Returns 1 if scheduled this */ +/* time or 0 if already scheduled. */ + +int xenidc_work_schedule(struct xenidc_work *work); + +/* Perform the task represented by the xenidc_work object synchronously on */ +/* the callers thread. */ + +static inline void xenidc_work_perform_synchronously(struct xenidc_work *work) +{ + work->function(work->context); +} + +/* Don't use any of these, they're just exposed for the macro below. */ + +extern spinlock_t xenidc_work_list_lock; +extern struct list_head xenidc_work_list; +extern wait_queue_head_t xenidc_work_waitqueue; +extern struct list_head xenidc_work_condition; + +/* Wait for a condition to be met. This works whether or not you call it */ +/* from a work item and works even when the condition will only be satisfied */ +/* by another work item. */ + +#define xenidc_work_until( condition ) \ +do { \ + unsigned long flags; \ + \ + spin_lock_irqsave(&xenidc_work_list_lock, flags); \ + for (;;) { \ + struct list_head link; \ + \ + while (!list_empty(&xenidc_work_list) && !(condition)) { \ + struct xenidc_work *work; \ + work = list_entry(xenidc_work_list.next, \ + xenidc_work, link); \ + list_del_init(&work->link); \ + spin_unlock_irqrestore(&xenidc_work_list_lock, flags);\ + xenidc_work_perform_synchronously(work); \ + spin_lock_irqsave(&xenidc_work_list_lock, flags); \ + } \ + \ + if (condition) \ + break; \ + \ + INIT_LIST_HEAD(&link); \ + list_add_tail(&link, &xenidc_work_condition); \ + spin_unlock_irqrestore(&xenidc_work_list_lock, flags); \ + wait_event(xenidc_work_waitqueue, list_empty(&link)); \ + spin_lock_irqsave(&xenidc_work_list_lock, flags); \ + } \ + spin_unlock_irqrestore(&xenidc_work_list_lock, flags); \ +} \ +while (0) + +/* When you satisfy a condition, you should call this to kick any threads */ +/* waiting on the condition. */ + +void xenidc_work_wake_up(void); + +#endif