aboutsummaryrefslogtreecommitdiffstats
path: root/libs/subcircuit/subcircuit.h
blob: 8368efab138aca5c7f7ff154b30ead4d0534d716 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
/*
 *  SubCircuit -- An implementation of the Ullmann Subgraph Isomorphism
 *                algorithm for coarse grain logic networks
 *
 *  Copyright (C) 2013  Clifford Wolf <clifford@clifford.at>
 *
 *  Permission to use, copy, modify, and/or distribute this software for any
 *  purpose with or without fee is hereby granted, provided that the above
 *  copyright notice and this permission notice appear in all copies.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

#ifndef SUBCIRCUIT_H
#define SUBCIRCUIT_H

#include <string>
#include <vector>
#include <set>
#include <map>

namespace SubCircuit
{
	class SolverWorker;

	class Graph
	{
	protected:
		struct BitRef {
			int nodeIdx, portIdx, bitIdx;
			BitRef(int nodeIdx = -1, int portIdx = -1, int bitIdx = -1) : nodeIdx(nodeIdx), portIdx(portIdx), bitIdx(bitIdx) { };
			bool operator < (const BitRef &other) const;
		};

		struct Edge {
			std::set<BitRef> portBits;
			int constValue;
			bool isExtern;
			Edge() : constValue(0), isExtern(false) { };
		};

		struct PortBit {
			int edgeIdx;
			PortBit() : edgeIdx(-1) { };
		};

		struct Port {
			std::string portId;
			int minWidth;
			std::vector<PortBit> bits;
			Port() : minWidth(-1) { };
		};

		struct Node {
			std::string nodeId, typeId;
			std::map<std::string, int> portMap;
			std::vector<Port> ports;
			void *userData;
			bool shared;
			Node() : userData(NULL), shared(false) { };
		};

		bool allExtern;
		std::map<std::string, int> nodeMap;
		std::vector<Node> nodes;
		std::vector<Edge> edges;

	public:
		Graph() : allExtern(false) { };
		Graph(const Graph &other, const std::vector<std::string> &otherNodes);

		void createNode(std::string nodeId, std::string typeId, void *userData = NULL, bool shared = false);
		void createPort(std::string nodeId, std::string portId, int width = 1, int minWidth = -1);
		void createConnection(std::string fromNodeId, std::string fromPortId, int fromBit, std::string toNodeId, std::string toPortId, int toBit, int width = 1);
		void createConnection(std::string fromNodeId, std::string fromPortId, std::string toNodeId, std::string toPortId);
		void createConstant(std::string toNodeId, std::string toPortId, int toBit, int constValue);
		void createConstant(std::string toNodeId, std::string toPortId, int constValue);
		void markExtern(std::string nodeId, std::string portId, int bit = -1);
		void markAllExtern();
		void print();

		friend class SolverWorker;
	};

	class Solver
	{
	public:
		struct ResultNodeMapping {
			std::string needleNodeId, haystackNodeId;
			void *needleUserData, *haystackUserData;
			std::map<std::string, std::string> portMapping;
		};
		struct Result {
			std::string needleGraphId, haystackGraphId;
			std::map<std::string, ResultNodeMapping> mappings;
		};

		struct MineResultNode {
			std::string nodeId;
			void *userData;
		};
		struct MineResult {
			std::string graphId;
			int totalMatchesAfterLimits;
			std::map<std::string, int> matchesPerGraph;
			std::vector<MineResultNode> nodes;
		};

	private:
		SolverWorker *worker;

	protected:
		virtual bool userCompareNodes(const std::string &needleGraphId, const std::string &needleNodeId, void *needleUserData,
				const std::string &haystackGraphId, const std::string &haystackNodeId, void *haystackUserData, const std::map<std::string, std::string> &portMapping);

		virtual std::string userAnnotateEdge(const std::string &graphId, const std::string &fromNodeId, void *fromUserData, const std::string &toNodeId, void *toUserData);

		virtual bool userCompareEdge(const std::string &needleGraphId, const std::string &needleFromNodeId, void *needleFromUserData, const std::string &needleToNodeId, void *needleToUserData,
				const std::string &haystackGraphId, const std::string &haystackFromNodeId, void *haystackFromUserData, const std::string &haystackToNodeId, void *haystackToUserData);

		virtual bool userCheckSolution(const Result &result);

		friend class SolverWorker;

	public:
		Solver();
		virtual ~Solver();

		void setVerbose();
		void addGraph(std::string graphId, const Graph &graph);
		void addCompatibleTypes(std::string needleTypeId, std::string haystackTypeId);
		void addCompatibleConstants(int needleConstant, int haystackConstant);
		void addSwappablePorts(std::string needleTypeId, std::string portId1, std::string portId2, std::string portId3 = std::string(), std::string portId4 = std::string());
		void addSwappablePorts(std::string needleTypeId, std::set<std::string> ports);
		void addSwappablePortsPermutation(std::string needleTypeId, std::map<std::string, std::string> portMapping);

		void solve(std::vector<Result> &results, std::string needleGraphId, std::string haystackGraphId, bool allowOverlap = true, int maxSolutions = -1);
		void solve(std::vector<Result> &results, std::string needleGraphId, std::string haystackGraphId,
				const std::map<std::string, std::set<std::string>> &initialMapping, bool allowOverlap = true, int maxSolutions = -1);

		void mine(std::vector<MineResult> &results, int minNodes, int maxNodes, int minMatches, int limitMatchesPerGraph = -1);

		void clearOverlapHistory();
		void clearConfig();
	};
}

#endif /* SUBCIRCUIT_H */
cp"> /* xenbus_probe.c */ extern char *kasprintf(const char *fmt, ...); struct xs_stored_msg { struct list_head list; struct xsd_sockmsg hdr; union { /* Queued replies. */ struct { char *body; } reply; /* Queued watch events. */ struct { struct xenbus_watch *handle; char **vec; unsigned int vec_size; } watch; } u; }; struct xs_handle { /* A list of replies. Currently only one will ever be outstanding. */ struct list_head reply_list; spinlock_t reply_lock; wait_queue_head_t reply_waitq; /* One request at a time. */ struct mutex request_mutex; /* Protect transactions against save/restore. */ struct rw_semaphore suspend_mutex; }; static struct xs_handle xs_state; /* List of registered watches, and a lock to protect it. */ static LIST_HEAD(watches); static DEFINE_SPINLOCK(watches_lock); /* List of pending watch callback events, and a lock to protect it. */ static LIST_HEAD(watch_events); static DEFINE_SPINLOCK(watch_events_lock); /* * Details of the xenwatch callback kernel thread. The thread waits on the * watch_events_waitq for work to do (queued on watch_events list). When it * wakes up it acquires the xenwatch_mutex before reading the list and * carrying out work. */ static pid_t xenwatch_pid; /* static */ DEFINE_MUTEX(xenwatch_mutex); static DECLARE_WAIT_QUEUE_HEAD(watch_events_waitq); static int get_error(const char *errorstring) { unsigned int i; for (i = 0; strcmp(errorstring, xsd_errors[i].errstring) != 0; i++) { if (i == ARRAY_SIZE(xsd_errors) - 1) { printk(KERN_WARNING "XENBUS xen store gave: unknown error %s", errorstring); return EINVAL; } } return xsd_errors[i].errnum; } static void *read_reply(enum xsd_sockmsg_type *type, unsigned int *len) { struct xs_stored_msg *msg; char *body; spin_lock(&xs_state.reply_lock); while (list_empty(&xs_state.reply_list)) { spin_unlock(&xs_state.reply_lock); /* XXX FIXME: Avoid synchronous wait for response here. */ wait_event(xs_state.reply_waitq, !list_empty(&xs_state.reply_list)); spin_lock(&xs_state.reply_lock); } msg = list_entry(xs_state.reply_list.next, struct xs_stored_msg, list); list_del(&msg->list); spin_unlock(&xs_state.reply_lock); *type = msg->hdr.type; if (len) *len = msg->hdr.len; body = msg->u.reply.body; kfree(msg); return body; } /* Emergency write. */ void xenbus_debug_write(const char *str, unsigned int count) { struct xsd_sockmsg msg = { 0 }; msg.type = XS_DEBUG; msg.len = sizeof("print") + count + 1; mutex_lock(&xs_state.request_mutex); xb_write(&msg, sizeof(msg)); xb_write("print", sizeof("print")); xb_write(str, count); xb_write("", 1); mutex_unlock(&xs_state.request_mutex); } void *xenbus_dev_request_and_reply(struct xsd_sockmsg *msg) { void *ret; struct xsd_sockmsg req_msg = *msg; int err; if (req_msg.type == XS_TRANSACTION_START) down_read(&xs_state.suspend_mutex); mutex_lock(&xs_state.request_mutex); err = xb_write(msg, sizeof(*msg) + msg->len); if (err) { msg->type = XS_ERROR; ret = ERR_PTR(err); } else ret = read_reply(&msg->type, &msg->len); mutex_unlock(&xs_state.request_mutex); if ((req_msg.type == XS_TRANSACTION_END) || ((req_msg.type == XS_TRANSACTION_START) && (msg->type == XS_ERROR))) up_read(&xs_state.suspend_mutex); return ret; } /* Send message to xs, get kmalloc'ed reply. ERR_PTR() on error. */ static void *xs_talkv(xenbus_transaction_t t, enum xsd_sockmsg_type type, const struct kvec *iovec, unsigned int num_vecs, unsigned int *len) { struct xsd_sockmsg msg; void *ret = NULL; unsigned int i; int err; msg.tx_id = t; msg.req_id = 0; msg.type = type; msg.len = 0; for (i = 0; i < num_vecs; i++) msg.len += iovec[i].iov_len; mutex_lock(&xs_state.request_mutex); err = xb_write(&msg, sizeof(msg)); if (err) { mutex_unlock(&xs_state.request_mutex); return ERR_PTR(err); } for (i = 0; i < num_vecs; i++) { err = xb_write(iovec[i].iov_base, iovec[i].iov_len);; if (err) { mutex_unlock(&xs_state.request_mutex); return ERR_PTR(err); } } ret = read_reply(&msg.type, len); mutex_unlock(&xs_state.request_mutex); if (IS_ERR(ret)) return ret; if (msg.type == XS_ERROR) { err = get_error(ret); kfree(ret); return ERR_PTR(-err); } if (msg.type != type) { if (printk_ratelimit()) printk(KERN_WARNING "XENBUS unexpected type [%d], expected [%d]\n", msg.type, type); kfree(ret); return ERR_PTR(-EINVAL); } return ret; } /* Simplified version of xs_talkv: single message. */ static void *xs_single(xenbus_transaction_t t, enum xsd_sockmsg_type type, const char *string, unsigned int *len) { struct kvec iovec; iovec.iov_base = (void *)string; iovec.iov_len = strlen(string) + 1; return xs_talkv(t, type, &iovec, 1, len); } /* Many commands only need an ack, don't care what it says. */ static int xs_error(char *reply) { if (IS_ERR(reply)) return PTR_ERR(reply); kfree(reply); return 0; } static unsigned int count_strings(const char *strings, unsigned int len) { unsigned int num; const char *p; for (p = strings, num = 0; p < strings + len; p += strlen(p) + 1) num++; return num; } /* Return the path to dir with /name appended. Buffer must be kfree()'ed. */ static char *join(const char *dir, const char *name) { char *buffer; if (strlen(name) == 0) buffer = kasprintf("%s", dir); else buffer = kasprintf("%s/%s", dir, name); return (!buffer) ? ERR_PTR(-ENOMEM) : buffer; } static char **split(char *strings, unsigned int len, unsigned int *num) { char *p, **ret; /* Count the strings. */ *num = count_strings(strings, len); /* Transfer to one big alloc for easy freeing. */ ret = kmalloc(*num * sizeof(char *) + len, GFP_KERNEL); if (!ret) { kfree(strings); return ERR_PTR(-ENOMEM); } memcpy(&ret[*num], strings, len); kfree(strings); strings = (char *)&ret[*num]; for (p = strings, *num = 0; p < strings + len; p += strlen(p) + 1) ret[(*num)++] = p; return ret; } char **xenbus_directory(xenbus_transaction_t t, const char *dir, const char *node, unsigned int *num) { char *strings, *path; unsigned int len; path = join(dir, node); if (IS_ERR(path)) return (char **)path; strings = xs_single(t, XS_DIRECTORY, path, &len); kfree(path); if (IS_ERR(strings)) return (char **)strings; return split(strings, len, num); } EXPORT_SYMBOL_GPL(xenbus_directory); /* Check if a path exists. Return 1 if it does. */ int xenbus_exists(xenbus_transaction_t t, const char *dir, const char *node) { char **d; int dir_n; d = xenbus_directory(t, dir, node, &dir_n); if (IS_ERR(d)) return 0; kfree(d); return 1; } EXPORT_SYMBOL_GPL(xenbus_exists); /* Get the value of a single file. * Returns a kmalloced value: call free() on it after use. * len indicates length in bytes. */ void *xenbus_read(xenbus_transaction_t t, const char *dir, const char *node, unsigned int *len) { char *path; void *ret; path = join(dir, node); if (IS_ERR(path)) return (void *)path; ret = xs_single(t, XS_READ, path, len); kfree(path); return ret; } EXPORT_SYMBOL_GPL(xenbus_read); /* Write the value of a single file. * Returns -err on failure. */ int xenbus_write(xenbus_transaction_t t, const char *dir, const char *node, const char *string) { const char *path; struct kvec iovec[2]; int ret; path = join(dir, node); if (IS_ERR(path)) return PTR_ERR(path); iovec[0].iov_base = (void *)path; iovec[0].iov_len = strlen(path) + 1; iovec[1].iov_base = (void *)string; iovec[1].iov_len = strlen(string); ret = xs_error(xs_talkv(t, XS_WRITE, iovec, ARRAY_SIZE(iovec), NULL)); kfree(path); return ret; } EXPORT_SYMBOL_GPL(xenbus_write); /* Create a new directory. */ int xenbus_mkdir(xenbus_transaction_t t, const char *dir, const char *node) { char *path; int ret; path = join(dir, node); if (IS_ERR(path)) return PTR_ERR(path); ret = xs_error(xs_single(t, XS_MKDIR, path, NULL)); kfree(path); return ret; } EXPORT_SYMBOL_GPL(xenbus_mkdir); /* Destroy a file or directory (directories must be empty). */ int xenbus_rm(xenbus_transaction_t t, const char *dir, const char *node) { char *path; int ret; path = join(dir, node); if (IS_ERR(path)) return PTR_ERR(path); ret = xs_error(xs_single(t, XS_RM, path, NULL)); kfree(path); return ret; } EXPORT_SYMBOL_GPL(xenbus_rm); /* Start a transaction: changes by others will not be seen during this * transaction, and changes will not be visible to others until end. */ int xenbus_transaction_start(xenbus_transaction_t *t) { char *id_str; down_read(&xs_state.suspend_mutex); id_str = xs_single(XBT_NULL, XS_TRANSACTION_START, "", NULL); if (IS_ERR(id_str)) { up_read(&xs_state.suspend_mutex); return PTR_ERR(id_str); } *t = simple_strtoul(id_str, NULL, 0); kfree(id_str); return 0; } EXPORT_SYMBOL_GPL(xenbus_transaction_start); /* End a transaction. * If abandon is true, transaction is discarded instead of committed. */ int xenbus_transaction_end(xenbus_transaction_t t, int abort) { char abortstr[2]; int err; if (abort) strcpy(abortstr, "F"); else strcpy(abortstr, "T"); err = xs_error(xs_single(t, XS_TRANSACTION_END, abortstr, NULL)); up_read(&xs_state.suspend_mutex); return err; } EXPORT_SYMBOL_GPL(xenbus_transaction_end); /* Single read and scanf: returns -errno or num scanned. */ int xenbus_scanf(xenbus_transaction_t t, const char *dir, const char *node, const char *fmt, ...) { va_list ap; int ret; char *val; val = xenbus_read(t, dir, node, NULL); if (IS_ERR(val)) return PTR_ERR(val); va_start(ap, fmt); ret = vsscanf(val, fmt, ap); va_end(ap); kfree(val); /* Distinctive errno. */ if (ret == 0) return -ERANGE; return ret; } EXPORT_SYMBOL_GPL(xenbus_scanf); /* Single printf and write: returns -errno or 0. */ int xenbus_printf(xenbus_transaction_t t, const char *dir, const char *node, const char *fmt, ...) { va_list ap; int ret; #define PRINTF_BUFFER_SIZE 4096 char *printf_buffer; printf_buffer = kmalloc(PRINTF_BUFFER_SIZE, GFP_KERNEL); if (printf_buffer == NULL) return -ENOMEM; va_start(ap, fmt); ret = vsnprintf(printf_buffer, PRINTF_BUFFER_SIZE, fmt, ap); va_end(ap); BUG_ON(ret > PRINTF_BUFFER_SIZE-1); ret = xenbus_write(t, dir, node, printf_buffer); kfree(printf_buffer); return ret; } EXPORT_SYMBOL_GPL(xenbus_printf); /* Takes tuples of names, scanf-style args, and void **, NULL terminated. */ int xenbus_gather(xenbus_transaction_t t, const char *dir, ...) { va_list ap; const char *name; int ret = 0; va_start(ap, dir); while (ret == 0 && (name = va_arg(ap, char *)) != NULL) { const char *fmt = va_arg(ap, char *); void *result = va_arg(ap, void *); char *p; p = xenbus_read(t, dir, name, NULL); if (IS_ERR(p)) { ret = PTR_ERR(p); break; } if (fmt) { if (sscanf(p, fmt, result) == 0) ret = -EINVAL; kfree(p); } else *(char **)result = p; } va_end(ap); return ret; } EXPORT_SYMBOL_GPL(xenbus_gather); static int xs_watch(const char *path, const char *token) { struct kvec iov[2]; iov[0].iov_base = (void *)path; iov[0].iov_len = strlen(path) + 1; iov[1].iov_base = (void *)token; iov[1].iov_len = strlen(token) + 1; return xs_error(xs_talkv(XBT_NULL, XS_WATCH, iov, ARRAY_SIZE(iov), NULL)); } static int xs_unwatch(const char *path, const char *token) { struct kvec iov[2]; iov[0].iov_base = (char *)path; iov[0].iov_len = strlen(path) + 1; iov[1].iov_base = (char *)token; iov[1].iov_len = strlen(token) + 1; return xs_error(xs_talkv(XBT_NULL, XS_UNWATCH, iov, ARRAY_SIZE(iov), NULL)); } static struct xenbus_watch *find_watch(const char *token) { struct xenbus_watch *i, *cmp; cmp = (void *)simple_strtoul(token, NULL, 16); list_for_each_entry(i, &watches, list) if (i == cmp) return i; return NULL; } /* Register callback to watch this node. */ int register_xenbus_watch(struct xenbus_watch *watch) { /* Pointer in ascii is the token. */ char token[sizeof(watch) * 2 + 1]; int err; sprintf(token, "%lX", (long)watch); down_read(&xs_state.suspend_mutex); spin_lock(&watches_lock); BUG_ON(find_watch(token)); list_add(&watch->list, &watches); spin_unlock(&watches_lock); err = xs_watch(watch->node, token); /* Ignore errors due to multiple registration. */ if ((err != 0) && (err != -EEXIST)) { spin_lock(&watches_lock); list_del(&watch->list); spin_unlock(&watches_lock); } up_read(&xs_state.suspend_mutex); return err; } EXPORT_SYMBOL_GPL(register_xenbus_watch); void unregister_xenbus_watch(struct xenbus_watch *watch) { struct xs_stored_msg *msg, *tmp; char token[sizeof(watch) * 2 + 1]; int err; sprintf(token, "%lX", (long)watch); down_read(&xs_state.suspend_mutex); spin_lock(&watches_lock); BUG_ON(!find_watch(token)); list_del(&watch->list); spin_unlock(&watches_lock); err = xs_unwatch(watch->node, token); if (err) printk(KERN_WARNING "XENBUS Failed to release watch %s: %i\n", watch->node, err); up_read(&xs_state.suspend_mutex); /* Cancel pending watch events. */ spin_lock(&watch_events_lock); list_for_each_entry_safe(msg, tmp, &watch_events, list) { if (msg->u.watch.handle != watch) continue; list_del(&msg->list); kfree(msg->u.watch.vec); kfree(msg); } spin_unlock(&watch_events_lock); /* Flush any currently-executing callback, unless we are it. :-) */ if (current->pid != xenwatch_pid) { mutex_lock(&xenwatch_mutex); mutex_unlock(&xenwatch_mutex); } } EXPORT_SYMBOL_GPL(unregister_xenbus_watch); void xs_suspend(void) { down_write(&xs_state.suspend_mutex); mutex_lock(&xs_state.request_mutex); } void xs_resume(void) { struct xenbus_watch *watch; char token[sizeof(watch) * 2 + 1]; mutex_unlock(&xs_state.request_mutex); /* No need for watches_lock: the suspend_mutex is sufficient. */ list_for_each_entry(watch, &watches, list) { sprintf(token, "%lX", (long)watch); xs_watch(watch->node, token); } up_write(&xs_state.suspend_mutex); } static int xenwatch_handle_callback(void *data) { struct xs_stored_msg *msg = data; msg->u.watch.handle->callback(msg->u.watch.handle, (const char **)msg->u.watch.vec, msg->u.watch.vec_size); kfree(msg->u.watch.vec); kfree(msg); /* Kill this kthread if we were spawned just for this callback. */ if (current->pid != xenwatch_pid) do_exit(0); return 0; } static int xenwatch_thread(void *unused) { struct list_head *ent; struct xs_stored_msg *msg; for (;;) { wait_event_interruptible(watch_events_waitq, !list_empty(&watch_events)); if (kthread_should_stop()) break; mutex_lock(&xenwatch_mutex); spin_lock(&watch_events_lock); ent = watch_events.next; if (ent != &watch_events) list_del(ent); spin_unlock(&watch_events_lock); if (ent != &watch_events) { msg = list_entry(ent, struct xs_stored_msg, list); if (msg->u.watch.handle->flags & XBWF_new_thread) kthread_run(xenwatch_handle_callback, msg, "xenwatch_cb"); else xenwatch_handle_callback(msg); } mutex_unlock(&xenwatch_mutex); } return 0; } static int process_msg(void) { struct xs_stored_msg *msg; char *body; int err; msg = kmalloc(sizeof(*msg), GFP_KERNEL); if (msg == NULL) return -ENOMEM; err = xb_read(&msg->hdr, sizeof(msg->hdr)); if (err) { kfree(msg); return err; } body = kmalloc(msg->hdr.len + 1, GFP_KERNEL); if (body == NULL) { kfree(msg); return -ENOMEM; } err = xb_read(body, msg->hdr.len); if (err) { kfree(body); kfree(msg); return err; } body[msg->hdr.len] = '\0'; if (msg->hdr.type == XS_WATCH_EVENT) { msg->u.watch.vec = split(body, msg->hdr.len, &msg->u.watch.vec_size); if (IS_ERR(msg->u.watch.vec)) { kfree(msg); return PTR_ERR(msg->u.watch.vec); } spin_lock(&watches_lock); msg->u.watch.handle = find_watch( msg->u.watch.vec[XS_WATCH_TOKEN]); if (msg->u.watch.handle != NULL) { spin_lock(&watch_events_lock); list_add_tail(&msg->list, &watch_events); wake_up(&watch_events_waitq); spin_unlock(&watch_events_lock); } else { kfree(msg->u.watch.vec); kfree(msg); } spin_unlock(&watches_lock); } else { msg->u.reply.body = body; spin_lock(&xs_state.reply_lock); list_add_tail(&msg->list, &xs_state.reply_list); spin_unlock(&xs_state.reply_lock); wake_up(&xs_state.reply_waitq); } return 0; } static int xenbus_thread(void *unused) { int err; for (;;) { err = process_msg(); if (err) printk(KERN_WARNING "XENBUS error %d while reading " "message\n", err); if (kthread_should_stop()) break; } return 0; } int xs_init(void) { int err; struct task_struct *task; INIT_LIST_HEAD(&xs_state.reply_list); spin_lock_init(&xs_state.reply_lock); init_waitqueue_head(&xs_state.reply_waitq); mutex_init(&xs_state.request_mutex); init_rwsem(&xs_state.suspend_mutex); /* Initialize the shared memory rings to talk to xenstored */ err = xb_init_comms(); if (err) return err; task = kthread_run(xenwatch_thread, NULL, "xenwatch"); if (IS_ERR(task)) return PTR_ERR(task); xenwatch_pid = task->pid; task = kthread_run(xenbus_thread, NULL, "xenbus"); if (IS_ERR(task)) return PTR_ERR(task); return 0; } /* * Local variables: * c-file-style: "linux" * indent-tabs-mode: t * c-indent-level: 8 * c-basic-offset: 8 * tab-width: 8 * End: */