From 38b2f399a58fa374c5569fcb6d2699b13f617bc7 Mon Sep 17 00:00:00 2001 From: "mjw@wray-m-3.hpl.hp.com" Date: Wed, 30 Jun 2004 14:32:52 +0000 Subject: [PATCH 01/36] bitkeeper revision 1.1038.1.1 (40e2cf14GDX_OUWz8w_ZyzvGOSY2gQ) Deleted unused files. Fix VmError typo. --- .rootkeys | 20 - tools/libxutil/enum.c | 61 -- tools/libxutil/enum.h | 30 - tools/libxutil/hash_table.c | 640 ---------------- tools/libxutil/hash_table.h | 295 -------- tools/libxutil/lexis.c | 93 --- tools/libxutil/lexis.h | 122 ---- tools/libxutil/lzi_stream.c | 590 --------------- tools/libxutil/lzi_stream.h | 36 - tools/libxutil/lzo_stream.c | 596 --------------- tools/libxutil/lzo_stream.h | 36 - tools/libxutil/marshal.c | 207 ------ tools/libxutil/marshal.h | 43 -- tools/libxutil/socket_stream.c | 259 ------- tools/libxutil/socket_stream.h | 54 -- tools/libxutil/sxpr.c | 935 ------------------------ tools/libxutil/sxpr.h | 413 ----------- tools/libxutil/sxpr_parser.c | 897 ----------------------- tools/libxutil/sxpr_parser.h | 125 ---- tools/libxutil/xdr.c | 246 ------- tools/libxutil/xdr.h | 14 - tools/python/xen/xend/XendDomainInfo.py | 20 +- 22 files changed, 10 insertions(+), 5722 deletions(-) delete mode 100644 tools/libxutil/enum.c delete mode 100644 tools/libxutil/enum.h delete mode 100644 tools/libxutil/hash_table.c delete mode 100644 tools/libxutil/hash_table.h delete mode 100644 tools/libxutil/lexis.c delete mode 100644 tools/libxutil/lexis.h delete mode 100644 tools/libxutil/lzi_stream.c delete mode 100644 tools/libxutil/lzi_stream.h delete mode 100644 tools/libxutil/lzo_stream.c delete mode 100644 tools/libxutil/lzo_stream.h delete mode 100644 tools/libxutil/marshal.c delete mode 100644 tools/libxutil/marshal.h delete mode 100644 tools/libxutil/socket_stream.c delete mode 100644 tools/libxutil/socket_stream.h delete mode 100644 tools/libxutil/sxpr.c delete mode 100644 tools/libxutil/sxpr.h delete mode 100644 tools/libxutil/sxpr_parser.c delete mode 100644 tools/libxutil/sxpr_parser.h delete mode 100644 tools/libxutil/xdr.c delete mode 100644 tools/libxutil/xdr.h diff --git a/.rootkeys b/.rootkeys index 5045bae458..88dc29a268 100644 --- a/.rootkeys +++ b/.rootkeys @@ -188,41 +188,21 @@ 40e033325Sjqs-_4TuzeUEprP_gYFg tools/libxutil/allocate.c 40e03332KYz7o1bn2MG_KPbBlyoIMA tools/libxutil/allocate.h 40e03332IyRttYoXKoJla5qCC514SQ tools/libxutil/debug.h -40e03332qV5tJ-GJZjo-LBCeGuEjJA tools/libxutil/enum.c -40e03332wwMVxfobgA1PSMTSAGLiCw tools/libxutil/enum.h 40e03332p5Dc_owJQRuN72ymJZddFQ tools/libxutil/file_stream.c 40e03332jWfB2viAhLSkq1WK0r_iDQ tools/libxutil/file_stream.h 40e03332rUjNMGg11n2rN6V4DCrvOg tools/libxutil/gzip_stream.c 40e033321O5Qg22haLoq5lpmk4tooQ tools/libxutil/gzip_stream.h -40e03332QrTR96tc6yS2rMBpd2mq1A tools/libxutil/hash_table.c -40e033325KoIb0d_uy8s7b5DUR9fPQ tools/libxutil/hash_table.h 40e03332ihnBGzHykVwZnFmkAppb4g tools/libxutil/iostream.c 40e03332UGwbLR4wsw4ft14p0Yw5pg tools/libxutil/iostream.h 40e0333245DLDzJemeSVBLuutHtzEQ tools/libxutil/kernel_stream.c 40e03332aK0GkgpDdc-PVTkWKTeOBg tools/libxutil/kernel_stream.h -40e03332HJ0cDcZDKDUUT-tEiBWOZw tools/libxutil/lexis.c -40e03332tnH9Ggzxbfi3xY9Vh2hUlg tools/libxutil/lexis.h -40e03332aYIW0BNBh6wXuKKn_P7Yyg tools/libxutil/lzi_stream.c -40e0333233voTffE4cJSMGJARfiSSQ tools/libxutil/lzi_stream.h -40e03332FXuMoUnfsAKSgV8X4rFbYQ tools/libxutil/lzo_stream.c -40e03332InJaiLfpDcIXBy2fI0RFGQ tools/libxutil/lzo_stream.h -40e03332a5SCuRsejHStTuWzMQNv8Q tools/libxutil/marshal.c -40e03332TwKyJrZQiiQfNq4vc2hpgw tools/libxutil/marshal.h -40e033328ccHlJuTR1FswYL_EC6LFA tools/libxutil/socket_stream.c -40e03332P0KVQGkmahj47aafo1X0nA tools/libxutil/socket_stream.h 40e03332KT_tnnoAMbPVAZBB7kSOAQ tools/libxutil/string_stream.c 40e03332-VtK6_OZa1vMHXFil8uq6w tools/libxutil/string_stream.h -40e03332dDtczi6YX7_mMxhYjJeAdQ tools/libxutil/sxpr.c -40e03332QPuyNKDOTIYVvkwK5qO-vg tools/libxutil/sxpr.h -40e03332Pi0_osJ3XPBi38ADPqdl4A tools/libxutil/sxpr_parser.c -40e033324v5QFMvWEXXzv38uUT9kHg tools/libxutil/sxpr_parser.h 40e03332gKUInsqtxQOV4mPiMqf_dg tools/libxutil/sys_ctype.h 40e03332Rkvq6nn_UNjzAAK_Tk9v1g tools/libxutil/sys_net.c 40e03332lQHvQHw4Rh7VsT1_sui29A tools/libxutil/sys_net.h 40e033321smklZd7bDSdWvQCeIshtg tools/libxutil/sys_string.c 40e03332h5V611rRWURRLqb1Ekatxg tools/libxutil/sys_string.h -40e03332u4q5kgF0N7RfqB4s0pZVew tools/libxutil/xdr.c -40e03332hY16nfRXF4gGd5S1aUJUBw tools/libxutil/xdr.h 3f776bd2Xd-dUcPKlPN2vG89VGtfvQ tools/misc/Makefile 40ab2cfawIw8tsYo0dQKtp83h4qfTQ tools/misc/fakei386xen 3f6dc136ZKOjd8PIqLbFBl_v-rnkGg tools/misc/miniterm/Makefile diff --git a/tools/libxutil/enum.c b/tools/libxutil/enum.c deleted file mode 100644 index 95f6e31a87..0000000000 --- a/tools/libxutil/enum.c +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2002, 2004 Mike Wray - * - * 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.1 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 - */ - -#ifdef __KERNEL__ -#include -#else -#include -#endif - -#include "sys_string.h" -#include "enum.h" - -/** Map an enum name to its value using a table. - * - * @param name enum name - * @param defs enum definitions - * @return enum value or -1 if not known - */ -int enum_name_to_val(char *name, EnumDef *defs){ - int val = -1; - for(; defs->name; defs++){ - if(!strcmp(defs->name, name)){ - val = defs->val; - break; - } - } - return val; -} - -/** Map an enum value to its name using a table. - * - * @param val enum value - * @param defs enum definitions - * @param defs_n number of definitions - * @return enum name or NULL if not known - */ -char *enum_val_to_name(int val, EnumDef *defs){ - char *name = NULL; - for(; defs->name; defs++){ - if(val == defs->val){ - name = defs->name; - break; - } - } - return name; -} - diff --git a/tools/libxutil/enum.h b/tools/libxutil/enum.h deleted file mode 100644 index db6e7b0058..0000000000 --- a/tools/libxutil/enum.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2002, 2004 Mike Wray - * - * 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.1 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 - */ - -#ifndef _XEN_LIB_ENUM_H_ -#define _XEN_LIB_ENUM_H_ - -/** Mapping of an enum value to a name. */ -typedef struct EnumDef { - int val; - char *name; -} EnumDef; - -extern int enum_name_to_val(char *name, EnumDef *defs); -extern char *enum_val_to_name(int val, EnumDef *defs); - -#endif /* _XEN_LIB_ENUM_H_ */ diff --git a/tools/libxutil/hash_table.c b/tools/libxutil/hash_table.c deleted file mode 100644 index 13da946e77..0000000000 --- a/tools/libxutil/hash_table.c +++ /dev/null @@ -1,640 +0,0 @@ -/* - * Copyright (C) 2001 - 2004 Mike Wray - * - * 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.1 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 - */ - -#ifdef __KERNEL__ -# include -# include -# include -# include -#else -# include -# include -#endif - -//#include - -#include "allocate.h" -#include "hash_table.h" - -/** @file - * Base support for hashtables. - * - * Hash codes are reduced modulo the number of buckets to index tables, - * so there is no need for hash functions to limit the range of hashcodes. - * In fact it is assumed that hashcodes do not change when the number of - * buckets in the table changes. - */ - -/*==========================================================================*/ -/** Number of bits in half a word. */ -//#if __WORDSIZE == 64 -//#define HALF_WORD_BITS 32 -//#else -#define HALF_WORD_BITS 16 -//#endif - -/** Mask for lo half of a word. On 32-bit this is - * (1<<16) - 1 = 65535 = 0xffff - * It's 4294967295 = 0xffffffff on 64-bit. - */ -#define LO_HALF_MASK ((1 << HALF_WORD_BITS) - 1) - -/** Get the lo half of a word. */ -#define LO_HALF(x) ((x) & LO_HALF_MASK) - -/** Get the hi half of a word. */ -#define HI_HALF(x) ((x) >> HALF_WORD_BITS) - -/** Do a full hash on both inputs, using DES-style non-linear scrambling. - * Both inputs are replaced with the results of the hash. - * - * @param pleft input/output word - * @param pright input/output word - */ -void pseudo_des(unsigned long *pleft, unsigned long *pright){ - // Bit-rich mixing constant. - static const unsigned long a_mixer[] = { - 0xbaa96887L, 0x1e17d32cL, 0x03bcdc3cL, 0x0f33d1b2L, }; - - // Bit-rich mixing constant. - static const unsigned long b_mixer[] = { - 0x4b0f3b58L, 0xe874f0c3L, 0x6955c5a6L, 0x55a7ca46L, }; - - // Number of iterations - must be 2 or 4. - static const int ncycle = 4; - //static const int ncycle = 2; - - unsigned long left = *pleft, right = *pright; - unsigned long v, v_hi, v_lo; - int i; - - for(i=0; ibuckets + (hashcode % table->buckets_n); -} - -/** Initialize a hash table. - * Can be safely called more than once. - * - * @param table to initialize - */ -void HashTable_init(HashTable *table){ - int i; - - if(!table->init_done){ - table->init_done = 1; - table->next_id = 0; - for(i=0; ibuckets_n; i++){ - HTBucket *bucket = get_bucket(table, i); - bucket->head = 0; - bucket->count = 0; - } - table->entry_count = 0; - } -} - -/** Allocate a new hashtable. - * If the number of buckets is not positive the default is used. - * The number of buckets should usually be prime. - * - * @param buckets_n number of buckets - * @return new hashtable or null - */ -HashTable *HashTable_new(int buckets_n){ - HashTable *z = ALLOCATE(HashTable); - if(!z) goto exit; - if(buckets_n <= 0){ - buckets_n = HT_BUCKETS_N; - } - z->buckets = (HTBucket*)allocate(buckets_n * sizeof(HTBucket)); - if(!z->buckets){ - deallocate(z); - z = 0; - goto exit; - } - z->buckets_n = buckets_n; - HashTable_init(z); - exit: - return z; -} - -/** Free a hashtable. - * Any entries are removed and freed. - * - * @param h hashtable (ignored if null) - */ -void HashTable_free(HashTable *h){ - if(h){ - HashTable_clear(h); - deallocate(h->buckets); - deallocate(h); - } -} - -/** Push an entry on the list in the bucket for a given hashcode. - * - * @param table to add entry to - * @param hashcode for the entry - * @param entry to add - */ -static inline void push_on_bucket(HashTable *table, Hashcode hashcode, - HTEntry *entry){ - HTBucket *bucket; - HTEntry *old_head; - - bucket = get_bucket(table, hashcode); - old_head = bucket->head; - bucket->count++; - bucket->head = entry; - entry->next = old_head; -} - -/** Change the number of buckets in a hashtable. - * No-op if the number of buckets is not positive. - * Existing entries are reallocated to buckets based on their hashcodes. - * The table is unmodified if the number of buckets cannot be changed. - * - * @param table hashtable - * @param buckets_n new number of buckets - * @return 0 on success, error code otherwise - */ -int HashTable_set_buckets_n(HashTable *table, int buckets_n){ - int err = 0; - HTBucket *old_buckets = table->buckets; - int old_buckets_n = table->buckets_n; - int i; - - if(buckets_n <= 0){ - err = -EINVAL; - goto exit; - } - table->buckets = (HTBucket*)allocate(buckets_n * sizeof(HTBucket)); - if(!table->buckets){ - err = -ENOMEM; - table->buckets = old_buckets; - goto exit; - } - table->buckets_n = buckets_n; - for(i=0; ihead; entry; entry = next){ - next = entry->next; - push_on_bucket(table, entry->hashcode, entry); - } - } - deallocate(old_buckets); - exit: - return err; -} - -/** Adjust the number of buckets so the table is neither too full nor too empty. - * The table is unmodified if adjusting fails. - * - * @param table hash table - * @param buckets_min minimum number of buckets (use default if 0 or negative) - * @return 0 on success, error code otherwise - */ -int HashTable_adjust(HashTable *table, int buckets_min){ - int buckets_n = 0; - int err = 0; - if(buckets_min <= 0) buckets_min = HT_BUCKETS_N; - if(table->entry_count >= table->buckets_n){ - // The table is dense - expand it. - buckets_n = 2 * table->buckets_n; - } else if((table->buckets_n > buckets_min) && - (4 * table->entry_count < table->buckets_n)){ - // The table is more than minimum size and sparse - shrink it. - buckets_n = 2 * table->entry_count; - if(buckets_n < buckets_min) buckets_n = buckets_min; - } - if(buckets_n){ - err = HashTable_set_buckets_n(table, buckets_n); - } - return err; -} - -/** Allocate a new entry for a given value. - * - * @param value to put in the entry - * @return entry, or 0 on failure - */ -HTEntry * HTEntry_new(Hashcode hashcode, void *key, void *value){ - HTEntry *z = ALLOCATE(HTEntry); - if(z){ - z->hashcode = hashcode; - z->key = key; - z->value = value; - } - return z; -} - -/** Free an entry. - * - * @param z entry to free - */ -inline void HTEntry_free(HTEntry *z){ - if(z){ - deallocate(z); - } -} - -/** Free an entry in a hashtable. - * The table's entry_free_fn is used is defined, otherwise - * the HTEntry itself is freed. - * - * @param table hashtable - * @param entry to free - */ -inline void HashTable_free_entry(HashTable *table, HTEntry *entry){ - if(!entry)return; - if(table && table->entry_free_fn){ - table->entry_free_fn(table, entry); - } else { - HTEntry_free(entry); - } -} - -/** Get the first entry satisfying a test from the bucket for the - * given hashcode. - * - * @param table to look in - * @param hashcode indicates the bucket - * @param test_fn test to apply to elements - * @param arg first argument to calls to test_fn - * @return entry found, or 0 - */ -inline HTEntry * HashTable_find_entry(HashTable *table, Hashcode hashcode, - TableTestFn *test_fn, TableArg arg){ - HTBucket *bucket; - HTEntry *entry = 0; - HTEntry *next; - - bucket = get_bucket(table, hashcode); - for(entry = bucket->head; entry; entry = next){ - next = entry->next; - if(test_fn(arg, table, entry)){ - break; - } - } - return entry; -} - -/** Test hashtable keys for equality. - * Uses the table's key_equal_fn if defined, otherwise pointer equality. - * - * @param key1 key to compare - * @param key2 key to compare - * @return 1 if equal, 0 otherwise - */ -inline int HashTable_key_equal(HashTable *table, void *key1, void *key2){ - return (table->key_equal_fn ? table->key_equal_fn(key1, key2) : key1==key2); -} - -/** Compute the hashcode of a hashtable key. - * The table's key_hash_fn is used if defined, otherwise the address of - * the key is hashed. - * - * @param table hashtable - * @param key to hash - * @return hashcode - */ -inline Hashcode HashTable_key_hash(HashTable *table, void *key){ - return (table->key_hash_fn ? table->key_hash_fn(key) : hash_ul((unsigned long)key)); -} - -/** Test if an entry has a given key. - * - * @param arg containing key to test for - * @param table the entry is in - * @param entry to test - * @return 1 if the entry has the key, 0 otherwise - */ -static inline int has_key(TableArg arg, HashTable *table, HTEntry *entry){ - return HashTable_key_equal(table, arg.ptr, entry->key); -} - -/** Get an entry with a given key. - * - * @param table to search - * @param key to look for - * @return entry if found, null otherwise - */ -#if 0 -inline HTEntry * HashTable_get_entry(HashTable *table, void *key){ - TableArg arg = { ptr: key }; - return HashTable_find_entry(table, HashTable_key_hash(table, key), has_key, arg); -} -#else -inline HTEntry * HashTable_get_entry(HashTable *table, void *key){ - Hashcode hashcode; - HTBucket *bucket; - HTEntry *entry = 0; - HTEntry *next; - - hashcode = HashTable_key_hash(table, key); - bucket = get_bucket(table, hashcode); - for(entry = bucket->head; entry; entry = next){ - next = entry->next; - if(HashTable_key_equal(table, key, entry->key)){ - break; - } - } - return entry; -} -#endif - -/** Get the value of an entry with a given key. - * - * @param table to search - * @param key to look for - * @return value if an entry was found, null otherwise - */ -inline void * HashTable_get(HashTable *table, void *key){ - HTEntry *entry = HashTable_get_entry(table, key); - return (entry ? entry->value : 0); -} - -/** Print the buckets in a table. - * - * @param table to print - */ -void show_buckets(HashTable *table, IOStream *io){ - int i,j ; - IOStream_print(io, "entry_count=%d buckets_n=%d\n", table->entry_count, table->buckets_n); - for(i=0; ibuckets_n; i++){ - if(0 || table->buckets[i].count>0){ - IOStream_print(io, "bucket %3d %3d %10p ", i, - table->buckets[i].count, - table->buckets[i].head); - for(j = table->buckets[i].count; j>0; j--){ - IOStream_print(io, "+"); - } - IOStream_print(io, "\n"); - } - } - HashTable_print(table, io); -} - -/** Print an entry in a table. - * - * @param entry to print - * @param arg a pointer to an IOStream to print to - * @return 0 - */ -static int print_entry(TableArg arg, HashTable *table, HTEntry *entry){ - IOStream *io = (IOStream*)arg.ptr; - IOStream_print(io, " b=%4lx h=%08lx i=%08lx |-> e=%8p k=%8p v=%8p\n", - entry->hashcode % table->buckets_n, - entry->hashcode, - entry->index, - entry, entry->key, entry->value); - return 0; -} - -/** Print a hash table. - * - * @param table to print - */ -void HashTable_print(HashTable *table, IOStream *io){ - IOStream_print(io, "{\n"); - HashTable_map(table, print_entry, (TableArg){ ptr: io }); - IOStream_print(io, "}\n"); -} -/*==========================================================================*/ - -/** Get the next entry id to use for a table. - * - * @param table hash table - * @return non-zero entry id - */ -static inline unsigned long get_next_id(HashTable *table){ - unsigned long id; - - if(table->next_id == 0){ - table->next_id = 1; - } - id = table->next_id++; - return id; -} - -/** Add an entry to the bucket for the - * given hashcode. - * - * @param table to insert in - * @param hashcode indicates the bucket - * @param key to add an entry for - * @param value to add an entry for - * @return entry on success, 0 on failure - */ -inline HTEntry * HashTable_add_entry(HashTable *table, Hashcode hashcode, void *key, void *value){ - HTEntry *entry = HTEntry_new(hashcode, key, value); - if(entry){ - entry->index = get_next_id(table); - push_on_bucket(table, hashcode, entry); - table->entry_count++; - } - return entry; -} - -/** Move the front entry for a bucket to the correct point in the bucket order as - * defined by the order function. If this is called every time a new entry is added - * the bucket will be maintained in sorted order. - * - * @param table to modify - * @param hashcode indicates the bucket - * @param order entry comparison function - * @return 0 if an entry was moved, 1 if not - */ -int HashTable_order_bucket(HashTable *table, Hashcode hashcode, TableOrderFn *order){ - HTEntry *new_entry = NULL, *prev = NULL, *entry = NULL; - HTBucket *bucket; - int err = 1; - - bucket = get_bucket(table, hashcode); - new_entry = bucket->head; - if(!new_entry || !new_entry->next) goto exit; - for(entry = new_entry->next; entry; prev = entry, entry = entry->next){ - if(order(new_entry, entry) <= 0) break; - } - if(prev){ - err = 0; - bucket->head = new_entry->next; - new_entry->next = entry; - prev->next = new_entry; - } - exit: - return err; -} - -/** Add an entry to a hashtable. - * The entry is added to the bucket for its key's hashcode. - * - * @param table to insert in - * @param key to add an entry for - * @param value to add an entry for - * @return entry on success, 0 on failure - */ -inline HTEntry * HashTable_add(HashTable *table, void *key, void *value){ - return HashTable_add_entry(table, HashTable_key_hash(table, key), key, value); -} - - -/** Remove entries satisfying a test from the bucket for the - * given hashcode. - * - * @param table to remove from - * @param hashcode indicates the bucket - * @param test_fn test to apply to elements - * @param arg first argument to calls to test_fn - * @return number of entries removed - */ -inline int HashTable_remove_entry(HashTable *table, Hashcode hashcode, - TableTestFn *test_fn, TableArg arg){ - HTBucket *bucket; - HTEntry *entry, *prev = 0, *next; - int removed_count = 0; - - bucket = get_bucket(table, hashcode); - for(entry = bucket->head; entry; entry = next){ - next = entry->next; - if(test_fn(arg, table, entry)){ - if(prev){ - prev->next = next; - } else { - bucket->head = next; - } - bucket->count--; - table->entry_count--; - removed_count++; - HashTable_free_entry(table, entry); - entry = 0; - } - prev = entry; - } - return removed_count; -} - -/** Remove entries with a given key. - * - * @param table to remove from - * @param key of entries to remove - * @return number of entries removed - */ -inline int HashTable_remove(HashTable *table, void *key){ -#if 1 - Hashcode hashcode; - HTBucket *bucket; - HTEntry *entry, *prev = 0, *next; - int removed_count = 0; - - hashcode = HashTable_key_hash(table, key); - bucket = get_bucket(table, hashcode); - for(entry = bucket->head; entry; entry = next){ - next = entry->next; - if(HashTable_key_equal(table, key, entry->key)){ - if(prev){ - prev->next = next; - } else { - bucket->head = next; - } - bucket->count--; - table->entry_count--; - removed_count++; - HashTable_free_entry(table, entry); - entry = 0; - } - prev = entry; - } - return removed_count; -#else - return HashTable_remove_entry(table, HashTable_key_hash(table, key), - has_key, (TableArg){ ptr: key}); -#endif -} - -/** Remove (and free) all the entries in a bucket. - * - * @param bucket to clear - */ -static inline void bucket_clear(HashTable *table, HTBucket *bucket){ - HTEntry *entry, *next; - - for(entry = bucket->head; entry; entry = next){ - next = entry->next; - HashTable_free_entry(table, entry); - } - bucket->head = 0; - table->entry_count -= bucket->count; - bucket->count = 0; -} - -/** Remove (and free) all the entries in a table. - * - * @param table to clear - */ -void HashTable_clear(HashTable *table){ - int i, n = table->buckets_n; - - for(i=0; ibuckets + i); - } -} diff --git a/tools/libxutil/hash_table.h b/tools/libxutil/hash_table.h deleted file mode 100644 index 6d7e76ff33..0000000000 --- a/tools/libxutil/hash_table.h +++ /dev/null @@ -1,295 +0,0 @@ -/* $Id: hash_table.h,v 1.1 2004/03/30 16:21:26 mjw Exp $ */ -/* - * Copyright (C) 2001 - 2004 Mike Wray - * - * 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.1 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 - */ - -#ifndef _XEN_LIB_HASH_TABLE_H_ -#define _XEN_LIB_HASH_TABLE_H_ - -#include "iostream.h" - -typedef unsigned long Hashcode; - -/** Type used to pass parameters to table functions. */ -typedef union TableArg { - unsigned long ul; - void *ptr; -} TableArg; - -/** An entry in a bucket list. */ -typedef struct HTEntry { - /** Hashcode of the entry's key. */ - Hashcode hashcode; - /** Identifier for this entry in the table. */ - int index; - /** The key for this entry. */ - void *key; - /** The value in this entry. */ - void *value; - /** The next entry in the list. */ - struct HTEntry *next; -} HTEntry; - -/** A bucket in a rule table. */ -typedef struct HTBucket { - /** Number of entries in the bucket. */ - int count; - /** First entry in the bucket (may be null). */ - HTEntry *head; -} HTBucket; - -/** Default number of buckets in a hash table. - * You want enough buckets so the lists in the buckets will typically be short. - * It's a good idea if this is prime, since that will help to spread hashcodes - * around the table. - */ -//#define HT_BUCKETS_N 1 -//#define HT_BUCKETS_N 3 -//#define HT_BUCKETS_N 7 -//#define HT_BUCKETS_N 17 -//#define HT_BUCKETS_N 97 -//#define HT_BUCKETS_N 211 -//#define HT_BUCKETS_N 401 -#define HT_BUCKETS_N 1021 - -typedef struct HashTable HashTable; - -/** Type for a function used to select table entries. */ -typedef int TableTestFn(TableArg arg, HashTable *table, HTEntry *entry); - -/** Type for a function to map over table entries. */ -typedef int TableMapFn(TableArg arg, HashTable *table, HTEntry *entry); - -/** Type for a function to free table entries. */ -typedef void TableFreeFn(HashTable *table, HTEntry *entry); - -/** Type for a function to hash table keys. */ -typedef Hashcode TableHashFn(void *key); - -/** Type for a function to test table keys for equality. */ -typedef int TableEqualFn(void *key1, void *key2); - -/** Type for a function to order table entries. */ -typedef int TableOrderFn(HTEntry *e1, HTEntry *e2); - -/** General hash table. - * A hash table with a list in each bucket. - * Functions can be supplied for freeing entries, hashing keys, and comparing keys. - * These all default to 0, when default behaviour treating keys as integers is used. - */ -struct HashTable { - /** Flag indicating whether the table has been initialised. */ - int init_done; - /** Next value for the id field in inserted rules. */ - unsigned long next_id; - /** Number of buckets in the bucket array. */ - int buckets_n; - /** Array of buckets, each with its own list. */ - HTBucket *buckets; - /** Number of entries in the table. */ - int entry_count; - /** Function to free keys and values in entries. */ - TableFreeFn *entry_free_fn; - /** Function to hash keys. */ - TableHashFn *key_hash_fn; - /** Function to compare keys for equality. */ - TableEqualFn *key_equal_fn; - /** Place for the user of the table to hang extra data. */ - void *user_data; -}; - -extern HashTable *HashTable_new(int bucket_n); -extern void HashTable_free(HashTable *table); -extern HTEntry * HTEntry_new(Hashcode hashcode, void *key, void *value); -extern void HTEntry_free(HTEntry *entry); -extern int HashTable_set_bucket_n(HashTable *table, int bucket_n); -extern void HashTable_clear(HashTable *table); -extern HTEntry * HashTable_add_entry(HashTable *table, Hashcode hashcode, void *key, void *value); -extern HTEntry * HashTable_get_entry(HashTable *table, void *key); -extern HTEntry * HashTable_add(HashTable *table, void *key, void *value); -extern void * HashTable_get(HashTable *table, void *key); -extern int HashTable_remove(HashTable *table, void *key); -extern HTEntry * HashTable_find_entry(HashTable *table, Hashcode hashcode, - TableTestFn *test_fn, TableArg arg); -extern int HashTable_remove_entry(HashTable *table, Hashcode hashcode, - TableTestFn *test_fn, TableArg arg); -//extern int HashTable_map(HashTable *table, TableMapFn *map_fn, TableArg arg); -extern void HashTable_print(HashTable *table, IOStream *out); -extern int HashTable_set_buckets_n(HashTable *table, int buckets_n); -extern int HashTable_adjust(HashTable *table, int buckets_min); -extern void pseudo_des(unsigned long *pleft, unsigned long *pright); -extern Hashcode hash_string(char *s); - -extern int HashTable_order_bucket(HashTable *table, Hashcode hashcode, TableOrderFn *order); - -/** Control whether to use hashing based on DES or simple - * hashing. DES hashing is `more random' but much more expensive. - */ -#define HASH_PSEUDO_DES 0 - -/** Hash a long using a quick and dirty linear congruential random number generator. - * See `Numerical Recipes in C', Chapter 7, "An Even Quicker Generator". - * - * @param a value to hash - * @return hashed input - */ -static inline unsigned long lcrng_hash(unsigned long a){ - return (1664525L * a + 1013904223L); -} - -/** Hash an unsigned long. - * - * @param a input to hash - * @return hashcode - */ -static inline Hashcode hash_ul(unsigned long a){ -#if HASH_PSEUDO_DES - unsigned long left = a; - unsigned long right = 0L; - pseudo_des(&left, &right); - return right; -#else - a = lcrng_hash(a); - a = lcrng_hash(a); - return a; -#endif -} - -/** Hash two unsigned longs together. - * - * @param a input to hash - * @param b input to hash - * @return hashcode - */ -static inline Hashcode hash_2ul(unsigned long a, unsigned long b){ -#if HASH_PSEUDO_DES - unsigned long left = a; - unsigned long right = b; - pseudo_des(&left, &right); - return right; -#else - a = lcrng_hash(a); - a ^= b; - a = lcrng_hash(a); - return a; -#endif -} - -/** Hash a hashcode and an unsigned long together. - * - * @param a input hashcode - * @param b input to hash - * @return hashcode - */ -static inline Hashcode hash_hul(Hashcode a, unsigned long b){ -#if HASH_PSEUDO_DES - unsigned long left = a; - unsigned long right = b; - pseudo_des(&left, &right); - return right; -#else - a ^= b; - a = lcrng_hash(a); - return a; -#endif -} - -/** Macro to declare variables for HashTable_for_each() to use. - * - * @param entry variable that is set to entries in the table - */ -#define HashTable_for_decl(entry) \ - HashTable *_var_table; \ - HTBucket *_var_bucket; \ - HTBucket *_var_end; \ - HTEntry *_var_next; \ - HTEntry *entry - -/** Macro to iterate over the entries in a hashtable. - * Must be in a scope where HashTable_for_decl() has been used to declare - * variables for it to use. - * The variable 'entry' is iterated over entries in the table. - * The code produced is syntactically a loop, so it must be followed by - * a loop body, typically some statements in braces: - * HashTable_for_each(entry, table){ ...loop body... } - * - * HashTable_for_each() and HashTable_for_decl() cannot be used for nested - * loops as variables will clash. - * - * @note The simplest way to code a direct loop over the entries in a hashtable - * is to use a loop over the buckets, with a nested loop over the entries - * in a bucket. Using this approach in a macro means the macro contains - * an opening brace, and calls to it must be followed by 2 braces! - * To avoid this the code has been restructured so that it is a for loop. - * So that statements could be used in the test expression of the for loop, - * we have used the gcc statement expression extension ({ ... }). - * - * @param entry variable to iterate over the entries - * @param table to iterate over (non-null) - */ -#define HashTable_for_each(entry, table) \ - _var_table = table; \ - _var_bucket = _var_table->buckets; \ - _var_end = _var_bucket + _var_table->buckets_n; \ - for(entry=0, _var_next=0; \ - ({ if(_var_next){ \ - entry = _var_next; \ - _var_next = entry->next; \ - } else { \ - while(_var_bucket < _var_end){ \ - entry = _var_bucket->head; \ - _var_bucket++; \ - if(entry){ \ - _var_next = entry->next; \ - break; \ - } \ - } \ - }; \ - entry; }); \ - entry = _var_next ) - -/** Map a function over the entries in a table. - * Mapping stops when the function returns a non-zero value. - * Uses the gcc statement expression extension ({ ... }). - * - * @param table to map over - * @param fn function to apply to entries - * @param arg first argument to call the function with - * @return 0 if fn always returned 0, first non-zero value otherwise - */ -#define HashTable_map(table, fn, arg) \ - ({ HashTable_for_decl(_var_entry); \ - TableArg _var_arg = arg; \ - int _var_value = 0; \ - HashTable_for_each(_var_entry, table){ \ - if((_var_value = fn(_var_arg, _var_table, _var_entry))) break; \ - } \ - _var_value; }) - -/** Cast x to the type for a key or value in a hash table. - * This avoids compiler warnings when using short integers - * as keys or values (especially on 64-bit platforms). - */ -#define HKEY(x) ((void*)(unsigned long)(x)) - -/** Cast x from the type for a key or value in a hash table. - * to an unsigned long. This avoids compiler warnings when using - * short integers as keys or values (especially on 64-bit platforms). - */ -#define HVAL(x) ((unsigned long)(x)) - -#endif /* !_XEN_LIB_HASH_TABLE_H_ */ diff --git a/tools/libxutil/lexis.c b/tools/libxutil/lexis.c deleted file mode 100644 index 26d2ec4d5b..0000000000 --- a/tools/libxutil/lexis.c +++ /dev/null @@ -1,93 +0,0 @@ -/* - * - * 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.1 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 - */ - -/** @file - * Lexical analysis. - */ - -#include "sys_string.h" -#include "lexis.h" -#include - -/** Check if a value lies in a (closed) range. - * - * @param x value to test - * @param lo low end of the range - * @param hi high end of the range - * @return 1 if x is in the interval [lo, hi], 0 otherwise - */ -inline static int in_range(int x, int lo, int hi){ - return (lo <= x) && (x <= hi); -} - -/** Determine if a string is an (unsigned) decimal number. - * - * @param s pointer to characters to test - * @param n length of string - * @return 1 if s is a decimal number, 0 otherwise. - */ -int is_decimal_number(const char *s, int n){ - int i; - if(n <= 0)return 0; - for(i = 0; i < n; i++){ - if(!in_decimal_digit_class(s[i])) return 0; - } - return 1; -} - -/** Determine if a string is a hex number. - * Hex numbers are 0, or start with 0x or 0X followed - * by a non-zero number of hex digits (0-9,a-f,A-F). - * - * @param s pointer to characters to test - * @param n length of string - * @return 1 if s is a hex number, 0 otherwise. - */ -int is_hex_number(const char *s, int n){ - int i; - if(n <= 0) return 0; - if(n == 1){ - return s[0]=='0'; - } - if(n <= 3) return 0; - if(s[0] != '0' || (s[1] != 'x' && s[1] != 'X')) return 0; - for(i = 2; i < n; i++){ - if(!in_hex_digit_class(s[i])) return 0; - } - return 1; -} - -/** Test if a string matches a keyword. - * The comparison is case-insensitive. - * The comparison fails if either argument is null. - * - * @param s string - * @param k keyword - * @return 1 if they match, 0 otherwise - */ -int is_keyword(const char *s, const char *k){ - return s && k && !strcasecmp(s, k); -} - -/** Test if a string matches a character. - * - * @param s string - * @param c character (non-null) - * @return 1 if s contains exactly c, 0 otherwise - */ -int is_keychar(const char *s, char c){ - return c && (s[0] == c) && !s[1]; -} diff --git a/tools/libxutil/lexis.h b/tools/libxutil/lexis.h deleted file mode 100644 index 7d8fe7bc63..0000000000 --- a/tools/libxutil/lexis.h +++ /dev/null @@ -1,122 +0,0 @@ -/* - * - * 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.1 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 - */ - -#ifndef _SP_LEXIS_H_ -#define _SP_LEXIS_H_ - -#include "sys_string.h" -#include "sys_ctype.h" - -/** @file - * Lexical analysis. - */ - -/** Class of characters treated as space. */ -#define space_class ((char []){ '\n', '\r', '\t', ' ', '\f' , 0 }) - -/** Class of separator characters. */ -#define sep_class "{}()<>[]@!;" - -#define comment_class "#" - -/** Determine if a character is in a given class. - * - * @param c character to test - * @param s null-terminated string of characters in the class - * @return 1 if c is in the class, 0 otherwise. - */ -static inline int in_class(int c, const char *s){ - return s && (strchr(s, c) != 0); -} - -/** Determine if a character is in the space class. - * - * @param c character to test - * @return 1 if c is in the class, 0 otherwise. - */ -static inline int in_space_class(int c){ - return in_class(c, space_class); -} - -static inline int in_comment_class(int c){ - return in_class(c, comment_class); -} - -/** Determine if a character is in the separator class. - * Separator characters terminate tokens, and do not need space - * to separate them. - * - * @param c character to test - * @return 1 if c is in the class, 0 otherwise. - */ -static inline int in_sep_class(int c){ - return in_class(c, sep_class); -} - -/** Determine if a character is in the alpha class. - * - * @param c character to test - * @return 1 if c is in the class, 0 otherwise. - */ -static inline int in_alpha_class(int c){ - return isalpha(c); -} - -/** Determine if a character is in the octal digit class. - * - * @param c character to test - * @return 1 if c is in the class, 0 otherwise. - */ -static inline int in_octal_digit_class(int c){ - return '0' <= c && c <= '7'; -} - -/** Determine if a character is in the decimal digit class. - * - * @param c character to test - * @return 1 if c is in the class, 0 otherwise. - */ -static inline int in_decimal_digit_class(int c){ - return isdigit(c); -} - -/** Determine if a character is in the hex digit class. - * - * @param c character to test - * @return 1 if c is in the class, 0 otherwise. - */ -static inline int in_hex_digit_class(int c){ - return isdigit(c) || in_class(c, "abcdefABCDEF"); -} - - -static inline int in_string_quote_class(int c){ - return in_class(c, "'\""); -} - -static inline int in_printable_class(int c){ - return ('A' <= c && c <= 'Z') - || ('a' <= c && c <= 'z') - || ('0' <= c && c <= '9') - || in_class(c, "!$%&*+,-./:;<=>?@^_`{|}~"); -} - -extern int is_decimal_number(const char *s, int n); -extern int is_hex_number(const char *s, int n); -extern int is_keyword(const char *s, const char *k); -extern int is_keychar(const char *s, char c); - -#endif /* !_SP_LEXIS_H_ */ diff --git a/tools/libxutil/lzi_stream.c b/tools/libxutil/lzi_stream.c deleted file mode 100644 index 0f09734201..0000000000 --- a/tools/libxutil/lzi_stream.c +++ /dev/null @@ -1,590 +0,0 @@ -/* $Id: lzi_stream.c,v 1.4 2003/09/30 15:22:53 mjw Exp $ */ -#define __FILE_ID_INFO "$Id: lzi_stream.c,v 1.4 2003/09/30 15:22:53 mjw Exp $" -#include -static char __rcsid[] __attribute__((unused)) = WHAT_ID __FILE_ID_INFO; -/* - * Copyright (C) 2003 Hewlett-Packard Company. - * - * 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.1 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 - */ - -/** @file - * An IOStream implementation using LZI to provide compression and decompression. - * This is designed to provide compression without output latency. - * Flushing an LZI stream flushes all pending data to the underlying stream. - * This is essential for stream-based (e.g. networked) applications. - * - * A compressed data stream is a sequence of blocks. - * Each block is the block size followed by the compressed data. - * The last block has size zero. - * Sizes are 4-byte unsigned in network order. - * - * This format allows compressed data to be read from a stream without reading - * past the logical end of compressed data. - * - * @author Mike Wray - */ -#ifndef __KERNEL__ - -#include -#include -#include -#include - -#include "zlib.h" - -#include "allocate.h" -#include "lzi_stream.h" -#include "file_stream.h" -#include "marshal.h" - -#define dprintf(fmt, args...) fprintf(stdout, "[DEBUG] LZI>%s" fmt, __FUNCTION__, ##args) -#define wprintf(fmt, args...) fprintf(stderr, "[WARN] LZI>%s" fmt, __FUNCTION__, ##args) -#define iprintf(fmt, args...) fprintf(stdout, "[INFO] LZI>%s" fmt, __FUNCTION__, ##args) -#define eprintf(fmt, args...) fprintf(stderr, "[ERROR] LZI>%s" fmt, __FUNCTION__, ##args) - -static int lzi_read(IOStream *s, void *buf, size_t size, size_t count); -static int lzi_write(IOStream *s, const void *buf, size_t size, size_t count); -static int lzi_print(IOStream *s, const char *msg, va_list args); -static int lzi_getc(IOStream *s); -static int lzi_error(IOStream *s); -static int lzi_close(IOStream *s); -static void lzi_free(IOStream *s); -static int lzi_flush(IOStream *s); - -enum { - LZI_WRITE = 1, - LZI_READ = 2, -}; - -/** Methods used by a gzFile* IOStream. */ -static const IOMethods lzi_methods = { - read: lzi_read, - write: lzi_write, - print: lzi_print, - getc: lzi_getc, - error: lzi_error, - close: lzi_close, - free: lzi_free, - flush: lzi_flush, -}; - -#define BUFFER_SIZE (512 * 1024) - -typedef struct LZIState { - z_stream zstream; - void *inbuf; - uint32_t inbuf_size; - void *outbuf; - uint32_t outbuf_size; - /** Underlying stream for I/O. */ - IOStream *io; - /** Flags. */ - int flags; - /** Error indicator. */ - int error; - int eof; - int plain_bytes; - int comp_bytes; - int zstream_initialized; - int flushed; -} LZIState; - -static inline int LZIState_writeable(LZIState *s){ - return (s->flags & LZI_WRITE) != 0; -} - -static inline int LZIState_readable(LZIState *s){ - return (s->flags & LZI_READ) != 0; -} - -void LZIState_free(LZIState *z){ - if(!z) return; - if(z->zstream_initialized){ - if(LZIState_writeable(z)){ - deflateEnd(&z->zstream); - } else if(LZIState_readable(z)){ - inflateEnd(&z->zstream); - } - } - deallocate(z->inbuf); - deallocate(z->outbuf); - deallocate(z); -} - -static int mode_flags(const char *mode, int *flags){ - int err = 0; - int r=0, w=0; - if(!mode){ - err = -EINVAL; - goto exit; - } - for(; *mode; mode++){ - if(*mode == 'w') w = 1; - if(*mode == 'r') r = 1; - } - if(r + w != 1){ - err = -EINVAL; - goto exit; - } - if(r) *flags |= LZI_READ; - if(w) *flags |= LZI_WRITE; - exit: - return err; -} - -/** Get the stream state. - * - * @param s lzi stream - * @return stream state. - */ -static inline LZIState * lzi_state(IOStream *io){ - return io->data; -} - -IOStream *lzi_stream_io(IOStream *io){ - LZIState *s = lzi_state(io); - return s->io; -} - -static inline void set_error(LZIState *s, int err){ - if(err < 0 && !s->error){ - s->error = err; - } -} - -static int zerror(LZIState *s, int err){ - if(err){ - //dprintf("> err=%d\n", err); - if(err < 0) set_error(s, -EIO); - } - return s->error; -} - -int lzi_stream_plain_bytes(IOStream *io){ - LZIState *s = lzi_state(io); - return s->plain_bytes; -} - -int lzi_stream_comp_bytes(IOStream *io){ - LZIState *s = lzi_state(io); - return s->comp_bytes; -} - -float lzi_stream_ratio(IOStream *io){ - LZIState *s = lzi_state(io); - float ratio = 0.0; - if(s->comp_bytes){ - ratio = ((float) s->comp_bytes)/((float) s->plain_bytes); - } - return ratio; -} - -static int alloc(void **p, int n){ - *p = allocate(n); - return (p ? 0 : -ENOMEM); -} - -LZIState * LZIState_new(IOStream *io, int flags){ - int err = -ENOMEM; - int zlevel = Z_BEST_SPEED; // Level 1 compression - fastest. - int zstrategy = Z_DEFAULT_STRATEGY; - int zwindow = MAX_WBITS; - int zmemory = 8; - LZIState *z = ALLOCATE(LZIState); - - //dprintf(">\n"); - if(!z) goto exit; - z->io = io; - z->flags = flags; - - if(LZIState_writeable(z)){ - z->outbuf_size = BUFFER_SIZE; - /* windowBits is passed < 0 to suppress zlib header */ - err = deflateInit2(&z->zstream, zlevel, Z_DEFLATED, -zwindow, zmemory, zstrategy); - if (err != Z_OK) goto exit; - z->zstream_initialized = 1; - err = alloc(&z->outbuf, z->outbuf_size); - if(err) goto exit; - z->zstream.next_out = z->outbuf; - z->zstream.avail_out = z->outbuf_size; - } else { - z->inbuf_size = BUFFER_SIZE; - err = alloc(&z->inbuf, z->inbuf_size); - if(err) goto exit; - ///z->zstream.next_in = z->inbuf; - - /* windowBits is passed < 0 to tell that there is no zlib header. - * Note that in this case inflate *requires* an extra "dummy" byte - * after the compressed stream in order to complete decompression and - * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are - * present after the compressed stream. - */ - err = inflateInit2(&z->zstream, -zwindow); - if(err != Z_OK) goto exit; - z->zstream_initialized = 1; - } - - exit: - if(err){ - LZIState_free(z); - z = NULL; - } - //dprintf("< z=%p\n", z); - return z; -} - -int read_block(LZIState *s){ - int err = 0, k = 0; - //dprintf(">\n"); - if(s->eof) goto exit; - err = unmarshal_uint32(s->io, &k); - if(err) goto exit; - if(k > s->inbuf_size){ - err = -EINVAL; - goto exit; - } - if(k){ - err = unmarshal_bytes(s->io, s->inbuf, k); - if(err) goto exit; - } else { - s->eof = 1; - } - s->zstream.avail_in = k; - s->zstream.next_in = s->inbuf; - s->comp_bytes += 4; - s->comp_bytes += k; - exit: - //dprintf("< err=%d\n", err); - return err; -} - -int write_block(LZIState *s){ - int err = 0; - int k = ((char*)s->zstream.next_out) - ((char*)s->outbuf); - int k2 = s->outbuf_size - s->zstream.avail_out; - //dprintf("> k=%d k2=%d\n", k, k2); - if(!k) goto exit; - err = marshal_uint32(s->io, k); - if(err) goto exit; - err = marshal_bytes(s->io, s->outbuf, k); - if(err) goto exit; - s->zstream.next_out = s->outbuf; - s->zstream.avail_out = s->outbuf_size; - s->comp_bytes += 4; - s->comp_bytes += k; - exit: - //dprintf("< err=%d\n", err); - return err; -} - -int write_terminator(LZIState *s){ - int err = 0; - char c = 0; - err = marshal_uint32(s->io, 1); - if(err) goto exit; - err = marshal_bytes(s->io, &c, 1); - if(err) goto exit; - err = marshal_uint32(s->io, 0); - if(err) goto exit; - s->comp_bytes += 9; - exit: - return err; -} - -/** Write to the underlying stream using fwrite(); - * - * @param io destination - * @param buf data - * @param size size of data elements - * @param count number of data elements to write - * @return number of data elements written - */ -static int lzi_write(IOStream *io, const void *buf, size_t size, size_t count){ - int err = 0; - int n = size * count; - LZIState *s = lzi_state(io); - - //dprintf("> buf=%p size=%d count=%d n=%d\n", buf, size, count, n); - if(!LZIState_writeable(s)){ - err = -EINVAL; - goto exit; - } - s->flushed = 0; - s->zstream.next_in = (void*)buf; - s->zstream.avail_in = n; - while(s->zstream.avail_in){ - if(s->zstream.avail_out == 0){ - err = write_block(s); - if(err) goto exit; - } - //dprintf("> 1 deflate avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out); - //dprintf("> 1 deflate next_in=%p next_out=%p\n", s->zstream.next_in, s->zstream.next_out); - err = zerror(s, deflate(&s->zstream, Z_NO_FLUSH)); - //dprintf("> 2 deflate avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out); - //dprintf("> 2 deflate next_in=%p next_out=%p\n", s->zstream.next_in, s->zstream.next_out); - if(err) goto exit; - } - err = n; - s->plain_bytes += n; - if(size != 1) err /= size; - exit: - //dprintf("< err=%d\n", err); - return err; -} - - -/** Read from the underlying stream. - * - * @param io input - * @param buf where to put input - * @param size size of data elements - * @param count number of data elements to read - * @return number of data elements read - */ -static int lzi_read(IOStream *io, void *buf, size_t size, size_t count){ - int err, zerr; - int n = size * count; - LZIState *s = lzi_state(io); - - //dprintf("> size=%d count=%d n=%d\n", size, count, n); - if(!LZIState_readable(s)){ - err = -EINVAL; - goto exit; - } - s->zstream.next_out = buf; - s->zstream.avail_out = n; - while(s->zstream.avail_out){ - if(s->zstream.avail_in == 0){ - err = read_block(s); - } - //dprintf("> 1 deflate avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out); - zerr = inflate(&s->zstream, Z_NO_FLUSH); - //dprintf("> 2 deflate avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out); - if(zerr == Z_STREAM_END) break; - //dprintf("> zerr=%d\n", zerr); - err = zerror(s, zerr); - if(err) goto exit; - } - err = n - s->zstream.avail_out; - s->plain_bytes += err; - if(size != 1) err /= size; - exit: - set_error(s, err); - //dprintf("< err=%d\n", err); - return err; -} - -/** Print to the underlying stream. - * Returns 0 if the formatted output is too big for the internal buffer. - * - * @param io lzi stream - * @param msg format to use - * @param args arguments - * @return result of the print - */ -static int lzi_print(IOStream *io, const char *msg, va_list args){ - char buf[1024]; - int buf_n = sizeof(buf); - int n; - LZIState *s = lzi_state(io); - if(!LZIState_writeable(s)){ - n = -EINVAL; - goto exit; - } - n = vsnprintf(buf, buf_n, (char*)msg, args); - if(n < 0) goto exit; - if(n > buf_n){ - n = 0; - } else { - n = lzi_write(io, buf, 1, n); - } - exit: - return n; -} - -/** Read a character from the underlying stream - * - * @param io lzi stream - * @return character read, IOSTREAM_EOF on end of file (or error) - */ -static int lzi_getc(IOStream *io){ - int err; - char c; - err = lzi_read(io, &c, 1, 1); - if(err < 1) c = EOF; - err = (c==EOF ? IOSTREAM_EOF : c); - return err; -} - -static int flush_output(LZIState *s, int mode){ - int err = 0, zerr; - int done = 0; - int avail_out_old; - int count = 10; - - //dprintf("> avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out); - if(s->flushed == 1 + mode) goto exit; - //s->zstream.avail_in = 0; /* should be zero already anyway */ - for(;;){ - // Write any available output. - if(done || s->zstream.avail_out == 0){ - err = write_block(s); - if(err) goto exit; - if(done) break; - } - //dprintf("> 1 deflate avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out); - avail_out_old = s->zstream.avail_out; - zerr = deflate(&s->zstream, mode); - err = zerror(s, zerr); - //dprintf("> 2 deflate avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out); - //dprintf("> deflate=%d\n", err); - //done = (s->zstream.avail_out != 0); - //done = (s->zstream.avail_in == 0) && (s->zstream.avail_out == avail_out_old); - if(0 && mode == Z_FINISH){ - done = (zerr == Z_STREAM_END); - } else { - done = (s->zstream.avail_in == 0) - //&& (s->zstream.avail_out == avail_out_old) - && (s->zstream.avail_out != 0); - } - } - s->flushed = 1 + mode; - exit: - //dprintf("< err=%d\n", err); - return err; -} - -/** Flush any pending input to the underlying stream. - * - * @param s lzi stream - * @return 0 on success, error code otherwise - */ -static int lzi_flush(IOStream *io){ - int err = 0; - LZIState *s = lzi_state(io); - //dprintf(">\n"); - if(!LZIState_writeable(s)){ - err = -EINVAL; - goto exit; - } - err = flush_output(s, Z_SYNC_FLUSH); - if(err) goto exit; - err = IOStream_flush(s->io); - exit: - set_error(s, err); - //dprintf("< err=%d\n", err); - return (err < 0 ? err : 0); -} - -/** Check if a stream has an error. - * - * @param s lzi stream - * @return code if has an error, 0 otherwise - */ -static int lzi_error(IOStream *s){ - int err = 0; - LZIState *state = lzi_state(s); - err = state->error; - if(err) goto exit; - err = IOStream_error(state->io); - exit: - return err; -} - -/** Close an lzi stream. - * - * @param s lzi stream to close - * @return result of the close - */ -static int lzi_close(IOStream *io){ - int err = 0; - LZIState *s = lzi_state(io); - if(LZIState_writeable(s)){ - err = flush_output(s, Z_FINISH); - if(err) goto exit; - err = write_terminator(s); - if(err) goto exit; - err = IOStream_flush(s->io); - } - exit: - err = IOStream_close(s->io); - set_error(s, err); - return err; -} - -/** Free an lzi stream. - * - * @param s lzi stream - */ -static void lzi_free(IOStream *s){ - LZIState *state = lzi_state(s); - IOStream_free(state->io); - LZIState_free(state); - s->data = NULL; -} - -/** Create an lzi stream for an IOStream. - * - * @param io stream to wrap - * @return new IOStream using f for i/o - */ -IOStream *lzi_stream_new(IOStream *io, const char *mode){ - int err = -ENOMEM; - int flags = 0; - IOStream *zio = NULL; - LZIState *state = NULL; - - zio = ALLOCATE(IOStream); - if(!zio) goto exit; - err = mode_flags(mode, &flags); - if(err) goto exit; - state = LZIState_new(io, flags); - if(!state) goto exit; - err = 0; - zio->data = state; - zio->methods = &lzi_methods; - exit: - if(err){ - if(state) LZIState_free(state); - if(zio) deallocate(zio); - zio = NULL; - } - return zio; -} - -/** IOStream version of fdopen(). - * - * @param fd file descriptor - * @param flags giving the mode to open in (as for fdopen()) - * @return new stream for the open file, or NULL if failed - */ -IOStream *lzi_stream_fdopen(int fd, const char *mode){ - int err = -ENOMEM; - IOStream *io = NULL, *zio = NULL; - io = file_stream_fdopen(fd, mode); - if(!io) goto exit; - zio = lzi_stream_new(io, mode); - if(!io) goto exit; - err = 0; - exit: - if(err){ - IOStream_free(io); - IOStream_free(zio); - zio = NULL; - } - return zio; -} -#endif diff --git a/tools/libxutil/lzi_stream.h b/tools/libxutil/lzi_stream.h deleted file mode 100644 index 0ad4f8db8e..0000000000 --- a/tools/libxutil/lzi_stream.h +++ /dev/null @@ -1,36 +0,0 @@ -#/* $Id: lzi_stream.h,v 1.3 2003/09/30 15:22:53 mjw Exp $ */ -/* - * Copyright (C) 2003 Hewlett-Packard Company. - * - * 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.1 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 - */ - -#ifndef _SP_LZI_STREAM_H_ -#define _SP_LZI_STREAM_H_ - -#ifndef __KERNEL__ -#include "iostream.h" - -extern IOStream *lzi_stream_new(IOStream *io, const char *mode); -extern IOStream *lzi_stream_fopen(const char *file, const char *mode); -extern IOStream *lzi_stream_fdopen(int fd, const char *mode); -extern IOStream *lzi_stream_io(IOStream *zio); - -extern int lzi_stream_plain_bytes(IOStream *io); -extern int lzi_stream_comp_bytes(IOStream *io); -extern float lzi_stream_ratio(IOStream *io); - -#endif -#endif /* !_SP_FILE_STREAM_H_ */ diff --git a/tools/libxutil/lzo_stream.c b/tools/libxutil/lzo_stream.c deleted file mode 100644 index bf7c348471..0000000000 --- a/tools/libxutil/lzo_stream.c +++ /dev/null @@ -1,596 +0,0 @@ -/* $Id: lzo_stream.c,v 1.4 2003/09/30 15:22:53 mjw Exp $ */ -#define __FILE_ID_INFO "$Id: lzo_stream.c,v 1.4 2003/09/30 15:22:53 mjw Exp $" -#include -static char __rcsid[] __attribute__((unused)) = WHAT_ID __FILE_ID_INFO; -/* - * Copyright (C) 2003 Hewlett-Packard Company. - * - * 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.1 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 - */ - -/** @file - * An IOStream implementation using LZO to provide compression and decompression. - * This is designed to provide reasonable compression without output latency. - * Flushing an LZO stream flushes all pending data to the underlying stream. - * This is essential for stream-based (e.g. networked) applications. - * - * A compressed data stream is a sequence of blocks. - * Each block except the last is the plain data size followed by the compressed data size - * and the compressed data. The last block has plain data size zero and omits the rest. - * Sizes are 4-byte unsigned in network order. If the compressed size is smaller than - * the plain size the block data is compressed, otherwise it is plain (uncompressed). - * - * This format allows compressed data to be read from a stream without reading - * past the logical end of compressed data. - * - * @author Mike Wray - */ -#ifndef __KERNEL__ - -#include -#include -#include -#include - -#include "lzo1x.h" - -#include "allocate.h" -#include "lzo_stream.h" -#include "file_stream.h" -#include "marshal.h" - -#define dprintf(fmt, args...) fprintf(stdout, "[DEBUG] LZO>%s" fmt, __FUNCTION__, ##args) -#define wprintf(fmt, args...) fprintf(stderr, "[WARN] LZO>%s" fmt, __FUNCTION__, ##args) -#define iprintf(fmt, args...) fprintf(stdout, "[INFO] LZO>%s" fmt, __FUNCTION__, ##args) -#define eprintf(fmt, args...) fprintf(stderr, "[ERROR] LZO>%s" fmt, __FUNCTION__, ##args) - -static int lzo_read(IOStream *s, void *buf, size_t size, size_t count); -static int lzo_write(IOStream *s, const void *buf, size_t size, size_t count); -static int lzo_print(IOStream *s, const char *msg, va_list args); -static int lzo_getc(IOStream *s); -static int lzo_error(IOStream *s); -static int lzo_close(IOStream *s); -static void lzo_free(IOStream *s); -static int lzo_flush(IOStream *s); - -enum { - LZO_WRITE = 1, - LZO_READ = 2, -}; - -/** Methods used by a gzFile* IOStream. */ -static const IOMethods lzo_methods = { - read: lzo_read, - write: lzo_write, - print: lzo_print, - getc: lzo_getc, - error: lzo_error, - close: lzo_close, - free: lzo_free, - flush: lzo_flush, -}; - -//#define PLAIN_SIZE (64 * 1024) -//#define PLAIN_SIZE (128 * 1024) -#define PLAIN_SIZE (512 * 1024) - -//#define NOCOMPRESS - -typedef struct LZOState { - /** Flags. */ - int flags; - /** Error indicator. */ - int error; - /** Underlying stream for I/O. */ - IOStream *io; - /** Working memory (only needed for compression, not decompression). */ - lzo_byte *memory; - /** Buffer for plain (uncompressed) data. */ - lzo_byte *plain; - /** Size of the plain buffer. */ - lzo_uint plain_size; - /** Pointer into the plain buffer. */ - lzo_byte *plain_ptr; - /** Number of bytes of plain data available. */ - lzo_uint plain_n; - /** Buffer for compressed data. */ - lzo_byte *comp; - /** Size of the compressed buffer. */ - lzo_uint comp_size; - - int plain_bytes; - int comp_bytes; -} LZOState; - -void LZOState_free(LZOState *z){ - if(!z) return; - deallocate(z->memory); - deallocate(z->plain); - deallocate(z->comp); - deallocate(z); -} - -/** Maximum size of compressed data for the given plain data size. - * - * @param plain_size size of plain data - * @return maximum size of compressed data - */ -static int comp_size(int plain_size){ - return plain_size + (plain_size / 64) + 16 + 3; -} - -static int mode_flags(const char *mode, int *flags){ - int err = 0; - int r=0, w=0; - if(!mode){ - err = -EINVAL; - goto exit; - } - for(; *mode; mode++){ - if(*mode == 'w') w = 1; - if(*mode == 'r') r = 1; - } - if(r + w != 1){ - err = -EINVAL; - goto exit; - } - if(r) *flags |= LZO_READ; - if(w) *flags |= LZO_WRITE; - exit: - return err; -} - -/** Get the stream state. - * - * @param s lzo stream - * @return stream state. - */ -static inline LZOState * lzo_state(IOStream *s){ - return s->data; -} - -IOStream *lzo_stream_io(IOStream *s){ - LZOState *state = lzo_state(s); - return state->io; -} - -static inline void set_error(LZOState *state, int err){ - if(err < 0 && !state->error){ - state->error = err; - } -} - -int lzo_stream_plain_bytes(IOStream *s){ - LZOState *state = lzo_state(s); - return state->plain_bytes; -} - -int lzo_stream_comp_bytes(IOStream *s){ - LZOState *state = lzo_state(s); - return state->comp_bytes; -} - -float lzo_stream_ratio(IOStream *s){ - LZOState *state = lzo_state(s); - float ratio = 0.0; - if(state->comp_bytes){ - ratio = ((float) state->comp_bytes)/((float) state->plain_bytes); - } - return ratio; -} - -static inline int LZOState_writeable(LZOState *state){ - return (state->flags & LZO_WRITE) != 0; -} - -static inline int LZOState_readable(LZOState *state){ - return (state->flags & LZO_READ) != 0; -} - -LZOState * LZOState_new(IOStream *io, int flags){ - int err = -ENOMEM; - LZOState *z = ALLOCATE(LZOState); - //dprintf(">\n"); - if(!z) goto exit; - z->io = io; - z->flags = flags; - if(LZOState_writeable(z)){ - z->memory = allocate(LZO1X_1_MEM_COMPRESS); - if(!z->memory) goto exit; - } - z->plain_size = PLAIN_SIZE; - z->plain = allocate(z->plain_size); - if(!z->plain) goto exit; - z->plain_ptr = z->plain; - z->comp_size = comp_size(z->plain_size); - z->comp = allocate(z->comp_size); - if(!z->comp) goto exit; - err = 0; - exit: - if(err){ - LZOState_free(z); - z = NULL; - } - //dprintf("< z=%p\n", z); - return z; -} - -static int lzo_compress(LZOState *state){ - int err = 0; - int k, comp_n; - //dprintf(">\n"); - //dprintf(">plain=%p plain_n=%d comp=%p memory=%p\n", state->plain, state->plain_n, state->comp, state->memory); - // Compress the plain buffer. - err = lzo1x_1_compress(state->plain, state->plain_n, - state->comp, &comp_n, - state->memory); - //dprintf("> err=%d plain_n=%d comp_n=%d\n", err, state->plain_n, comp_n); - // Write plain size, compressed size. - err = marshal_uint32(state->io, state->plain_n); - if(err) goto exit; - err = marshal_uint32(state->io, comp_n); - if(err) goto exit; - //dprintf("> write data...\n"); - // Write the smaller of the compressed and plain data. - if(state->plain_n < comp_n){ - k = state->plain_n; - err = marshal_bytes(state->io, state->plain, state->plain_n); - } else { - k = comp_n; - err = marshal_bytes(state->io, state->comp, comp_n); - } - if(err) goto exit; - // Total output bytes. - k+= 8; - //dprintf("> wrote %d bytes\n", k); - state->plain_bytes += state->plain_n; - state->comp_bytes += k; - //dprintf("> plain=%d, comp=%d, ratio=%3.2f\n", - // state->plain_bytes, state->comp_bytes, - // ((float)state->comp_bytes)/((float)state->plain_bytes)); - // Reset the plain buffer. - state->plain_ptr = state->plain; - state->plain_n = 0; - err = k; - exit: - //dprintf("< err=%d\n", err); - return err; -} - -static int lzo_decompress(LZOState *state){ - int plain_n, comp_n; - int err, k; - //dprintf(">\n"); - err = unmarshal_uint32(state->io, &plain_n); - //dprintf("> err=%d plain_n=%d\n", err, plain_n); - if(err) goto exit; - state->comp_bytes += 4; - if(plain_n == 0) goto exit; - err = unmarshal_uint32(state->io, &comp_n); - //dprintf("> err=%d comp_n=%d\n", err, comp_n); - if(err) goto exit; - state->comp_bytes += 4; - if(plain_n > state->plain_size){ - err = -EINVAL; - goto exit; - } - if(comp_n > plain_n){ - //dprintf("> reading plain data %d...\n", plain_n); - k = plain_n; - err = unmarshal_bytes(state->io, state->plain, plain_n); - state->plain_n = plain_n; - } else { - //dprintf("> reading comp data %d...\n", comp_n); - k = comp_n; - err = unmarshal_bytes(state->io, state->comp, comp_n); - //dprintf("> decompress comp_n=%d\n", comp_n); - err = lzo1x_decompress(state->comp, comp_n, - state->plain, &state->plain_n, - state->memory); - //dprintf("> err=%d plain=%d state->plain_n=%d\n", err, plain_n, state->plain_n); - if(err != LZO_E_OK || state->plain_n != plain_n){ - // Bad. Corrupted input. - err = -EINVAL; - eprintf("> Corrupted!\n"); - goto exit; - } - } - state->comp_bytes += k; - state->plain_bytes += state->plain_n; - state->plain_ptr = state->plain; - err = k; - exit: - //dprintf("< err=%d\n", err); - return err; -} - -/** Write to the underlying stream using fwrite(); - * - * @param stream destination - * @param buf data - * @param size size of data elements - * @param count number of data elements to write - * @return number of data elements written - */ -static int lzo_write(IOStream *s, const void *buf, size_t size, size_t count){ - int err = 0; - int n = size * count; // Total number of bytes to write. - int chunk; // Size of chunk to write. - int remaining; // Number of bytes remaining to write. - int space; // Amount of space left in plain buffer. - LZOState *state = lzo_state(s); -#ifdef NOCOMPRESS - //dprintf("> buf=%p size=%d count=%d\n", buf, size, count); - err = IOStream_write(state->io, buf, size, count); - //dprintf("< err=%d\n", err); -#else - //dprintf("> buf=%p size=%d count=%d n=%d\n", buf, size, count, n); - remaining = n; - space = state->plain_size - state->plain_n; - //dprintf("> plain=%p plain_ptr=%p plain_n=%d space=%d\n", - // state->plain, state->plain_ptr, state->plain_n, space); - while(remaining){ - chunk = remaining; - if(chunk > space) chunk = space; - //dprintf("> memcpy %p %p %d\n", state->plain_ptr, buf, chunk); - memcpy(state->plain_ptr, buf, chunk); - remaining -= chunk; - space -= chunk; - state->plain_ptr += chunk; - state->plain_n += chunk; - if(space == 0){ - // Input buffer is full. Compress and write it. - err = lzo_compress(state); - if(err < 0) goto exit; - space = state->plain_size - state->plain_n; - } - } - err = (size > 1 ? n / size : n); - exit: - set_error(state, err); -#endif - return err; -} - - -/** Read from the underlying stream. - * - * @param stream input - * @param buf where to put input - * @param size size of data elements - * @param count number of data elements to read - * @return number of data elements read - */ -static int lzo_read(IOStream *s, void *buf, size_t size, size_t count){ - int err = 0; - int k = 0; // Number of (plain) bytes read. - int remaining = size * count; // Number of bytes remaining to read. - int chunk; // Size of chunk to read. - LZOState *state = lzo_state(s); -#ifdef NOCOMPRESS - //dprintf("> buf=%p size=%d count=%d\n", buf, size, count); - err = IOStream_read(state->io, buf, size, count); - //dprintf("< err=%d\n", err); -#else - if(!(state->flags & LZO_READ)){ - err = -EINVAL; - goto exit; - } - while(remaining){ - if(state->plain_n == 0){ - // No more plain input, decompress some more. - err = lzo_decompress(state); - if(err < 0) goto exit; - // Stop reading if there is no more input. - if(err == 0 || state->plain_n == 0) break; - } - chunk = remaining; - if(chunk > state->plain_n) chunk = state->plain_n; - memcpy(buf, state->plain_ptr, chunk); - k += chunk; - buf += chunk; - state->plain_ptr += chunk; - state->plain_n -= chunk; - remaining -= chunk; - } - err = k; - exit: - set_error(state, err); -#endif - return err; -} - -/** Print to the underlying stream. - * Returns 0 if the formatted output is too big for the internal buffer. - * - * @param s lzo stream - * @param msg format to use - * @param args arguments - * @return result of the print - */ -static int lzo_print(IOStream *s, const char *msg, va_list args){ - char buf[1024]; - int buf_n = sizeof(buf); - int n; - LZOState *state = lzo_state(s); - if(!LZOState_writeable(state)){ - n = -EINVAL; - goto exit; - } - n = vsnprintf(buf, buf_n, (char*)msg, args); - if(n < 0) goto exit; - if(n > buf_n){ - n = 0; - } else { - n = lzo_write(s, buf, 1, n); - } - exit: - return n; -} - -/** Read a character from the underlying stream - * - * @param s lzo stream - * @return character read, IOSTREAM_EOF on end of file (or error) - */ -static int lzo_getc(IOStream *s){ - int err; - char c; - err = lzo_read(s, &c, 1, 1); - if(err < 1) c = EOF; - err = (c==EOF ? IOSTREAM_EOF : c); - return err; -} - -/** Flush any pending input to the underlying stream. - * - * @param s lzo stream - * @return 0 on success, error code otherwise - */ -static int lzo_flush(IOStream *s){ - int err = 0; - LZOState *state = lzo_state(s); - //dprintf(">\n"); -#ifdef NOCOMPRESS - err = IOStream_flush(state->io); -#else - if(!LZOState_writeable(state)){ - err = -EINVAL; - goto exit; - } - if(state->plain_n){ - err = lzo_compress(state); - if(err < 0) goto exit; - } - err = IOStream_flush(state->io); - exit: - set_error(state, err); -#endif - //dprintf("< err=%d\n", err); - return (err < 0 ? err : 0); -} - -/** Check if a stream has an error. - * - * @param s lzo stream - * @return code if has an error, 0 otherwise - */ -static int lzo_error(IOStream *s){ - int err = 0; - LZOState *state = lzo_state(s); - err = state->error; - if(err) goto exit; - err = IOStream_error(state->io); - exit: - return err; -} - -int lzo_stream_finish(IOStream *s){ - int err = 0; - LZOState *state = lzo_state(s); - if(!LZOState_writeable(state)){ - err = -EINVAL; - goto exit; - } - err = lzo_flush(s); - if(err < 0) goto exit; - err = marshal_int32(state->io, 0); - exit: - return err; -} - -/** Close an lzo stream. - * - * @param s lzo stream to close - * @return result of the close - */ -static int lzo_close(IOStream *s){ - int err = 0; - LZOState *state = lzo_state(s); -#ifdef NOCOMPRESS - err = IOStream_close(state->io); -#else - if(LZOState_writeable(state)){ - err = lzo_stream_finish(s); - } - err = IOStream_close(state->io); - set_error(state, err); -#endif - return err; -} - -/** Free an lzo stream. - * - * @param s lzo stream - */ -static void lzo_free(IOStream *s){ - LZOState *state = lzo_state(s); - IOStream_free(state->io); - LZOState_free(state); - s->data = NULL; -} - -/** Create an lzo stream for an IOStream. - * - * @param io stream to wrap - * @return new IOStream using f for i/o - */ -IOStream *lzo_stream_new(IOStream *io, const char *mode){ - int err = -ENOMEM; - int flags = 0; - IOStream *zio = NULL; - LZOState *state = NULL; - - zio = ALLOCATE(IOStream); - if(!zio) goto exit; - err = mode_flags(mode, &flags); - if(err) goto exit; - state = LZOState_new(io, flags); - if(!state) goto exit; - err = 0; - zio->data = state; - zio->methods = &lzo_methods; - exit: - if(err){ - if(state) LZOState_free(state); - if(zio) deallocate(zio); - zio = NULL; - } - return zio; -} - -/** IOStream version of fdopen(). - * - * @param fd file descriptor - * @param flags giving the mode to open in (as for fdopen()) - * @return new stream for the open file, or NULL if failed - */ -IOStream *lzo_stream_fdopen(int fd, const char *mode){ - int err = -ENOMEM; - IOStream *io = NULL, *zio = NULL; - io = file_stream_fdopen(fd, mode); - if(!io) goto exit; - zio = lzo_stream_new(io, mode); - if(!io) goto exit; - err = 0; - exit: - if(err){ - IOStream_free(io); - IOStream_free(zio); - zio = NULL; - } - return zio; -} -#endif diff --git a/tools/libxutil/lzo_stream.h b/tools/libxutil/lzo_stream.h deleted file mode 100644 index 493da7b1ad..0000000000 --- a/tools/libxutil/lzo_stream.h +++ /dev/null @@ -1,36 +0,0 @@ -#/* $Id: lzo_stream.h,v 1.3 2003/09/30 15:22:53 mjw Exp $ */ -/* - * Copyright (C) 2003 Hewlett-Packard Company. - * - * 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.1 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 - */ - -#ifndef _SP_LZO_STREAM_H_ -#define _SP_LZO_STREAM_H_ - -#ifndef __KERNEL__ -#include "iostream.h" - -extern IOStream *lzo_stream_new(IOStream *io, const char *mode); -extern IOStream *lzo_stream_fopen(const char *file, const char *mode); -extern IOStream *lzo_stream_fdopen(int fd, const char *mode); -extern IOStream *lzo_stream_io(IOStream *zio); - -extern int lzo_stream_plain_bytes(IOStream *io); -extern int lzo_stream_comp_bytes(IOStream *io); -extern float lzo_stream_ratio(IOStream *io); - -#endif -#endif /* !_SP_FILE_STREAM_H_ */ diff --git a/tools/libxutil/marshal.c b/tools/libxutil/marshal.c deleted file mode 100644 index 21691d4412..0000000000 --- a/tools/libxutil/marshal.c +++ /dev/null @@ -1,207 +0,0 @@ -#include -#include "sys_net.h" -#include "allocate.h" -#include "marshal.h" - -#define dprintf(fmt, args...) IOStream_print(iostdout, "[DEBUG] %s" fmt, __FUNCTION__, ##args) -#define wprintf(fmt, args...) IOStream_print(iostderr, "[WARN] %s" fmt, __FUNCTION__, ##args) -#define iprintf(fmt, args...) IOStream_print(iostdout, "[INFO] %s" fmt, __FUNCTION__, ##args) -#define eprintf(fmt, args...) IOStream_print(iostderr, "[ERROR] %s" fmt, __FUNCTION__, ##args) - - -#define ARRAY_SIZE(ary) (sizeof(ary)/sizeof((ary)[0])) - -/* Messages are coded as msgid followed by message fields. - * Initial message on any channel is hello - so can check version - * compatibility. - * - * char* -> uint16_t:n - * ints/uints go as suitable number of bytes (e.g. uint16_t is 2 bytes). - * optional fields go as '1' or '0' (the 0/1 is 1 byte). - * lists go as ('1' )* '0' - */ - -int marshal_flush(IOStream *io){ - int err = 0; - err = IOStream_flush(io); - return err; -} - -int marshal_bytes(IOStream *io, void *s, uint32_t s_n){ - int err = 0; - int n; - n = IOStream_write(io, s, s_n); - if(n < 0){ - err = n; - } else if (n < s_n){ - wprintf("> Wanted %d, got %d\n", s_n, n); - err = -EIO; - } - return err; -} - -int unmarshal_bytes(IOStream *io, void *s, uint32_t s_n){ - int err = 0; - int n; - //dprintf("> s_n=%d\n", s_n); - n = IOStream_read(io, s, s_n); - //dprintf("> n=%d\n", n); - if(n < 0){ - err = n; - } else if(n < s_n){ - wprintf("> Wanted %d, got %d\n", s_n, n); - err = -EIO; - } - //dprintf("< err=%d\n", err); - return err; -} - -int marshal_uint8(IOStream *io, uint8_t x){ - return marshal_bytes(io, &x, sizeof(x)); -} - -int unmarshal_uint8(IOStream *io, uint8_t *x){ - return unmarshal_bytes(io, x, sizeof(*x)); -} - -int marshal_uint16(IOStream *io, uint16_t x){ - x = htons(x); - return marshal_bytes(io, &x, sizeof(x)); -} - -int unmarshal_uint16(IOStream *io, uint16_t *x){ - int err = 0; - err = unmarshal_bytes(io, x, sizeof(*x)); - *x = ntohs(*x); - return err; -} - -int marshal_int32(IOStream *io, int32_t x){ - int err = 0; - //dprintf("> x=%d\n", x); - x = htonl(x); - err = marshal_bytes(io, &x, sizeof(x)); - //dprintf("< err=%d\n", err); - return err; -} - -int unmarshal_int32(IOStream *io, int32_t *x){ - int err = 0; - //dprintf(">\n"); - err = unmarshal_bytes(io, x, sizeof(*x)); - *x = ntohl(*x); - //dprintf("< err=%d x=%d\n", err, *x); - return err; -} - -int marshal_uint32(IOStream *io, uint32_t x){ - int err = 0; - //dprintf("> x=%u\n", x); - x = htonl(x); - err = marshal_bytes(io, &x, sizeof(x)); - //dprintf("< err=%d\n", err); - return err; -} - -int unmarshal_uint32(IOStream *io, uint32_t *x){ - int err = 0; - //dprintf(">\n"); - err = unmarshal_bytes(io, x, sizeof(*x)); - *x = ntohl(*x); - //dprintf("< err=%d x=%u\n", err, *x); - return err; -} - -int marshal_uint64(IOStream *io, uint64_t x){ - int err; - err = marshal_uint32(io, (uint32_t) ((x >> 32) & 0xffffffff)); - if(err) goto exit; - err = marshal_uint32(io, (uint32_t) ( x & 0xffffffff)); - exit: - return err; -} - -int unmarshal_uint64(IOStream *io, uint64_t *x){ - int err = 0; - uint32_t hi, lo; - err = unmarshal_uint32(io, &hi); - if(err) goto exit; - err = unmarshal_uint32(io, &lo); - *x = (((uint64_t) hi) << 32) | lo; - exit: - return err; -} - -int marshal_net16(IOStream *io, net16_t x){ - return marshal_bytes(io, &x, sizeof(x)); -} - -int unmarshal_net16(IOStream *io, net16_t *x){ - int err = 0; - err = unmarshal_bytes(io, x, sizeof(*x)); - return err; -} - -int marshal_net32(IOStream *io, net32_t x){ - return marshal_bytes(io, &x, sizeof(x)); -} - -int unmarshal_net32(IOStream *io, net32_t *x){ - int err = 0; - err = unmarshal_bytes(io, x, sizeof(*x)); - return err; -} - -int marshal_string(IOStream *io, char *s, uint32_t s_n){ - int err; - //dprintf("> s=%s\n", s); - err = marshal_uint32(io, s_n); - if(err) goto exit; - err = marshal_bytes(io, s, s_n); - exit: - //dprintf("< err=%d\n", err); - return err; -} - -int unmarshal_string(IOStream *io, char *s, uint32_t s_n){ - int err = 0, val_n = 0; - //dprintf(">\n"); - err = unmarshal_uint32(io, &val_n); - if(err) goto exit; - if(val_n >= s_n){ - err = -EINVAL; - goto exit; - } - err = unmarshal_bytes(io, s, val_n); - if(err) goto exit; - s[val_n] = '\0'; - exit: - //dprintf("< err=%d s=%s\n", err, s); - return err; -} - -int unmarshal_new_string(IOStream *io, char **s, uint32_t *s_n){ - int err = 0, val_n = 0; - char *val = NULL; - //dprintf(">\n"); - err = unmarshal_uint32(io, &val_n); - if(err) goto exit; - val = allocate(val_n + 1); - if(!val){ - err = -ENOMEM; - goto exit; - } - err = unmarshal_bytes(io, val, val_n); - if(err) goto exit; - val[val_n] = '\0'; - exit: - if(err){ - if(val) deallocate(val); - val = NULL; - val_n = 0; - } - *s = val; - if(s_n) *s_n = val_n; - //dprintf("< err=%d s=%s\n", err, *s); - return err; -} diff --git a/tools/libxutil/marshal.h b/tools/libxutil/marshal.h deleted file mode 100644 index 9a9d465b9b..0000000000 --- a/tools/libxutil/marshal.h +++ /dev/null @@ -1,43 +0,0 @@ -/* $Id: marshal.h,v 1.1 2003/10/17 15:48:43 mjw Exp $ */ -#ifndef _SP_MARSHAL_H_ -#define _SP_MARSHAL_H_ - -#include "iostream.h" - -/** A 16-bit uint in network order, e.g. a port number. */ -typedef uint16_t net16_t; - -/** A 32-bit uint in network order, e.g. an IP address. */ -typedef uint32_t net32_t; - -extern int marshal_flush(IOStream *io); - -extern int marshal_bytes(IOStream *io, void *s, uint32_t s_n); -extern int unmarshal_bytes(IOStream *io, void *s, uint32_t s_n); - -extern int marshal_uint8(IOStream *io, uint8_t x); -extern int unmarshal_uint8(IOStream *io, uint8_t *x); - -extern int marshal_uint16(IOStream *io, uint16_t x); -extern int unmarshal_uint16(IOStream *io, uint16_t *x); - -extern int marshal_uint32(IOStream *io, uint32_t x); -extern int unmarshal_uint32(IOStream *io, uint32_t *x); - -extern int marshal_int32(IOStream *io, int32_t x); -extern int unmarshal_int32(IOStream *io, int32_t *x); - -extern int marshal_uint64(IOStream *io, uint64_t x); -extern int unmarshal_uint64(IOStream *io, uint64_t *x); - -extern int marshal_net16(IOStream *io, net16_t x); -extern int unmarshal_net16(IOStream *io, net16_t *x); - -extern int marshal_net32(IOStream *io, net32_t x); -extern int unmarshal_net32(IOStream *io, net32_t *x); - -extern int marshal_string(IOStream *io, char *s, uint32_t s_n); -extern int unmarshal_string(IOStream *io, char *s, uint32_t s_n); -extern int unmarshal_new_string(IOStream *io, char **s, uint32_t *s_n); - -#endif /* ! _SP_MARSHAL_H_ */ diff --git a/tools/libxutil/socket_stream.c b/tools/libxutil/socket_stream.c deleted file mode 100644 index cfa6e3abf0..0000000000 --- a/tools/libxutil/socket_stream.c +++ /dev/null @@ -1,259 +0,0 @@ -/* $Id: socket_stream.c,v 1.9 2004/03/05 14:45:34 mjw Exp $ */ -/* - * Copyright (C) 2004 Mike Wray - * - * 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.1 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 - */ - -/** @file - * An IOStream implementation using sockets. - */ - -#include -#include -#include -#include -#include -#include "allocate.h" -#include "socket_stream.h" - -#define MODULE_NAME "sock" -#define DEBUG 0 -//#undef DEBUG -#include "debug.h" - -static int socket_read(IOStream *s, void *buf, size_t n); -static int socket_write(IOStream *s, const void *buf, size_t n); -static int socket_error(IOStream *s); -static int socket_close(IOStream *s); -static void socket_free(IOStream *s); -static int socket_flush(IOStream *s); - -/** Methods used by a socket IOStream. */ -static const IOMethods socket_methods = { - read: socket_read, - write: socket_write, - error: socket_error, - close: socket_close, - free: socket_free, - flush: socket_flush, -}; - -/** Get the socket data. - * - * @param io socket stream - * @return data - */ -static inline SocketData * socket_data(IOStream *io){ - return (SocketData *)io->data; -} - -/** Test if a stream is a socket stream. - * - * @param io stream - * @return 0 if a socket stream, -EINVAL if not - */ -int socket_stream_check(IOStream *io){ - return (io && io->methods == &socket_methods ? 0 : -EINVAL); -} - -/** Get the data for a socket stream. - * - * @param io stream - * @param data return value for the data - * @return 0 if a socket stream, -EINVAL if not - */ -int socket_stream_data(IOStream *io, SocketData **data){ - int err = socket_stream_check(io); - if(err){ - *data = NULL; - } else { - *data = socket_data(io); - } - return err; -} - -/** Set the destination address for a socket stream. - * - * @param io stream - * @param addr address - * @return 0 if a socket stream, -EINVAL if not - */ -int socket_stream_set_addr(IOStream *io, struct sockaddr_in *addr){ - int err = 0; - SocketData *data = NULL; - err = socket_stream_data(io, &data); - if(!err){ - data->daddr = *addr; - } - return err; -} - -/** Set the send flags for a socket stream. - * - * @param io stream - * @param flags flags - * @return 0 if a socket stream, -EINVAL if not - */ -int socket_stream_set_flags(IOStream *io, int flags){ - int err = 0; - SocketData *data = NULL; - err = socket_stream_data(io, &data); - if(!err){ - data->flags = flags; - } - return err; -} - -/** Write to the underlying socket using sendto. - * - * @param stream input - * @param buf where to put input - * @param n number of bytes to write - * @return number of bytes written - */ -static int socket_write(IOStream *s, const void *buf, size_t n){ - SocketData *data = socket_data(s); - struct sockaddr *daddr = (struct sockaddr *)&data->daddr; - socklen_t daddr_n = sizeof(data->daddr); - int k; - dprintf("> sock=%d addr=%s:%d n=%d\n", - data->fd, inet_ntoa(data->daddr.sin_addr), ntohs(data->daddr.sin_port), n); - if(0){ - struct sockaddr_in self = {}; - socklen_t self_n; - getsockname(data->fd, (struct sockaddr *)&self, &self_n); - dprintf("> sockname sock=%d %s:%d\n", - data->fd, inet_ntoa(self.sin_addr), ntohs(self.sin_port)); - } - k = sendto(data->fd, buf, n, data->flags, daddr, daddr_n); - dprintf("> sendto=%d\n", k); - return k; -} - -/** Read from the underlying stream using recv(); - * - * @param stream input - * @param buf where to put input - * @param n number of bytes to read - * @return number of bytes read - */ -static int socket_read(IOStream *s, void *buf, size_t n){ - SocketData *data = socket_data(s); - int k; - struct sockaddr *saddr = (struct sockaddr *)&data->saddr; - socklen_t saddr_n = sizeof(data->saddr); - k = recvfrom(data->fd, buf, n, data->flags, saddr, &saddr_n); - return k; -} - -/** Print to the underlying socket. - * - * @param s socket stream - * @param msg format to use - * @param args arguments - * @return result of the print - */ -static int socket_print(IOStream *s, const char *msg, va_list args){ - SocketData *data = socket_data(s); - int n; - n = vsnprintf(data->buf, data->buf_n - 1, msg, args); - if(0 < n && n < data->buf_n){ - socket_write(s, data->buf, n); - } - return n; -} - -/** Read a character from the underlying socket - * - * @param s socket stream - * @return character read, IOSTREAM_EOF on end of socket (or error) - */ -static int socket_getc(IOStream *s){ - char b; - int n, c; - n = socket_read(s, &b, 1); - c = (n <= 0 ? IOSTREAM_EOF : b); - return c; -} - -/** Flush the socket (no-op). - * - * @param s socket stream - * @return 0 on success, error code otherwise - */ -static int socket_flush(IOStream *s){ - return 0; -} - -/** Check if a socket stream has an error (no-op). - * - * @param s socket stream - * @return 1 if has an error, 0 otherwise - */ -static int socket_error(IOStream *s){ - // Read SOL_SOCKET/SO_ERROR ? - return 0; -} - -/** Close a socket stream. - * - * @param s socket stream to close - * @return result of the close - */ -static int socket_close(IOStream *s){ - SocketData *data = socket_data(s); - return close(data->fd); -} - -/** Free a socket stream. - * - * @param s socket stream - */ -static void socket_free(IOStream *s){ - SocketData *data = socket_data(s); - deallocate(data); -} - -/** Create an IOStream for a socket. - * - * @param fd socket to wtap - * @return new IOStream using fd for i/o - */ -IOStream *socket_stream_new(int fd){ - int err = -ENOMEM; - IOStream *io = NULL; - SocketData *data = NULL; - - io = ALLOCATE(IOStream); - if(!io) goto exit; - io->methods = &socket_methods; - data = ALLOCATE(SocketData); - if(!data) goto exit; - io->data = data; - data->fd = fd; - data->buf_n = sizeof(data->buf); - err = 0; - exit: - if(err){ - if(io){ - if(data) deallocate(data); - deallocate(io); - io = NULL; - } - } - return io; -} - diff --git a/tools/libxutil/socket_stream.h b/tools/libxutil/socket_stream.h deleted file mode 100644 index 5b8515f6b3..0000000000 --- a/tools/libxutil/socket_stream.h +++ /dev/null @@ -1,54 +0,0 @@ -/* $Id: socket_stream.h,v 1.2 2004/03/04 17:38:13 mjw Exp $ */ -/* - * Copyright (C) 2004 Mike Wray - * - * 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.1 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 - */ - -#ifndef _XEN_LIB_SOCKET_STREAM_H_ -#define _XEN_LIB_SOCKET_STREAM_H_ - -#ifndef __KERNEL__ -#include "iostream.h" -#include - -#include -#include -#include - -/** Data associated with a socket stream. */ -typedef struct SocketData { - /** The socket file descriptor. */ - int fd; - /** Source address from last read (recvfrom). */ - struct sockaddr_in saddr; - /** Destination address for writes (sendto). */ - struct sockaddr_in daddr; - /** Write flags (sendto). */ - int flags; - /** Buffer size. */ - int buf_n; - /** Buffer for formatted printing. */ - char buf[1024]; -} SocketData; - -extern IOStream *socket_stream_new(int fd); -extern int socket_stream_data(IOStream *io, SocketData **data); -extern int socket_stream_check(IOStream *io); -extern int socket_stream_set_addr(IOStream *io, struct sockaddr_in *addr); -extern int socket_stream_set_flags(IOStream *io, int flags); - -#endif -#endif /* !_XEN_LIB_SOCKET_STREAM_H_ */ diff --git a/tools/libxutil/sxpr.c b/tools/libxutil/sxpr.c deleted file mode 100644 index adeffbe5eb..0000000000 --- a/tools/libxutil/sxpr.c +++ /dev/null @@ -1,935 +0,0 @@ -/* - * - * 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.1 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 -#include "sys_string.h" -#include "lexis.h" -#include "sys_net.h" -#include "hash_table.h" -#include "sxpr.h" - -#include -#undef free - -/** @file - * General representation of sxprs. - * Includes print, equal, and free functions for the sxpr types. - * - * Zero memory containing an Sxpr will have the value ONONE - this is intentional. - * When a function returning an sxpr cannot allocate memory we return ONOMEM. - * - */ - -static int atom_print(IOStream *io, Sxpr obj, unsigned flags); -static int atom_equal(Sxpr x, Sxpr y); -static void atom_free(Sxpr obj); - -static int string_print(IOStream *io, Sxpr obj, unsigned flags); -static int string_equal(Sxpr x, Sxpr y); -static void string_free(Sxpr obj); - -static int cons_print(IOStream *io, Sxpr obj, unsigned flags); -static int cons_equal(Sxpr x, Sxpr y); -static void cons_free(Sxpr obj); - -static int null_print(IOStream *io, Sxpr obj, unsigned flags); -static int none_print(IOStream *io, Sxpr obj, unsigned flags); -static int int_print(IOStream *io, Sxpr obj, unsigned flags); -static int bool_print(IOStream *io, Sxpr obj, unsigned flags); - -/** Type definitions. */ -static SxprType types[1024] = { - [T_NONE] { type: T_NONE, name: "none", print: none_print }, - [T_NULL] { type: T_NULL, name: "null", print: null_print }, - [T_UINT] { type: T_UINT, name: "int", print: int_print, }, - [T_BOOL] { type: T_BOOL, name: "bool", print: bool_print, }, - [T_ATOM] { type: T_ATOM, name: "atom", print: atom_print, - pointer: TRUE, - free: atom_free, - equal: atom_equal, - }, - [T_STRING] { type: T_STRING, name: "string", print: string_print, - pointer: TRUE, - free: string_free, - equal: string_equal, - }, - [T_CONS] { type: T_CONS, name: "cons", print: cons_print, - pointer: TRUE, - free: cons_free, - equal: cons_equal, - }, -}; - -/** Number of entries in the types array. */ -static int type_sup = sizeof(types)/sizeof(types[0]); - -/** Get the type definition for a given type code. - * - * @param ty type code - * @return type definition or null - */ -SxprType *get_sxpr_type(int ty){ - if(0 <= ty && ty < type_sup){ - return types+ty; - } - return NULL; -} - -/** The default print function. - * - * @param io stream to print to - * @param x sxpr to print - * @param flags print flags - * @return number of bytes written on success - */ -int default_print(IOStream *io, Sxpr x, unsigned flags){ - return IOStream_print(io, "#<%u %lu>\n", get_type(x), get_ul(x)); -} - -/** The default equal function. - * Uses eq(). - * - * @param x sxpr to compare - * @param y sxpr to compare - * @return 1 if equal, 0 otherwise - */ -int default_equal(Sxpr x, Sxpr y){ - return eq(x, y); -} - -/** General sxpr print function. - * Prints an sxpr on a stream using the print function for the sxpr type. - * Printing is controlled by flags from the PrintFlags enum. - * If PRINT_TYPE is in the flags the sxpr type is printed before the sxpr - * (for debugging). - * - * @param io stream to print to - * @param x sxpr to print - * @param flags print flags - * @return number of bytes written - */ -int objprint(IOStream *io, Sxpr x, unsigned flags){ - SxprType *def = get_sxpr_type(get_type(x)); - ObjPrintFn *print_fn = (def && def->print ? def->print : default_print); - int k = 0; - if(!io) return k; - if(flags & PRINT_TYPE){ - k += IOStream_print(io, "%s:", def->name); - } - k += print_fn(io, x, flags); - return k; -} - -/** General sxpr free function. - * Frees an sxpr using the free function for its type. - * Free functions must recursively free any subsxprs. - * If no function is defined then the default is to - * free sxprs whose type has pointer true. - * Sxprs must not be used after freeing. - * - * @param x sxpr to free - */ -void objfree(Sxpr x){ - SxprType *def = get_sxpr_type(get_type(x)); - - if(def){ - if(def->free){ - def->free(x); - } else if (def->pointer){ - hfree(x); - } - } -} - -/** General sxpr equality function. - * Compares x and y using the equal function for x. - * Uses default_equal() if x has no equal function. - * - * @param x sxpr to compare - * @param y sxpr to compare - * @return 1 if equal, 0 otherwise - */ -int objequal(Sxpr x, Sxpr y){ - SxprType *def = get_sxpr_type(get_type(x)); - ObjEqualFn *equal_fn = (def && def->equal ? def->equal : default_equal); - return equal_fn(x, y); -} - -/** Search for a key in an alist. - * An alist is a list of conses, where the cars - * of the conses are the keys. Compares keys using equality. - * - * @param k key - * @param l alist to search - * @return first element of l with car k, or ONULL - */ -Sxpr assoc(Sxpr k, Sxpr l){ - for( ; CONSP(l) ; l = CDR(l)){ - Sxpr x = CAR(l); - if(CONSP(x) && objequal(k, CAR(x))){ - return x; - } - } - return ONULL; -} - -/** Search for a key in an alist. - * An alist is a list of conses, where the cars - * of the conses are the keys. Compares keys using eq. - * - * @param k key - * @param l alist to search - * @return first element of l with car k, or ONULL - */ -Sxpr assocq(Sxpr k, Sxpr l){ - for( ; CONSP(l); l = CDR(l)){ - Sxpr x = CAR(l); - if(CONSP(x) && eq(k, CAR(x))){ - return x; - } - } - return ONULL; -} - -/** Add a new key and value to an alist. - * - * @param k key - * @param l value - * @param l alist - * @return l with the new cell added to the front - */ -Sxpr acons(Sxpr k, Sxpr v, Sxpr l){ - Sxpr x, y; - x = cons_new(k, v); - if(NOMEMP(x)) return x; - y = cons_new(x, l); - if(NOMEMP(y)) cons_free_cells(x); - return y; -} - -/** Test if a list contains an element. - * Uses sxpr equality. - * - * @param l list - * @param x element to look for - * @return a tail of l with x as car, or ONULL - */ -Sxpr cons_member(Sxpr l, Sxpr x){ - for( ; CONSP(l) && !eq(x, CAR(l)); l = CDR(l)){} - return l; -} - -/** Test if a list contains an element satisfying a test. - * The test function is called with v and an element of the list. - * - * @param l list - * @param test_fn test function to use - * @param v value for first argument to the test - * @return a tail of l with car satisfying the test, or 0 - */ -Sxpr cons_member_if(Sxpr l, ObjEqualFn *test_fn, Sxpr v){ - for( ; CONSP(l) && !test_fn(v, CAR(l)); l = CDR(l)){ } - return l; -} - -/** Test if the elements of list 't' are a subset of the elements - * of list 's'. Element order is not significant. - * - * @param s element list to check subset of - * @param t element list to check if is a subset - * @return 1 if is a subset, 0 otherwise - */ -int cons_subset(Sxpr s, Sxpr t){ - for( ; CONSP(t); t = CDR(t)){ - if(!CONSP(cons_member(s, CAR(t)))){ - return 0; - } - } - return 1; -} - -/** Test if two lists have equal sets of elements. - * Element order is not significant. - * - * @param s list to check - * @param t list to check - * @return 1 if equal, 0 otherwise - */ -int cons_set_equal(Sxpr s, Sxpr t){ - return cons_subset(s, t) && cons_subset(t, s); -} - -#ifdef USE_GC -/*============================================================================*/ -/* The functions inside this ifdef are only safe if GC is used. - * Otherwise they may leak memory. - */ - -/** Remove an element from a list (GC only). - * Uses sxpr equality and removes all instances, even - * if there are more than one. - * - * @param l list to remove elements from - * @param x element to remove - * @return modified input list - */ -Sxpr cons_remove(Sxpr l, Sxpr x){ - return cons_remove_if(l, eq, x); -} - -/** Remove elements satisfying a test (GC only). - * The test function is called with v and an element of the set. - * - * @param l list to remove elements from - * @param test_fn function to use to decide if an element should be removed - * @return modified input list - */ -Sxpr cons_remove_if(Sxpr l, ObjEqualFn *test_fn, Sxpr v){ - Sxpr prev = ONULL, elt, next; - - for(elt = l; CONSP(elt); elt = next){ - next = CDR(elt); - if(test_fn(v, CAR(elt))){ - if(NULLP(prev)){ - l = next; - } else { - CDR(prev) = next; - } - } - } - return l; -} - -/** Set the value for a key in an alist (GC only). - * If the key is present, changes the value, otherwise - * adds a new cell. - * - * @param k key - * @param v value - * @param l alist - * @return modified or extended list - */ -Sxpr setf(Sxpr k, Sxpr v, Sxpr l){ - Sxpr e = assoc(k, l); - if(NULLP(e)){ - l = acons(k, v, l); - } else { - CAR(CDR(e)) = v; - } - return l; -} -/*============================================================================*/ -#endif /* USE_GC */ - -/** Create a new atom with the given name. - * - * @param name the name - * @return new atom - */ -Sxpr atom_new(char *name){ - Sxpr n, obj = ONOMEM; - - n = string_new(name); - if(NOMEMP(n)) goto exit; - obj = HALLOC(ObjAtom, T_ATOM); - if(NOMEMP(obj)) goto exit; - OBJ_ATOM(obj)->name = n; - exit: - return obj; -} - -/** Free an atom. - * - * @param obj to free - */ -void atom_free(Sxpr obj){ - // Interned atoms are shared, so do not free. - if(OBJ_ATOM(obj)->interned) return; - objfree(OBJ_ATOM(obj)->name); - hfree(obj); -} - -/** Print an atom. Prints the atom name. - * - * @param io stream to print to - * @param obj to print - * @param flags print flags - * @return number of bytes printed - */ -int atom_print(IOStream *io, Sxpr obj, unsigned flags){ - //return string_print(io, OBJ_ATOM(obj)->name, (flags | PRINT_RAW)); - return string_print(io, OBJ_ATOM(obj)->name, flags); -} - -/** Atom equality. - * - * @param x to compare - * @param y to compare - * @return 1 if equal, 0 otherwise - */ -int atom_equal(Sxpr x, Sxpr y){ - int ok; - ok = eq(x, y); - if(ok) goto exit; - ok = ATOMP(y) && string_equal(OBJ_ATOM(x)->name, OBJ_ATOM(y)->name); - if(ok) goto exit; - ok = STRINGP(y) && string_equal(OBJ_ATOM(x)->name, y); - exit: - return ok; -} - -/** Get the name of an atom. - * - * @param obj atom - * @return name - */ -char * atom_name(Sxpr obj){ - return string_string(OBJ_ATOM(obj)->name); -} - -/** Get the C string from a string sxpr. - * - * @param obj string sxpr - * @return string - */ -char * string_string(Sxpr obj){ - return OBJ_STRING(obj); -} - -/** Get the length of a string. - * - * @param obj string - * @return length - */ -int string_length(Sxpr obj){ - return strlen(OBJ_STRING(obj)); -} - -/** Create a new string. The input string is copied, - * and must be null-terminated. - * - * @param s characters to put in the string - * @return new sxpr - */ -Sxpr string_new(char *s){ - int n = (s ? strlen(s) : 0); - Sxpr obj; - obj = halloc(n+1, T_STRING); - if(!NOMEMP(obj)){ - char *str = OBJ_STRING(obj); - strncpy(str, s, n); - str[n] = '\0'; - } - return obj; -} - -/** Free a string. - * - * @param obj to free - */ -void string_free(Sxpr obj){ - hfree(obj); -} - -/** Determine if a string needs escapes when printed - * using the given flags. - * - * @param str string to check - * @param flags print flags - * @return 1 if needs escapes, 0 otherwise - */ -int needs_escapes(char *str, unsigned flags){ - char *c; - int val = 0; - - if(str){ - for(c=str; *c; c++){ - if(in_alpha_class(*c)) continue; - if(in_decimal_digit_class(*c)) continue; - if(in_class(*c, "/._+:@~-")) continue; - val = 1; - break; - } - } - //printf("\n> val=%d str=|%s|\n", val, str); - return val; -} - -/** Print a string to a stream, with escapes if necessary. - * - * @param io stream to print to - * @param str string - * @param flags print flags - * @return number of bytes written - */ -int _string_print(IOStream *io, char *str, unsigned flags){ - int k = 0; - if((flags & PRINT_RAW) || !needs_escapes(str, flags)){ - k += IOStream_print(io, str); - } else { - k += IOStream_print(io, "\""); - if(str){ - char *s; - for(s = str; *s; s++){ - if(*s < ' ' || *s >= 127 ){ - switch(*s){ - case '\a': k += IOStream_print(io, "\\a"); break; - case '\b': k += IOStream_print(io, "\\b"); break; - case '\f': k += IOStream_print(io, "\\f"); break; - case '\n': k += IOStream_print(io, "\\n"); break; - case '\r': k += IOStream_print(io, "\\r"); break; - case '\t': k += IOStream_print(io, "\\t"); break; - case '\v': k += IOStream_print(io, "\\v"); break; - default: - // Octal escape; - k += IOStream_print(io, "\\%o", *s); - break; - } - } else if(*s == c_double_quote || - *s == c_single_quote || - *s == c_escape){ - k += IOStream_print(io, "\\%c", *s); - } else { - k+= IOStream_print(io, "%c", *s); - } - } - } - k += IOStream_print(io, "\""); - } - return k; -} - -/** Print a string to a stream, with escapes if necessary. - * - * @param io stream to print to - * @param obj string - * @param flags print flags - * @return number of bytes written - */ -int string_print(IOStream *io, Sxpr obj, unsigned flags){ - return _string_print(io, OBJ_STRING(obj), flags); -} - -/** Compare an sxpr with a string for equality. - * - * @param x string to compare with - * @param y sxpr to compare - * @return 1 if equal, 0 otherwise - */ -int string_equal(Sxpr x, Sxpr y){ - int ok = 0; - ok = eq(x,y); - if(ok) goto exit; - ok = has_type(y, T_STRING) && !strcmp(OBJ_STRING(x), OBJ_STRING(y)); - if(ok) goto exit; - ok = has_type(y, T_ATOM) && !strcmp(OBJ_STRING(x), atom_name(y)); - exit: - return ok; -} - -/** Create a new cons cell. - * The cell is ONOMEM if either argument is. - * - * @param car sxpr for the car - * @param cdr sxpr for the cdr - * @return new cons - */ -Sxpr cons_new(Sxpr car, Sxpr cdr){ - Sxpr obj; - if(NOMEMP(car) || NOMEMP(cdr)){ - obj = ONOMEM; - } else { - obj = HALLOC(ObjCons, T_CONS); - if(!NOMEMP(obj)){ - ObjCons *z = OBJ_CONS(obj); - z->car = car; - z->cdr = cdr; - } - } - return obj; -} - -/** Push a new element onto a list. - * - * @param list list to add to - * @param elt element to add - * @return 0 if successful, error code otherwise - */ -int cons_push(Sxpr *list, Sxpr elt){ - Sxpr l; - l = cons_new(elt, *list); - if(NOMEMP(l)) return -ENOMEM; - *list = l; - return 0; -} - -/** Free a cons. Recursively frees the car and cdr. - * - * @param obj to free - */ -void cons_free(Sxpr obj){ - Sxpr next; - for(; CONSP(obj); obj = next){ - next = CDR(obj); - objfree(CAR(obj)); - hfree(obj); - } - if(!NULLP(obj)){ - objfree(obj); - } -} - -/** Free a cons and its cdr cells, but not the car sxprs. - * Does nothing if called on something that is not a cons. - * - * @param obj to free - */ -void cons_free_cells(Sxpr obj){ - Sxpr next; - for(; CONSP(obj); obj = next){ - next = CDR(obj); - hfree(obj); - } -} - -/** Print a cons. - * Prints the cons in list format if the cdrs are conses. - * uses pair (dot) format if the last cdr is not a cons (or null). - * - * @param io stream to print to - * @param obj to print - * @param flags print flags - * @return number of bytes written - */ -int cons_print(IOStream *io, Sxpr obj, unsigned flags){ - int first = 1; - int k = 0; - k += IOStream_print(io, "("); - for( ; CONSP(obj) ; obj = CDR(obj)){ - if(first){ - first = 0; - } else { - k += IOStream_print(io, " "); - } - k += objprint(io, CAR(obj), flags); - } - if(!NULLP(obj)){ - k += IOStream_print(io, " . "); - k += objprint(io, obj, flags); - } - k += IOStream_print(io, ")"); - return (IOStream_error(io) ? -1 : k); -} - -/** Compare a cons with another sxpr for equality. - * If y is a cons, compares the cars and cdrs recursively. - * - * @param x cons to compare - * @param y sxpr to compare - * @return 1 if equal, 0 otherwise - */ -int cons_equal(Sxpr x, Sxpr y){ - return CONSP(y) && - objequal(CAR(x), CAR(y)) && - objequal(CDR(x), CDR(y)); -} - -/** Return the length of a cons list. - * - * @param obj list - * @return length - */ -int cons_length(Sxpr obj){ - int count = 0; - for( ; CONSP(obj); obj = CDR(obj)){ - count++; - } - return count; -} - -/** Destructively reverse a cons list in-place. - * If the argument is not a cons it is returned unchanged. - * - * @param l to reverse - * @return reversed list - */ -Sxpr nrev(Sxpr l){ - if(CONSP(l)){ - // Iterate down the cells in the list making the cdr of - // each cell point to the previous cell. The last cell - // is the head of the reversed list. - Sxpr prev = ONULL; - Sxpr cell = l; - Sxpr next; - - while(1){ - next = CDR(cell); - CDR(cell) = prev; - if(!CONSP(next)) break; - prev = cell; - cell = next; - } - l = cell; - } - return l; -} - -/** Print the null sxpr. - * - * @param io stream to print to - * @param obj to print - * @param flags print flags - * @return number of bytes written - */ -static int null_print(IOStream *io, Sxpr obj, unsigned flags){ - return IOStream_print(io, "()"); -} - -/** Print the `unspecified' sxpr none. - * - * @param io stream to print to - * @param obj to print - * @param flags print flags - * @return number of bytes written - */ -static int none_print(IOStream *io, Sxpr obj, unsigned flags){ - return IOStream_print(io, ""); -} - -/** Print an integer. - * - * @param io stream to print to - * @param obj to print - * @param flags print flags - * @return number of bytes written - */ -static int int_print(IOStream *io, Sxpr obj, unsigned flags){ - return IOStream_print(io, "%d", OBJ_INT(obj)); -} - -/** Print a boolean. - * - * @param io stream to print to - * @param obj to print - * @param flags print flags - * @return number of bytes written - */ -static int bool_print(IOStream *io, Sxpr obj, unsigned flags){ - return IOStream_print(io, (OBJ_UINT(obj) ? k_true : k_false)); -} - -int sxprp(Sxpr obj, Sxpr name){ - return CONSP(obj) && objequal(CAR(obj), name); -} - -/** Get the name of an element. - * - * @param obj element - * @return name - */ -Sxpr sxpr_name(Sxpr obj){ - Sxpr val = ONONE; - if(CONSP(obj)){ - val = CAR(obj); - } else if(STRINGP(obj) || ATOMP(obj)){ - val = obj; - } - return val; -} - -int sxpr_is(Sxpr obj, char *s){ - if(ATOMP(obj)) return !strcmp(atom_name(obj), s); - if(STRINGP(obj)) return !strcmp(string_string(obj), s); - return 0; -} - -int sxpr_elementp(Sxpr obj, Sxpr name){ - return CONSP(obj) && objequal(CAR(obj), name); -} - -/** Get the attributes of an sxpr. - * - * @param obj sxpr - * @return attributes - */ -Sxpr sxpr_attributes(Sxpr obj){ - Sxpr val = ONULL; - if(CONSP(obj)){ - obj = CDR(obj); - if(CONSP(obj)){ - obj = CAR(obj); - if(sxprp(obj, intern("@"))){ - val = CDR(obj); - } - } - } - return val; -} - -Sxpr sxpr_attribute(Sxpr obj, Sxpr key, Sxpr def){ - Sxpr val = ONONE; - val = assoc(sxpr_attributes(obj), key); - if(CONSP(val) && CONSP(CDR(val))){ - val = CADR(def); - } else { - val = def; - } - return val; -} - -/** Get the children of an sxpr. - * - * @param obj sxpr - * @return children - */ -Sxpr sxpr_children(Sxpr obj){ - Sxpr val = ONULL; - if(CONSP(obj)){ - val = CDR(obj); - if(CONSP(val) && sxprp(CAR(val), intern("@"))){ - val = CDR(val); - } - } - return val; -} - -Sxpr sxpr_child(Sxpr obj, Sxpr name, Sxpr def){ - Sxpr val = ONONE; - Sxpr l; - for(l = sxpr_children(obj); CONSP(l); l = CDR(l)){ - if(sxprp(CAR(l), name)){ - val = CAR(l); - break; - } - } - if(NONEP(val)) val = def; - return val; -} - -Sxpr sxpr_child0(Sxpr obj, Sxpr def){ - Sxpr val = ONONE; - Sxpr l = sxpr_children(obj); - if(CONSP(l)){ - val = CAR(l); - } else { - val = def; - } - return val; -} - -Sxpr sxpr_child_value(Sxpr obj, Sxpr name, Sxpr def){ - Sxpr val = ONONE; - val = sxpr_child(obj, name, ONONE); - if(NONEP(val)){ - val = def; - } else { - val = sxpr_child0(val, def); - } - return val; -} - -/** Table of interned symbols. Indexed by symbol name. */ -static HashTable *symbols = NULL; - -/** Hash function for entries in the symbol table. - * - * @param key to hash - * @return hashcode - */ -static Hashcode sym_hash_fn(void *key){ - return hash_string((char*)key); -} - -/** Key equality function for the symbol table. - * - * @param x to compare - * @param y to compare - * @return 1 if equal, 0 otherwise - */ -static int sym_equal_fn(void *x, void *y){ - return !strcmp((char*)x, (char*)y); -} - -/** Entry free function for the symbol table. - * - * @param table the entry is in - * @param entry being freed - */ -static void sym_free_fn(HashTable *table, HTEntry *entry){ - if(entry){ - objfree(((ObjAtom*)entry->value)->name); - HTEntry_free(entry); - } -} - -/** Initialize the symbol table. - * - * @return 0 on sucess, error code otherwise - */ -static int init_symbols(void){ - symbols = HashTable_new(100); - if(symbols){ - symbols->key_hash_fn = sym_hash_fn; - symbols->key_equal_fn = sym_equal_fn; - symbols->entry_free_fn = sym_free_fn; - return 0; - } - return -1; -} - -/** Cleanup the symbol table. Frees the table and all its symbols. - */ -void cleanup_symbols(void){ - HashTable_free(symbols); - symbols = NULL; -} - -/** Get the interned symbol with the given name. - * No new symbol is created. - * - * @return symbol or null - */ -Sxpr get_symbol(char *sym){ - HTEntry *entry; - if(!symbols){ - if(init_symbols()) return ONOMEM; - return ONULL; - } - entry = HashTable_get_entry(symbols, sym); - if(entry){ - return OBJP(T_ATOM, entry->value); - } else { - return ONULL; - } -} - -/** Get the interned symbol with the given name. - * Creates a new symbol if necessary. - * - * @return symbol - */ -Sxpr intern(char *sym){ - Sxpr symbol = get_symbol(sym); - if(NULLP(symbol)){ - if(!symbols) return ONOMEM; - symbol = atom_new(sym); - if(!NOMEMP(symbol)){ - OBJ_ATOM(symbol)->interned = TRUE; - HashTable_add(symbols, atom_name(symbol), get_ptr(symbol)); - } - } - return symbol; -} diff --git a/tools/libxutil/sxpr.h b/tools/libxutil/sxpr.h deleted file mode 100644 index b90083139c..0000000000 --- a/tools/libxutil/sxpr.h +++ /dev/null @@ -1,413 +0,0 @@ -/* - * - * 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.1 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 - */ -#ifndef _XEN_LIB_SXPR_H_ -#define _XEN_LIB_SXPR_H_ - -#include - -#include "hash_table.h" -#include "iostream.h" -#include "allocate.h" - -/** @file - * Definitions for rules and sxprs. - */ - -#ifndef NULL -#define NULL 0 -#endif - -#ifndef TRUE -#define TRUE 1 -#endif - -#ifndef FALSE -#define FALSE 0 -#endif - -/** Sxpr type. */ -typedef int16_t TypeCode; - -/** A typed sxpr handle.*/ -typedef struct Sxpr { - /** Sxpr type. */ - TypeCode type; - union { - /** Sxpr value. */ - unsigned long ul; - /** Pointer. */ - void *ptr; - } v; -} Sxpr; - -/** Sxpr type to indicate out of memory. */ -#define T_NOMEM ((TypeCode)-1) -/** The 'unspecified' sxpr. */ -#define T_NONE ((TypeCode)0) -/** The empty list. */ -#define T_NULL ((TypeCode)1) -/** Unsigned integer. */ -#define T_UINT ((TypeCode)2) -/** A string. */ -#define T_STRING ((TypeCode)3) -/** An atom. */ -#define T_ATOM ((TypeCode)4) -/** A boolean. */ -#define T_BOOL ((TypeCode)5) - -/** A cons (pair or list). */ -#define T_CONS ((TypeCode)10) - -/** An error. */ -#define T_ERR ((TypeCode)40) - -/** An atom. */ -typedef struct ObjAtom { - Sxpr name; - Hashcode hashcode; - int interned; -} ObjAtom; - -/** A cons (pair). */ -typedef struct ObjCons { - Sxpr car; - Sxpr cdr; -} ObjCons; - -/** A vector. */ -typedef struct ObjVector { - int n; - Sxpr data[0]; -} ObjVector; - -/** Flags for sxpr printing. */ -enum PrintFlags { - PRINT_RAW = 0x001, - PRINT_TYPE = 0x002, - PRINT_PRETTY = 0x004, - PRINT_NUM = 0x008, -}; - -/** An integer sxpr. - * - * @param ty type - * @param val integer value - */ -#define OBJI(ty, val) (Sxpr){ type: (ty), v: { ul: (val) }} - -/** A pointer sxpr. - * If the pointer is non-null, returns an sxpr containing it. - * If the pointer is null, returns ONOMEM. - * - * @param ty type - * @param val pointer - */ -#define OBJP(ty, val) ((val) ? (Sxpr){ type: (ty), v: { ptr: (val) }} : ONOMEM) - -/** Make an integer sxpr containing a pointer. - * - * @param val pointer - */ -#define PTR(val) OBJP(T_UINT, (void*)(val)) - -/** Make an integer sxpr. - * @param x value - */ -#define OINT(x) OBJI(T_UINT, x) - -/** Make an error sxpr. - * - * @param x value - */ -#define OERR(x) OBJI(T_ERR, x) - -/** Out of memory constant. */ -#define ONOMEM OBJI(T_NOMEM, 0) - -/** The `unspecified' constant. */ -#define ONONE OBJI(T_NONE, 0) - -/** Empty list constant. */ -#define ONULL OBJI(T_NULL, 0) - -/** False constant. */ -#define OFALSE OBJI(T_BOOL, 0) - -/** True constant. */ -#define OTRUE OBJI(T_BOOL, 1) - -/* Recognizers for the various sxpr types. */ -#define ATOMP(obj) has_type(obj, T_ATOM) -#define BOOLP(obj) has_type(obj, T_BOOL) -#define CONSP(obj) has_type(obj, T_CONS) -#define ERRP(obj) has_type(obj, T_ERR) -#define INTP(obj) has_type(obj, T_UINT) -#define NOMEMP(obj) has_type(obj, T_NOMEM) -#define NONEP(obj) has_type(obj, T_NONE) -#define NULLP(obj) has_type(obj, T_NULL) -#define STRINGP(obj) has_type(obj, T_STRING) - -#define TRUEP(obj) get_ul(obj) - -/** Convert an sxpr to an unsigned integer. */ -#define OBJ_UINT(x) get_ul(x) -/** Convert an sxpr to an integer. */ -#define OBJ_INT(x) (int)get_ul(x) - -/* Conversions of sxprs to their values. - * No checking is done. - */ -#define OBJ_STRING(x) ((char*)get_ptr(x)) -#define OBJ_CONS(x) ((ObjCons*)get_ptr(x)) -#define OBJ_ATOM(x) ((ObjAtom*)get_ptr(x)) -#define OBJ_SET(x) ((ObjSet*)get_ptr(x)) -#define CAR(x) (OBJ_CONS(x)->car) -#define CDR(x) (OBJ_CONS(x)->cdr) - -#define CAAR(x) (CAR(CAR(x))) -#define CADR(x) (CAR(CDR(x))) -#define CDAR(x) (CDR(CAR(x))) -#define CDDR(x) (CDR(CDR(x))) - -/** Get the integer value from an sxpr. - * - * @param obj sxpr - * @return value - */ -static inline unsigned long get_ul(Sxpr obj){ - return obj.v.ul; -} - -/** Get the pointer value from an sxpr. - * - * @param obj sxpr - * @return value - */ -static inline void * get_ptr(Sxpr obj){ - return obj.v.ptr; -} - -/** Create an sxpr containing a pointer. - * - * @param type typecode - * @param val pointer - * @return sxpr - */ -static inline Sxpr obj_ptr(TypeCode type, void *val){ - return (Sxpr){ type: type, v: { ptr: val } }; -} - -/** Create an sxpr containing an integer. - * - * @param type typecode - * @param val integer - * @return sxpr - */ -static inline Sxpr obj_ul(TypeCode type, unsigned long val){ - return (Sxpr){ type: type, v: { ul: val } }; -} - -/** Get the type of an sxpr. - * - * @param obj sxpr - * @return type - */ -static inline TypeCode get_type(Sxpr obj){ - return obj.type; -} - -/** Check the type of an sxpr. - * - * @param obj sxpr - * @param type to check - * @return 1 if has the type, 0 otherwise - */ -static inline int has_type(Sxpr obj, TypeCode type){ - return get_type(obj) == type; -} - -/** Compare sxprs for literal equality of type and value. - * - * @param x sxpr to compare - * @param y sxpr to compare - * @return 1 if equal, 0 otherwise - */ -static inline int eq(Sxpr x, Sxpr y){ - return ((get_type(x) == get_type(y)) && (get_ul(x) == get_ul(y))); -} - -/** Checked version of CAR - * - * @param x sxpr - * @return CAR if a cons, x otherwise - */ -static inline Sxpr car(Sxpr x){ - return (CONSP(x) ? CAR(x) : x); -} - -/** Checked version of CDR. - * - * @param x sxpr - * @return CDR if a cons, null otherwise - */ -static inline Sxpr cdr(Sxpr x){ - return (CONSP(x) ? CDR(x) : ONULL); -} - -/** Allocate some memory and return an sxpr containing it. - * Returns ONOMEM if allocation failed. - * - * @param n number of bytes to allocate - * @param ty typecode - * @return sxpr - */ -static inline Sxpr halloc(size_t n, TypeCode ty){ - return OBJP(ty, allocate(n)); -} - -/** Allocate an sxpr containing a pointer to the given type. - * - * @param ty type (uses sizeof to determine how many bytes to allocate) - * @param code typecode - * @return sxpr, ONOMEM if allocation failed - */ -#define HALLOC(ty, code) halloc(sizeof(ty), code) - -typedef int ObjPrintFn(IOStream *io, Sxpr obj, unsigned flags); -typedef int ObjEqualFn(Sxpr obj, Sxpr other); -typedef void ObjFreeFn(Sxpr obj); - -/** An sxpr type definition. */ -typedef struct SxprType { - TypeCode type; - char *name; - int pointer; - ObjPrintFn *print; - ObjEqualFn *equal; - ObjFreeFn *free; -} SxprType; - - -extern SxprType *get_sxpr_type(int ty); - -/** Free the pointer in an sxpr. - * - * @param x sxpr containing a pointer - */ -static inline void hfree(Sxpr x){ - deallocate(get_ptr(x)); -} - -extern int objprint(IOStream *io, Sxpr x, unsigned flags); -extern int objequal(Sxpr x, Sxpr y); -extern void objfree(Sxpr x); - -extern void cons_free_cells(Sxpr obj); -extern Sxpr intern(char *s); - -extern Sxpr assoc(Sxpr k, Sxpr l); -extern Sxpr assocq(Sxpr k, Sxpr l); -extern Sxpr acons(Sxpr k, Sxpr v, Sxpr l); -extern Sxpr nrev(Sxpr l); -extern Sxpr cons_member(Sxpr l, Sxpr x); -extern Sxpr cons_member_if(Sxpr l, ObjEqualFn *test_fn, Sxpr v); -extern int cons_subset(Sxpr s, Sxpr t); -extern int cons_set_equal(Sxpr s, Sxpr t); - -#ifdef USE_GC -extern Sxpr cons_remove(Sxpr l, Sxpr x); -extern Sxpr cons_remove_if(Sxpr l, ObjEqualFn *test_fn, Sxpr v); -#endif - -extern Sxpr atom_new(char *name); -extern char * atom_name(Sxpr obj); - -extern Sxpr string_new(char *s); -extern char * string_string(Sxpr obj); -extern int string_length(Sxpr obj); - -extern Sxpr cons_new(Sxpr car, Sxpr cdr); -extern int cons_push(Sxpr *list, Sxpr elt); -extern int cons_length(Sxpr obj); - -Sxpr sxpr_name(Sxpr obj); -int sxpr_is(Sxpr obj, char *s); -int sxpr_elementp(Sxpr obj, Sxpr name); -Sxpr sxpr_attributes(Sxpr obj); -Sxpr sxpr_attribute(Sxpr obj, Sxpr key, Sxpr def); -Sxpr sxpr_children(Sxpr obj); -Sxpr sxpr_child(Sxpr obj, Sxpr name, Sxpr def); -Sxpr sxpr_child0(Sxpr obj, Sxpr def); -Sxpr sxpr_child_value(Sxpr obj, Sxpr name, Sxpr def); - -/** Create a new atom. - * - * @param s atom name - * @return new atom - */ -static inline Sxpr mkatom(char *s){ - return atom_new(s); -} - -/** Create a new string sxpr. - * - * @param s string bytes (copied) - * @return new string - */ -static inline Sxpr mkstring(char *s){ - return string_new(s); -} - -/** Create an integer sxpr. - * - * @param i value - * @return sxpr - */ -static inline Sxpr mkint(int i){ - return OBJI(T_UINT, i); -} - -/** Create a boolean sxpr. - * - * @param b value - * @return sxpr - */ -static inline Sxpr mkbool(int b){ - return OBJI(T_BOOL, (b ? 1 : 0)); -} - -/* Constants used in parsing and printing. */ -#define k_list_open "(" -#define c_list_open '(' -#define k_list_close ")" -#define c_list_close ')' -#define k_true "true" -#define k_false "false" - -#define c_var '$' -#define c_escape '\\' -#define c_single_quote '\'' -#define c_double_quote '"' -#define c_string_open c_double_quote -#define c_string_close c_double_quote -#define c_data_open '[' -#define c_data_close ']' -#define c_binary '*' -#define c_eval '!' -#define c_concat_open '{' -#define c_concat_close '}' - -#endif /* ! _XEN_LIB_SXPR_H_ */ diff --git a/tools/libxutil/sxpr_parser.c b/tools/libxutil/sxpr_parser.c deleted file mode 100644 index 16fec56b67..0000000000 --- a/tools/libxutil/sxpr_parser.c +++ /dev/null @@ -1,897 +0,0 @@ - -#ifdef __KERNEL__ -# include -# include -# include -# include -# include -#else -# include -# include -#endif - -#include "iostream.h" -#include "lexis.h" -#include "sxpr_parser.h" -#include "sys_string.h" - -/** @file - * Sxpr parsing. - * - * So that the parser does not leak memory, all sxprs constructed by - * the parser must be freed on error. On successful parse the sxpr - * returned becomes the responsibility of the caller. - * - * @author Mike Wray - */ - -#define dprintf(fmt, args...) IOStream_print(iostdout, "[DEBUG] %s" fmt, __FUNCTION__, ##args) -#define printf(fmt, args...) IOStream_print(iostdout, fmt, ##args) - -static void reset(Parser *z); -static int inputchar(Parser *p, char c); -static int savechar(Parser *p, char c); -extern void parse_error(Parser *in); -extern void parse_error_id(Parser *in, ParseErrorId id); - -static int begin_start(Parser *p, char c); -static int state_start(Parser *p, char c); -static int end_start(Parser *p); - -static int begin_comment(Parser *p, char c); -static int state_comment(Parser *p, char c); -static int end_comment(Parser *p); - -static int begin_string(Parser *p, char c); -static int state_string(Parser *p, char c); -static int end_string(Parser *p); -static int state_escape(Parser *p, char c); -static int state_octal(Parser *p, char c); -static int state_hex(Parser *p, char c); - -static int begin_atom(Parser *p, char c); -static int state_atom(Parser *p, char c); -static int end_atom(Parser *p); - -static int state_list(Parser *p, char c); -static int begin_list(Parser *p, char c); -static int end_list(Parser *p); - -/** Print a parse error. - * - * @param in parser - * @param msg format followed by printf arguments - */ -void eprintf(Parser *in, char *msg, ...){ - va_list args; - if(in->error_out){ - va_start(args, msg); - IOStream_vprint(in->error_out, msg, args); - va_end(args); - } -} - -/** Print a parse warning. - * - * @param in parser - * @param msg format followed by printf arguments - */ -void wprintf(Parser *in, char *msg, ...){ - va_list args; - if(in->error_out){ - va_start(args, msg); - IOStream_vprint(in->error_out, msg, args); - va_end(args); - } -} - -/*============================================================================*/ - -/** Record defining the message for a parse error. */ -typedef struct { - ParseErrorId id; - char *message; -} ParseError; - -/** Format for printing parse error messages. */ -#define PARSE_ERR_FMT "parse error> line %3d, column %2d: %s" - -/** Message catalog for the parse error codes. */ -static ParseError catalog[] = { - { PARSE_ERR_UNSPECIFIED, "unspecified error" }, - { PARSE_ERR_NOMEM, "out of memory" }, - { PARSE_ERR_UNEXPECTED_EOF, "unexpected end of input" }, - { PARSE_ERR_TOKEN_TOO_LONG, "token too long" }, - { PARSE_ERR_INVALID_SYNTAX, "syntax error" }, - { PARSE_ERR_INVALID_ESCAPE, "invalid escape" }, - { 0, NULL } -}; - -/** Number of entries in the message catalog. */ -const static int catalog_n = sizeof(catalog)/sizeof(ParseError); - -void ParserState_free(ParserState *z){ - if(!z) return; - objfree(z->val); - deallocate(z); -} - -int ParserState_new(ParserStateFn *fn, ParserState *parent, ParserState **val){ - int err = 0; - ParserState *z; - z = ALLOCATE(ParserState); - if(z){ - z->fn = fn; - z->parent = parent; - z->val = ONULL; - } else { - err = -ENOMEM; - } - if(!err) *val = z; - return err; -} - -/** Free a parser. - * No-op if the parser is null. - * - * @param z parser - */ -void Parser_free(Parser *z){ - if(!z) return; - objfree(z->val); - z->val = ONONE; - deallocate(z); -} - -/** Create a new parser. The error stream defaults to null. - */ -Parser * Parser_new(void){ - Parser *z = ALLOCATE(Parser); - int err = -ENOMEM; - - if(!z) goto exit; - err = 0; - reset(z); - exit: - if(err){ - Parser_free(z); - z = NULL; - } - return z; -} - -/** Get the next character. - * Records the character read in the parser, - * and sets the line and character counts. - * - * @param p parser - * @return error flag: 0 on success, non-zero on error - */ -static int inputchar(Parser *p, char c){ - int err = 0; - if(c=='\n'){ - p->line_no++; - p->char_no = 0; - } else { - p->char_no++; - } - return err; -} - -static int savechar(Parser *p, char c){ - int err = 0; - if(p->buf_i >= p->buf_n){ - err = -ENOMEM; - goto exit; - } - p->buf[p->buf_i] = c; - p->buf_i++; - exit: - return err; -} - -int Parser_input_char(Parser *p, char c){ - int err = 0; - if(at_eof(p)){ - //skip; - } else { - inputchar(p, c); - } - if(!p->state){ - err = begin_start(p, c); - if(err) goto exit; - } - err = p->state->fn(p, c); - exit: - return err; -} - -int Parser_input_eof(Parser *p){ - int err = 0; - p->eof = 1; - err = Parser_input_char(p, IOSTREAM_EOF); - return err; -} - -int Parser_input(Parser *p, char *buf, int buf_n){ - int err = 0; - int i = 0; - if(buf_n <= 0){ - err = Parser_input_eof(p); - goto exit; - } - for(i = 0; istate, &p->state); - return err; -} - -int Parser_pop(Parser *p){ - int err = 0; - ParserState *s = p->state; - p->state = s->parent; - ParserState_free(s); - return err; -} - -int Parser_return(Parser *p){ - int err = 0; - Sxpr val = ONONE; - if(!p->state){ - err = -EINVAL; - goto exit; - } - val = p->state->val; - p->state->val = ONONE; - err = Parser_pop(p); - if(err) goto exit; - if(p->state){ - err = cons_push(&p->state->val, val); - } else { - val = nrev(val); - p->val = val; - } - exit: - if(err){ - objfree(val); - } - return err; -} - -/** Determine if a character is a separator. - * - * @param p parser - * @param c character to test - * @return 1 if a separator, 0 otherwise - */ -static int is_separator(Parser *p, char c){ - return in_sep_class(c); -} - -/** Return the current token. - * The return value points at the internal buffer, so - * it must not be modified (or freed). Use copy_token() if you need a copy. - * - * @param p parser - * @return token - */ -char *peek_token(Parser *p){ - return p->buf; -} - -/** Return a copy of the current token. - * The returned value should be freed when finished with. - * - * @param p parser - * @return copy of token - */ -char *copy_token(Parser *p){ - return strdup(peek_token(p)); -} - -static int do_intern(Parser *p){ - int err = 0; - Sxpr obj = intern(peek_token(p)); - if(NOMEMP(obj)){ - err = -ENOMEM; - } else { - p->state->val = obj; - } - return err; -} - -static int do_string(Parser *p){ - int err = 0; - Sxpr obj; - obj = string_new(peek_token(p)); - if(NOMEMP(obj)){ - err = -ENOMEM; - } else { - p->state->val = obj; - } - return err; -} - -void newtoken(Parser *p){ - memset(p->buf, 0, p->buf_n); - p->buf_i = 0; - p->tok_begin_line = p->line_no; - p->tok_begin_char = p->char_no; -} - -int get_escape(char c, char *d){ - int err = 0; - switch(c){ - case 'a': *d = '\a'; break; - case 'b': *d = '\b'; break; - case 'f': *d = '\f'; break; - case 'n': *d = '\n'; break; - case 'r': *d = '\r'; break; - case 't': *d = '\t'; break; - case 'v': *d = '\v'; break; - case c_escape: *d = c_escape; break; - case c_single_quote: *d = c_single_quote; break; - case c_double_quote: *d = c_double_quote; break; - default: - err = -EINVAL; - } - return err; -} - - -int begin_start(Parser *p, char c){ - return Parser_push(p, state_start); -} - -int state_start(Parser *p, char c){ - int err = 0; - if(at_eof(p)){ - err = end_start(p); - } else if(in_space_class(c)){ - //skip - } else if(in_comment_class(c)){ - begin_comment(p, c); - } else if(c == c_list_open){ - begin_list(p, c); - } else if(c == c_list_close){ - parse_error(p); - err = -EINVAL; - } else if(in_string_quote_class(c)){ - begin_string(p, c); - } else if(in_printable_class(c)){ - begin_atom(p, c); - } else if(c == 0x04){ - //ctrl-D, EOT: end-of-text. - Parser_input_eof(p); - } else { - parse_error(p); - err = -EINVAL; - } - return err; -} - -int end_start(Parser *p){ - int err = 0; - err = Parser_return(p); - return err; -} - -int begin_comment(Parser *p, char c){ - int err = 0; - err = Parser_push(p, state_comment); - if(err) goto exit; - err = inputchar(p, c); - exit: - return err; -} - -int state_comment(Parser *p, char c){ - int err = 0; - if(c == '\n' || at_eof(p)){ - err = end_comment(p); - } else { - err = inputchar(p, c); - } - return err; -} - -int end_comment(Parser *p){ - return Parser_pop(p); -} - -int begin_string(Parser *p, char c){ - int err = 0; - err = Parser_push(p, state_string); - if(err) goto exit; - newtoken(p); - p->state->delim = c; - exit: - return err; -} - -int state_string(Parser *p, char c){ - int err = 0; - if(at_eof(p)){ - parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF); - err = -EINVAL; - } else if(c == p->state->delim){ - err = end_string(p); - } else if(c == '\\'){ - err = Parser_push(p, state_escape); - } else { - err = savechar(p, c); - } - return err; -} - -int end_string(Parser *p){ - int err = 0; - err = do_string(p); - if(err) goto exit; - err = Parser_return(p); - exit: - return err; -} - -int state_escape(Parser *p, char c){ - int err = 0; - char d; - if(at_eof(p)){ - parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF); - err = -EINVAL; - goto exit; - } - if(get_escape(c, &d) == 0){ - err = savechar(p, d); - if(err) goto exit; - err = Parser_pop(p); - } else if(c == 'x'){ - p->state->fn = state_hex; - p->state->ival = 0; - p->state->count = 0; - } else { - p->state->fn = state_octal; - p->state->ival = 0; - p->state->count = 0; - err = Parser_input_char(p, c); - } - exit: - return err; -} - -int octaldone(Parser *p){ - int err = 0; - char d = (char)(p->state->ival & 0xff); - err = Parser_pop(p); - if(err) goto exit; - err = Parser_input_char(p, d); - exit: - return err; -} - -int octaldigit(Parser *p, char c){ - int err = 0; - p->state->ival *= 8; - p->state->ival += c - '0'; - p->state->count++; - if(err) goto exit; - if(p->state->ival < 0 || p->state->ival > 0xff){ - parse_error(p); - err = -EINVAL; - goto exit; - } - if(p->state->count == 3){ - err = octaldone(p); - } - exit: - return err; -} - -int state_octal(Parser *p, char c){ - int err = 0; - if(at_eof(p)){ - parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF); - err = -EINVAL; - goto exit; - } else if('0' <= c && c <= '7'){ - err = octaldigit(p, c); - } else { - err = octaldone(p); - if(err) goto exit; - Parser_input_char(p, c); - } - exit: - return err; -} - -int hexdone(Parser *p){ - int err = 0; - char d = (char)(p->state->ival & 0xff); - err = Parser_pop(p); - if(err) goto exit; - err = Parser_input_char(p, d); - exit: - return err; -} - -int hexdigit(Parser *p, char c, char d){ - int err = 0; - p->state->ival *= 16; - p->state->ival += c - d; - p->state->count++; - if(err) goto exit; - if(p->state->ival < 0 || p->state->ival > 0xff){ - parse_error(p); - err = -EINVAL; - goto exit; - } - if(p->state->count == 2){ - err = hexdone(p); - } - exit: - return err; -} - -int state_hex(Parser *p, char c){ - int err = 0; - if(at_eof(p)){ - parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF); - err = -EINVAL; - goto exit; - } else if('0' <= c && c <= '9'){ - err = hexdigit(p, c, '0'); - } else if('A' <= c && c <= 'F'){ - err = hexdigit(p, c, 'A'); - } else if('a' <= c && c <= 'f'){ - err = hexdigit(p, c, 'a'); - } else if(p->state->count){ - err =hexdone(p); - if(err) goto exit; - Parser_input_char(p, c); - } - exit: - return err; -} - -int begin_atom(Parser *p, char c){ - int err = 0; - err = Parser_push(p, state_atom); - if(err) goto exit; - newtoken(p); - err = savechar(p, c); - exit: - return err; -} - -int state_atom(Parser *p, char c){ - int err = 0; - if(at_eof(p)){ - err = end_atom(p); - } else if(is_separator(p, c) || - in_space_class(c) || - in_comment_class(c)){ - err = end_atom(p); - if(err) goto exit; - err = Parser_input_char(p, c); - } else { - err = savechar(p, c); - } - exit: - return err; -} - -int end_atom(Parser *p){ - int err = 0; - err = do_intern(p); - if(err) goto exit; - err = Parser_return(p); - exit: - return err; -} - -int state_list(Parser *p, char c){ - int err = 0; - if(at_eof(p)){ - parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF); - err = -EINVAL; - } else if(c == c_list_close){ - p->state->val = nrev(p->state->val); - err = end_list(p); - } else { - err = state_start(p, c); - } - return err; - -} - -int begin_list(Parser *p, char c){ - return Parser_push(p, state_list); -} - -int end_list(Parser *p){ - return Parser_return(p); -} - -/** Reset the fields of a parser to initial values. - * - * @param z parser - */ -static void reset(Parser *z){ - IOStream *error_out = z->error_out; - int flags = z->flags; - zero(z, sizeof(Parser)); - z->buf_n = sizeof(z->buf) - 1; - z->buf_i = 0; - z->line_no = 1; - z->char_no = 0; - z->error_out = error_out; - z->flags = flags; -} - -/** Set the parser error stream. - * Parse errors are reported on the the error stream if it is non-null. - * - * @param z parser - * @param error_out error stream - */ -void set_error_stream(Parser *z, IOStream *error_out){ - if(z){ - z->error_out = error_out; - } -} - -/** Get the parser error message for an error code. - * - * @param id error code - * @return error message (empty string if the code is unknown) - */ -static char *get_message(ParseErrorId id){ - int i; - for(i=0; iline_no; -} - -/** Get the column number. - * - * @param in parser - */ -int get_column(Parser *in){ - return in->char_no; -} - -/** Get the line number the current token started on. - * - * @param in parser - */ -int get_tok_line(Parser *in){ - return in->tok_begin_line; -} - -/** Get the column number the current token started on. - * - * @param in parser - */ -int get_tok_column(Parser *in){ - return in->tok_begin_char; -} - -/** Report a parse error. - * Does nothing if the error stream is null or there is no error. - * - * @param in parser - */ -static void report_error(Parser *in){ - if(in->error_out && in->err){ - char *msg = get_message(in->err); - char *tok = peek_token(in); - IOStream_print(in->error_out, PARSE_ERR_FMT, - get_tok_line(in), get_tok_column(in), msg); - if(tok && tok[0]){ - IOStream_print(in->error_out, " '%s'", tok); - } - IOStream_print(in->error_out, "\n"); - } -} - -/** Get the error message for the current parse error code. - * Does nothing if there is no error. - * - * @param in parser - * @param buf where to place the message - * @param n maximum number of characters to place in buf - * @return current error code (zero for no error) - */ -int parse_error_message(Parser *in, char *buf, int n){ - if(in->err){ - char *msg = get_message(in->err); - snprintf(buf, n, PARSE_ERR_FMT, get_tok_line(in), get_tok_column(in), msg); - } - return in->err; -} - -/** Flag an unspecified parse error. All subsequent reads will fail. - * - * @param in parser - */ -void parse_error(Parser *in){ - parse_error_id(in, PARSE_ERR_INVALID_SYNTAX); -} - -/** Flag a parse error. All subsequent reads will fail. - * Does not change the parser error code if it is already set. - * - * @param in parser - * @param id error code - */ -void parse_error_id(Parser *in, ParseErrorId id){ - if(!in->err){ - in->err = id; - report_error(in); - } -} - -/** Test if the parser's error flag is set. - * - * @param in parser - * @return 1 if set, 0 otherwise - */ -int has_error(Parser *in){ - return (in->err > 0); -} - -/** Test if the parser is at end of input. - * - * @param in parser - * @return 1 if at EOF, 0 otherwise - */ -int at_eof(Parser *p){ - return p->eof; -} - -#ifdef SXPR_PARSER_MAIN -/* Stuff for standalone testing. */ - -#include "file_stream.h" -#include "string_stream.h" - -int stringof(Sxpr exp, char **s){ - int err = 0; - if(ATOMP(exp)){ - *s = atom_name(exp); - } else if(STRINGP(exp)){ - *s = string_string(exp); - } else { - err = -EINVAL; - *s = NULL; - } - return err; -} - -int child_string(Sxpr exp, Sxpr key, char **s){ - int err = 0; - Sxpr val = sxpr_child_value(exp, key, ONONE); - err = stringof(val, s); - return err; -} - -int intof(Sxpr exp, int *v){ - int err = 0; - char *s; - unsigned long l; - if(INTP(exp)){ - *v = OBJ_INT(exp); - } else { - err = stringof(exp, &s); - if(err) goto exit; - err = convert_atoul(s, &l); - *v = (int)l; - } - exit: - return err; -} - -int child_int(Sxpr exp, Sxpr key, int *v){ - int err = 0; - Sxpr val = sxpr_child_value(exp, key, ONONE); - err = intof(val, v); - return err; -} - -int eval_vnet(Sxpr exp){ - int err = 0; - Sxpr oid = intern("id"); - int id; - err = child_int(exp, oid, &id); - if(err) goto exit; - dprintf("> vnet id=%d\n", id); - exit: - dprintf("< err=%d\n", err); - return err; -} - -int eval_connect(Sxpr exp){ - int err = 0; - Sxpr ovif = intern("vif"); - Sxpr ovnet = intern("vnet"); - char *vif; - int vnet; - - err = child_string(exp, ovif, &vif); - if(err) goto exit; - err = child_int(exp, ovnet, &vnet); - if(err) goto exit; - dprintf("> connect vif=%s vnet=%d\n", vif, vnet); - exit: - dprintf("< err=%d\n", err); - return err; -} - -int eval(Sxpr exp){ - int err = 0; - Sxpr oconnect = intern("connect"); - Sxpr ovnet = intern("vnet"); - - if(sxpr_elementp(exp, ovnet)){ - err = eval_vnet(exp); - } else if(sxpr_elementp(exp, oconnect)){ - err = eval_connect(exp); - } else { - err = -EINVAL; - } - return err; -} - -/** Main program for testing. - * Parses input and prints it. - * - * @param argc number of arguments - * @param argv arguments - * @return error code - */ -int main(int argc, char *argv[]){ - Parser *pin; - int err = 0; - char buf[1024]; - int k; - Sxpr obj, l, x; - - pin = Parser_new(); - set_error_stream(pin, iostdout); - dprintf("> parse...\n"); - while(1){ - k = fread(buf, 1, 1024, stdin); - err = Parser_input(pin, buf, k); - dprintf("> Parser_input=%d\n", err); - if(k <= 0) break; - } - obj = pin->val; - for(l = obj ; CONSP(l); l = CDR(l)){ - x = CAR(l); - objprint(iostdout, x, 0); printf("\n"); - eval(x); - } - dprintf("> err=%d\n", err); - return 0; -} -#endif diff --git a/tools/libxutil/sxpr_parser.h b/tools/libxutil/sxpr_parser.h deleted file mode 100644 index 7296312e44..0000000000 --- a/tools/libxutil/sxpr_parser.h +++ /dev/null @@ -1,125 +0,0 @@ -/* - * - * 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.1 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 - */ - -#ifndef _XEN_LIB_SXPR_PARSER_H_ -#define _XEN_LIB_SXPR_PARSER_H_ - -#include "sxpr.h" -#include "iostream.h" - -/** @file - * Sxpr parsing definitions. - */ - -/** Size of a parser input buffer. - * Tokens read must fit into this size (including trailing null). - */ -#define PARSER_BUF_SIZE 1024 - -struct Parser; -typedef int ParserStateFn(struct Parser *, char c); - -typedef struct ParserState { - struct ParserState *parent; - Sxpr val; - int ival; - int count; - char delim; - ParserStateFn *fn; -} ParserState; - -/** Structure representing an input source for the parser. - * Can read from any IOStream implementation. - */ -typedef struct Parser { - Sxpr val; - /** Error reporting stream (null for no reports). */ - IOStream *error_out; - int eof; - /** Error flag. Non-zero if there has been a read error. */ - int err; - /** Line number on input (from 1). */ - int line_no; - /** Column number of input (reset on new line). */ - int char_no; - /** Lookahead character. */ - char c; - /** Buffer for reading tokens. */ - char buf[PARSER_BUF_SIZE]; - /** Size of token buffer. */ - int buf_n; - int buf_i; - /** Line the last token started on. */ - int tok_begin_line; - /** Character number the last token started on. */ - int tok_begin_char; - /** Parsing flags. */ - int flags; - ParserState *state; -} Parser; - -/** Parser error codes. */ -typedef enum { - PARSE_ERR_NONE=0, - PARSE_ERR_UNSPECIFIED, - PARSE_ERR_NOMEM, - PARSE_ERR_UNEXPECTED_EOF, - PARSE_ERR_TOKEN_TOO_LONG, - PARSE_ERR_INVALID_SYNTAX, - PARSE_ERR_INVALID_ESCAPE, -} ParseErrorId; - - -/** Parser flags. */ -//enum { -//}; - -/** Raise some parser flags. - * - * @param in parser - * @param flags flags mask - */ -inline static void parser_flags_raise(Parser *in, int flags){ - in->flags |= flags; -} - -/** Lower some parser flags. - * - * @param in parser - * @param flags flags mask - */ -inline static void parser_flags_lower(Parser *in, int flags){ - in->flags &= ~flags; -} - -/** Clear all parser flags. - * - * @param in parser - */ -inline static void parser_flags_clear(Parser *in){ - in->flags = 0; -} - -extern void Parser_free(Parser *z); -extern Parser * Parser_new(void); -extern int Parser_input(Parser *p, char *buf, int buf_n); -extern int Parser_input_eof(Parser *p); - -extern int parse_error_message(Parser *in, char *buf, int n); -extern int has_error(Parser *in); -extern int at_eof(Parser *in); - -#endif /* ! _XEN_LIB_SXPR_PARSER_H_ */ diff --git a/tools/libxutil/xdr.c b/tools/libxutil/xdr.c deleted file mode 100644 index dfb91f23c4..0000000000 --- a/tools/libxutil/xdr.c +++ /dev/null @@ -1,246 +0,0 @@ -/* $Id: xdr.c,v 1.3 2003/09/29 13:40:00 mjw Exp $ */ -#include "xdr.h" -#include -/** @file - * XDR packer/unpacker for elements. - * - * string -> [T_STRING] [len:u32] - * atom -> [T_ATOM] [len:u32] - * uint -> [T_UINT] [value] - * cons -> [T_CONS] - * null -> [T_NULL] - * none -> [T_NONE] - * bool -> [T_BOOL] { 0:u8 | 1:u8 } - * - * types packed as u16. - * - * So (a b c) -> [T_CONS] a [T_CONS] b [T_CONS] c [T_NULL] - * () -> [T_NULL] - */ - -int pack_bool(IOStream *io, int x){ - int err=0; - err = IOStream_print(io, "%c", 0xff & x); - if(err > 0) err = 0; - return err; -} - -int unpack_bool(IOStream *io, int *x){ - int err = 0; - int c; - c = IOStream_getc(io); - *x = (c < 0 ? 0 : c); - err = IOStream_error(io); - if(c < 0 && !err) err = -EIO; - return err; -} - -int pack_ushort(IOStream *io, unsigned short x){ - int err=0; - err = IOStream_print(io, "%c%c", - 0xff & (x >> 8), - 0xff & (x )); - if(err > 0) err = 0; - return err; -} - -int unpack_ushort(IOStream *io, unsigned short *x){ - int err = 0; - int i, c = 0; - *x = 0; - for(i = 0; i< 2; i++){ - c = IOStream_getc(io); - if(c < 0) break; - *x <<= 8; - *x |= (0xff & c); - } - err = IOStream_error(io); - if(c < 0 && !err) err = -EIO; - return err; -} - -int pack_uint(IOStream *io, unsigned int x){ - int err=0; - err = IOStream_print(io, "%c%c%c%c", - 0xff & (x >> 24), - 0xff & (x >> 16), - 0xff & (x >> 8), - 0xff & (x )); - if(err > 0) err = 0; - return err; -} - -int unpack_uint(IOStream *io, unsigned int *x){ - int err = 0; - int i, c = 0; - *x = 0; - for(i = 0; i< 4; i++){ - c = IOStream_getc(io); - if(c < 0) break; - *x <<= 8; - *x |= (0xff & c); - } - err = IOStream_error(io); - if(c < 0 && !err) err = -EIO; - return err; -} - -int pack_string(IOStream *io, Sxpr x){ - int err = 0; - int n = string_length(x); - char *s = string_string(x); - int i; - err = pack_uint(io, n); - if(err) goto exit; - for(i = 0; i < n; i++){ - err = IOStream_print(io, "%c", s[i]); - if(err < 0) break; - } - if(err > 0) err = 0; - exit: - return err; -} - -int unpack_string(IOStream *io, Sxpr *x){ - int err; - unsigned int n; - int i, c = 0; - char *s; - Sxpr val = ONONE; - - err = unpack_uint(io, &n); - if(err) goto exit; - val = halloc(n+1, T_STRING); - if(NOMEMP(val)){ - err = -ENOMEM; - goto exit; - } - s = string_string(val); - for(i=0; iname); - break; - case T_STRING: - err = pack_string(io, x); - break; - case T_UINT: - err = pack_uint(io, get_ul(x)); - break; - default: - err = -EINVAL; - IOStream_print(iostderr, "%s> invalid type %d\n", __FUNCTION__, type); - break; - } - exit: - return err; -} - -int unpack_sxpr(IOStream *io, Sxpr *x){ - int err = 0; - unsigned short type; - unsigned int u; - Sxpr val = ONONE, y; - - err = unpack_ushort(io, &type); - if(err) goto exit; - switch(type){ - case T_NULL: - val = ONULL; - break; - case T_NONE: - val = ONONE; - break; - case T_CONS: - err = unpack_cons(io, &val); - break; - case T_BOOL: - err = unpack_bool(io, &u); - if(err) goto exit; - val = (u ? OTRUE : OFALSE); - break; - case T_ATOM: - err = unpack_string(io, &y); - if(err) goto exit; - val = intern(string_string(y)); - objfree(y); - break; - case T_STRING: - err = unpack_string(io, &val); - break; - case T_UINT: - err = unpack_uint(io, &u); - if(err) goto exit; - val = OBJI(type, u); - break; - default: - err = -EINVAL; - IOStream_print(iostderr, "%s> invalid type %d\n", __FUNCTION__, type); - break; - } - exit: - *x = (err ? ONONE : val); - return err; -} diff --git a/tools/libxutil/xdr.h b/tools/libxutil/xdr.h deleted file mode 100644 index cb7d97df95..0000000000 --- a/tools/libxutil/xdr.h +++ /dev/null @@ -1,14 +0,0 @@ -/* $Id: xdr.h,v 1.2 2003/09/29 13:40:00 mjw Exp $ */ -#ifndef _SP_XDR_H_ -#define _SP_XDR_H_ -#include "iostream.h" -#include "sxpr.h" -int pack_uint(IOStream *out, unsigned int x); -int unpack_uint(IOStream *in, unsigned int *x); -int pack_string(IOStream *out, Sxpr x); -int unpack_string(IOStream *in, Sxpr *x); -int pack_cons(IOStream *out, Sxpr x); -int unpack_cons(IOStream *in, Sxpr *x); -int pack_sxpr(IOStream *out, Sxpr x); -int unpack_sxpr(IOStream *in, Sxpr *x); -#endif /* _SP_XDR_H_ */ diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index c43dcfe892..75dda1b1c7 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -283,7 +283,7 @@ def vm_restore(src, progress=0): d = restorefn(state_file=src, progress=progress) dom = int(d['dom']) if dom < 0: - raise VMError('restore failed') + raise VmError('restore failed') vmconfig = sxp.from_string(d['vmconfig']) vm.config = sxp.child_value(vmconfig, 'config') deferred = vm.dom_configure(dom) @@ -611,7 +611,7 @@ class XendDomainInfo: if not os.path.isfile(kernel): raise VmError('Kernel image does not exist: %s' % kernel) if ramdisk and not os.path.isfile(ramdisk): - raise VMError('Kernel ramdisk does not exist: %s' % ramdisk) + raise VmError('Kernel ramdisk does not exist: %s' % ramdisk) print 'create-domain> init_domain...' self.init_domain() print 'create_domain>', 'dom=', self.dom @@ -691,7 +691,7 @@ class XendDomainInfo: """ d = dom_get(dom) if not d: - raise VMError("Domain not found: %d" % dom) + raise VmError("Domain not found: %d" % dom) try: self.setdom(dom) self.name = d['name'] @@ -807,10 +807,10 @@ def vm_dev_vbd(vm, val, index): vdev = index uname = sxp.child_value(val, 'uname') if not uname: - raise VMError('vbd: Missing uname') + raise VmError('vbd: Missing uname') dev = sxp.child_value(val, 'dev') if not dev: - raise VMError('vbd: Missing dev') + raise VmError('vbd: Missing dev') mode = sxp.child_value(val, 'mode', 'r') defer = make_disk(vm.dom, uname, dev, mode, vm.recreate) def fn(vbd): @@ -833,24 +833,24 @@ def parse_pci(val): def vm_dev_pci(vm, val, index): bus = sxp.child_value(val, 'bus') if not bus: - raise VMError('pci: Missing bus') + raise VmError('pci: Missing bus') dev = sxp.child_value(val, 'dev') if not dev: - raise VMError('pci: Missing dev') + raise VmError('pci: Missing dev') func = sxp.child_value(val, 'func') if not func: - raise VMError('pci: Missing func') + raise VmError('pci: Missing func') try: bus = parse_pci(bus) dev = parse_pci(dev) func = parse_pci(func) except: - raise VMError('pci: invalid parameter') + raise VmError('pci: invalid parameter') rc = xc.physdev_pci_access_modify(dom=vm.dom, bus=bus, dev=dev, func=func, enable=1) if rc < 0: #todo non-fatal - raise VMError('pci: Failed to configure device: bus=%s dev=%s func=%s' % + raise VmError('pci: Failed to configure device: bus=%s dev=%s func=%s' % (bus, dev, func)) return rc From 21eba388cb62032989571041343e2366b397a320 Mon Sep 17 00:00:00 2001 From: "mjw@wray-m-3.hpl.hp.com" Date: Wed, 30 Jun 2004 14:42:36 +0000 Subject: [PATCH 02/36] bitkeeper revision 1.1038.1.2 (40e2d15cfcuphKQbfhX2mh2JEFMyPA) Some missing 'types' imports and prefixes spotted by Niraj. --- tools/python/xen/xend/Args.py | 1 + tools/python/xen/xend/XendDomainInfo.py | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/python/xen/xend/Args.py b/tools/python/xen/xend/Args.py index 527e841d3d..31bc067d07 100644 --- a/tools/python/xen/xend/Args.py +++ b/tools/python/xen/xend/Args.py @@ -1,3 +1,4 @@ +import types import sxp class ArgError(StandardError): diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index 75dda1b1c7..e3e4e92cbd 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -9,6 +9,7 @@ Author: Mike Wray """ import string +import types import re import sys import os @@ -821,7 +822,7 @@ def vm_dev_vbd(vm, val, index): return defer def parse_pci(val): - if isinstance(val, StringType): + if isinstance(val, types.StringType): radix = 10 if val.startswith('0x') or val.startswith('0X'): radix = 16 From 3905d888b656268bf9b9e1932fc45415554d9218 Mon Sep 17 00:00:00 2001 From: "djm@kirby.fc.hp.com" Date: Wed, 30 Jun 2004 22:26:29 +0000 Subject: [PATCH 03/36] bitkeeper revision 1.1041.2.3 (40e33e15ASwSHg8_daLqUfOJezgo6A) Encapsulate shadow_mode for minimal perturbation portability and move shadow.[ch] to machdep layer --- .rootkeys | 5 +- BitKeeper/etc/logging_ok | 1 + xen/{common => arch/x86}/shadow.c | 0 xen/include/asm-x86/shadow.h | 604 ++++++++++++++++++++++++++++++ xen/include/xen/shadow.h | 600 +---------------------------- 5 files changed, 609 insertions(+), 601 deletions(-) rename xen/{common => arch/x86}/shadow.c (100%) create mode 100644 xen/include/asm-x86/shadow.h diff --git a/.rootkeys b/.rootkeys index feb8ec1995..26357f0617 100644 --- a/.rootkeys +++ b/.rootkeys @@ -326,6 +326,7 @@ 3ddb79bc1_2bAt67x9MFCP4AZrQnvQ xen/arch/x86/process.c 3ddb79bc7KxGCEJsgBnkDX7XjD_ZEQ xen/arch/x86/rwlock.c 3ddb79bcrD6Z_rUvSDgrvjyb4846Eg xen/arch/x86/setup.c +405b8599xI_PoEr3zZoJ2on-jdn7iw xen/arch/x86/shadow.c 3ddb79bcSx2e8JSR3pdSGa8x1ScYzA xen/arch/x86/smp.c 3ddb79bcfUN3-UBCPzX26IU8bq-3aw xen/arch/x86/smpboot.c 3ddb79bc-Udq7ol-NX4q9XsYnN7A2Q xen/arch/x86/time.c @@ -353,7 +354,6 @@ 40589968dD2D1aejwSOvrROg7fOvGQ xen/common/sched_bvt.c 40589968be_t_n0-w6ggceW7h-sx0w xen/common/sched_rrobin.c 3e397e6619PgAfBbw2XFbXkewvUWgw xen/common/schedule.c -405b8599xI_PoEr3zZoJ2on-jdn7iw xen/common/shadow.c 3ddb79bdB9RNMnkQnUyZ5C9hhMSQQw xen/common/slab.c 3ddb79bd0gVQYmL2zvuJnldvD0AGxQ xen/common/softirq.c 3e7f358awXBC3Vw-wFRwPw18qL1khg xen/common/string.c @@ -443,6 +443,7 @@ 3ddb79c2QF5-pZGzuX4QukPCDAl59A xen/include/asm-x86/processor.h 40cf1596bim9F9DNdV75klgRSZ6Y2A xen/include/asm-x86/ptrace.h 3ddb79c2plf7ciNgoNjU-RsbUzawsw xen/include/asm-x86/rwlock.h +405b8599BsDsDwKEJLS0XipaiQW3TA xen/include/asm-x86/shadow.h 3ddb79c3Hgbb2g8CyWLMCK-6_ZVQSQ xen/include/asm-x86/smp.h 3ddb79c3jn8ALV_S9W5aeTYUQRKBpg xen/include/asm-x86/smpboot.h 3ddb79c3NiyQE2vQnyGiaBnNjBO1rA xen/include/asm-x86/spinlock.h @@ -500,7 +501,7 @@ 40589969nPq3DMzv24RDb5LXE9brHw xen/include/xen/sched-if.h 3ddb79c0LzqqS0LhAQ50ekgj4oGl7Q xen/include/xen/sched.h 403a06a7H0hpHcKpAiDe5BPnaXWTlA xen/include/xen/serial.h -405b8599BsDsDwKEJLS0XipaiQW3TA xen/include/xen/shadow.h +40e3392dib7GrcBAu5cT-EUZTYzeEQ xen/include/xen/shadow.h 3ddb79c14dXIhP7C2ahnoD08K90G_w xen/include/xen/slab.h 3ddb79c09xbS-xxfKxuV3JETIhBzmg xen/include/xen/smp.h 3ddb79c1Vi5VleJAOKHAlY0G2zAsgw xen/include/xen/softirq.h diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok index 04eb20bb84..d2431905b5 100644 --- a/BitKeeper/etc/logging_ok +++ b/BitKeeper/etc/logging_ok @@ -9,6 +9,7 @@ bd240@labyrinth.cl.cam.ac.uk br260@br260.wolfson.cam.ac.uk br260@labyrinth.cl.cam.ac.uk br260@laudney.cl.cam.ac.uk +djm@kirby.fc.hp.com gm281@boulderdash.cl.cam.ac.uk iap10@freefall.cl.cam.ac.uk iap10@labyrinth.cl.cam.ac.uk diff --git a/xen/common/shadow.c b/xen/arch/x86/shadow.c similarity index 100% rename from xen/common/shadow.c rename to xen/arch/x86/shadow.c diff --git a/xen/include/asm-x86/shadow.h b/xen/include/asm-x86/shadow.h new file mode 100644 index 0000000000..df24329b2b --- /dev/null +++ b/xen/include/asm-x86/shadow.h @@ -0,0 +1,604 @@ +/* -*- Mode:C; c-basic-offset:4; tab-width:4 -*- */ + +#ifndef _XEN_SHADOW_H +#define _XEN_SHADOW_H + +#include +#include +#include +#include + + +/* Shadow PT flag bits in pfn_info */ +#define PSH_shadowed (1<<31) /* page has a shadow. PFN points to shadow */ +#define PSH_pending (1<<29) /* page is in the process of being shadowed */ +#define PSH_pfn_mask ((1<<21)-1) + +/* Shadow PT operation mode : shadowmode variable in mm_struct */ +#define SHM_test (1) /* just run domain on shadow PTs */ +#define SHM_logdirty (2) /* log pages that are dirtied */ +#define SHM_translate (3) /* lookup machine pages in translation table */ +//#define SHM_cow (4) /* copy on write all dirtied pages */ + + +#define shadow_linear_pg_table ((l1_pgentry_t *)SH_LINEAR_PT_VIRT_START) +#define shadow_linear_l2_table ((l2_pgentry_t *)(SH_LINEAR_PT_VIRT_START+(SH_LINEAR_PT_VIRT_START>>(L2_PAGETABLE_SHIFT-L1_PAGETABLE_SHIFT)))) + +extern void shadow_mode_init(void); +extern int shadow_mode_control( struct domain *p, dom0_shadow_control_t *sc ); +extern int shadow_fault( unsigned long va, long error_code ); +extern void shadow_l1_normal_pt_update( unsigned long pa, unsigned long gpte, + unsigned long *prev_spfn_ptr, + l1_pgentry_t **prev_spl1e_ptr ); +extern void shadow_l2_normal_pt_update( unsigned long pa, unsigned long gpte ); +extern void unshadow_table( unsigned long gpfn, unsigned int type ); +extern int shadow_mode_enable( struct domain *p, unsigned int mode ); +extern void shadow_mode_disable( struct domain *p ); +extern unsigned long shadow_l2_table( + struct mm_struct *m, unsigned long gpfn ); + +#define SHADOW_DEBUG 0 +#define SHADOW_HASH_DEBUG 0 +#define SHADOW_OPTIMISE 1 + +struct shadow_status { + unsigned long pfn; // gpfn + unsigned long spfn_and_flags; // spfn plus flags + struct shadow_status *next; // use pull-to-front list. +}; + +#define shadow_ht_extra_size 128 /*128*/ +#define shadow_ht_buckets 256 /*256*/ + +#ifndef NDEBUG +#define SH_LOG(_f, _a...) \ +printk("DOM%u: (file=shadow.c, line=%d) " _f "\n", \ + current->domain , __LINE__ , ## _a ) +#else +#define SH_LOG(_f, _a...) +#endif + +#if SHADOW_DEBUG +#define SH_VLOG(_f, _a...) \ + printk("DOM%u: (file=shadow.c, line=%d) " _f "\n", \ + current->domain , __LINE__ , ## _a ) +#else +#define SH_VLOG(_f, _a...) +#endif + +#if 0 +#define SH_VVLOG(_f, _a...) \ + printk("DOM%u: (file=shadow.c, line=%d) " _f "\n", \ + current->domain , __LINE__ , ## _a ) +#else +#define SH_VVLOG(_f, _a...) +#endif + + +/************************************************************************/ + +#define shadow_mode(d) (d->mm.shadow_mode) +#define shadow_lock_init(d) spin_lock_init(&d->mm.shadow_lock) + +/************************************************************************/ + +static inline int __mark_dirty( struct mm_struct *m, unsigned int mfn ) +{ + unsigned int pfn; + int rc = 0; + + ASSERT(spin_is_locked(&m->shadow_lock)); + + pfn = machine_to_phys_mapping[mfn]; + + /* We use values with the top bit set to mark MFNs that aren't + really part of the domain's psuedo-physical memory map e.g. + the shared info frame. Nothing to do here... + */ + if ( unlikely(pfn & 0x80000000U) ) return rc; + + ASSERT(m->shadow_dirty_bitmap); + if( likely(pfnshadow_dirty_bitmap_size) ) + { + /* These updates occur with mm.shadow_lock held, so use + (__) version of test_and_set */ + if( __test_and_set_bit( pfn, m->shadow_dirty_bitmap ) == 0 ) + { + // if we set it + m->shadow_dirty_count++; + rc = 1; + } + } + else + { + extern void show_traceX(void); + SH_LOG("mark_dirty OOR! mfn=%x pfn=%x max=%x (mm %p)", + mfn, pfn, m->shadow_dirty_bitmap_size, m ); + SH_LOG("dom=%u caf=%08x taf=%08x\n", + frame_table[mfn].u.domain->domain, + frame_table[mfn].count_and_flags, + frame_table[mfn].type_and_flags ); + } + + return rc; +} + + +static inline int mark_dirty( struct mm_struct *m, unsigned int mfn ) +{ + int rc; + ASSERT(local_irq_is_enabled()); + //if(spin_is_locked(&m->shadow_lock)) printk("+"); + spin_lock(&m->shadow_lock); + rc = __mark_dirty( m, mfn ); + spin_unlock(&m->shadow_lock); + return rc; +} + + +/************************************************************************/ + +static inline void l1pte_write_fault( struct mm_struct *m, + unsigned long *gpte_p, unsigned long *spte_p ) +{ + unsigned long gpte = *gpte_p; + unsigned long spte = *spte_p; + + switch( m->shadow_mode ) + { + case SHM_test: + spte = gpte; + gpte |= _PAGE_DIRTY | _PAGE_ACCESSED; + spte |= _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED; + break; + + case SHM_logdirty: + spte = gpte; + gpte |= _PAGE_DIRTY | _PAGE_ACCESSED; + spte |= _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED; + __mark_dirty( m, (gpte >> PAGE_SHIFT) ); + break; + } + + *gpte_p = gpte; + *spte_p = spte; +} + +static inline void l1pte_read_fault( struct mm_struct *m, + unsigned long *gpte_p, unsigned long *spte_p ) +{ + unsigned long gpte = *gpte_p; + unsigned long spte = *spte_p; + + switch( m->shadow_mode ) + { + case SHM_test: + spte = gpte; + gpte |= _PAGE_ACCESSED; + spte |= _PAGE_ACCESSED; + if ( ! (gpte & _PAGE_DIRTY ) ) + spte &= ~ _PAGE_RW; + break; + + case SHM_logdirty: + spte = gpte; + gpte |= _PAGE_ACCESSED; + spte |= _PAGE_ACCESSED; + spte &= ~ _PAGE_RW; + break; + } + + *gpte_p = gpte; + *spte_p = spte; +} + +static inline void l1pte_no_fault( struct mm_struct *m, + unsigned long *gpte_p, unsigned long *spte_p ) +{ + unsigned long gpte = *gpte_p; + unsigned long spte = *spte_p; + + switch( m->shadow_mode ) + { + case SHM_test: + spte = 0; + if ( (gpte & (_PAGE_PRESENT|_PAGE_ACCESSED) ) == + (_PAGE_PRESENT|_PAGE_ACCESSED) ) + { + spte = gpte; + if ( ! (gpte & _PAGE_DIRTY ) ) + spte &= ~ _PAGE_RW; + } + break; + + case SHM_logdirty: + spte = 0; + if ( (gpte & (_PAGE_PRESENT|_PAGE_ACCESSED) ) == + (_PAGE_PRESENT|_PAGE_ACCESSED) ) + { + spte = gpte; + spte &= ~ _PAGE_RW; + } + + break; + } + + *gpte_p = gpte; + *spte_p = spte; +} + +static inline void l2pde_general( struct mm_struct *m, + unsigned long *gpde_p, unsigned long *spde_p, + unsigned long sl1pfn) +{ + unsigned long gpde = *gpde_p; + unsigned long spde = *spde_p; + + spde = 0; + + if ( sl1pfn ) + { + spde = (gpde & ~PAGE_MASK) | (sl1pfn<shadow_ht[j]; + if(a->pfn){live++; ASSERT(a->spfn_and_flags&PSH_pfn_mask);} + ASSERT((a->pfn&0xf0000000)==0); + ASSERT(a->pfn<0x00100000); + a=a->next; + while(a && live<9999) + { + live++; + if(a->pfn == 0 || a->spfn_and_flags == 0) + { + printk("XXX live=%d pfn=%08lx sp=%08lx next=%p\n", + live, a->pfn, a->spfn_and_flags, a->next); + BUG(); + } + ASSERT(a->pfn); + ASSERT((a->pfn&0xf0000000)==0); + ASSERT(a->pfn<0x00100000); + ASSERT(a->spfn_and_flags&PSH_pfn_mask); + a=a->next; + } + ASSERT(live<9999); + } + + a = m->shadow_ht_free; + while(a) { free++; a=a->next; } + + if(print) printk("Xlive=%d free=%d\n",live,free); + + abs=(perfc_value(shadow_l1_pages)+perfc_value(shadow_l2_pages))-live; + if( abs < -1 || abs > 1 ) + { + printk("live=%d free=%d l1=%d l2=%d\n",live,free, + perfc_value(shadow_l1_pages), perfc_value(shadow_l2_pages) ); + BUG(); + } + +} + +#else +#define shadow_audit(p, print) +#endif + + + +static inline struct shadow_status* hash_bucket( struct mm_struct *m, + unsigned int gpfn ) +{ + return &(m->shadow_ht[gpfn % shadow_ht_buckets]); +} + + +static inline unsigned long __shadow_status( struct mm_struct *m, + unsigned int gpfn ) +{ + struct shadow_status **ob, *b, *B = hash_bucket( m, gpfn ); + + b = B; + ob = NULL; + + SH_VVLOG("lookup gpfn=%08x bucket=%p", gpfn, b ); + shadow_audit(m,0); // if in debug mode + + do + { + if ( b->pfn == gpfn ) + { + unsigned long t; + struct shadow_status *x; + + // swap with head + t=B->pfn; B->pfn=b->pfn; b->pfn=t; + t=B->spfn_and_flags; B->spfn_and_flags=b->spfn_and_flags; + b->spfn_and_flags=t; + + if( ob ) + { // pull to front + *ob=b->next; + x=B->next; + B->next=b; + b->next=x; + } + return B->spfn_and_flags; + } +#if SHADOW_HASH_DEBUG + else + { + if(b!=B)ASSERT(b->pfn); + } +#endif + ob=&b->next; + b=b->next; + } + while (b); + + return 0; +} + +/* we can make this locking more fine grained e.g. per shadow page if it +ever becomes a problem, but since we need a spin lock on the hash table +anyway its probably not worth being too clever. */ + +static inline unsigned long get_shadow_status( struct mm_struct *m, + unsigned int gpfn ) +{ + unsigned long res; + + /* If we get here, we know that this domain is running in shadow mode. + We also know that some sort of update has happened to the underlying + page table page: either a PTE has been updated, or the page has + changed type. If we're in log dirty mode, we should set the approrpiate + bit in the dirty bitmap. + NB: the VA update path doesn't use this so needs to be handled + independnetly. + */ + + ASSERT(local_irq_is_enabled()); + //if(spin_is_locked(&m->shadow_lock)) printk("*"); + spin_lock(&m->shadow_lock); + + if( m->shadow_mode == SHM_logdirty ) + __mark_dirty( m, gpfn ); + + res = __shadow_status( m, gpfn ); + if (!res) spin_unlock(&m->shadow_lock); + return res; +} + + +static inline void put_shadow_status( struct mm_struct *m ) +{ + spin_unlock(&m->shadow_lock); +} + + +static inline void delete_shadow_status( struct mm_struct *m, + unsigned int gpfn ) +{ + struct shadow_status *b, *B, **ob; + + ASSERT(spin_is_locked(&m->shadow_lock)); + + B = b = hash_bucket( m, gpfn ); + + SH_VVLOG("delete gpfn=%08x bucket=%p", gpfn, b ); + shadow_audit(m,0); + ASSERT(gpfn); + + if( b->pfn == gpfn ) + { + if (b->next) + { + struct shadow_status *D=b->next; + b->spfn_and_flags = b->next->spfn_and_flags; + b->pfn = b->next->pfn; + + b->next = b->next->next; + D->next = m->shadow_ht_free; + D->pfn = 0; + D->spfn_and_flags = 0; + m->shadow_ht_free = D; + } + else + { + b->pfn = 0; + b->spfn_and_flags = 0; + } + +#if SHADOW_HASH_DEBUG + if( __shadow_status(m,gpfn) ) BUG(); + shadow_audit(m,0); +#endif + return; + } + + ob = &b->next; + b=b->next; + + do + { + if ( b->pfn == gpfn ) + { + b->pfn = 0; + b->spfn_and_flags = 0; + + // b is in the list + *ob=b->next; + b->next = m->shadow_ht_free; + m->shadow_ht_free = b; + +#if SHADOW_HASH_DEBUG + if( __shadow_status(m,gpfn) ) BUG(); +#endif + shadow_audit(m,0); + return; + } + + ob = &b->next; + b=b->next; + } + while (b); + + // if we got here, it wasn't in the list + BUG(); +} + + +static inline void set_shadow_status( struct mm_struct *m, + unsigned int gpfn, unsigned long s ) +{ + struct shadow_status *b, *B, *extra, **fptr; + int i; + + ASSERT(spin_is_locked(&m->shadow_lock)); + + B = b = hash_bucket( m, gpfn ); + + ASSERT(gpfn); + SH_VVLOG("set gpfn=%08x s=%08lx bucket=%p(%p)", gpfn, s, b, b->next ); + + shadow_audit(m,0); + + do + { + if ( b->pfn == gpfn ) + { + b->spfn_and_flags = s; + shadow_audit(m,0); + return; + } + + b=b->next; + } + while (b); + + // if we got here, this is an insert rather than update + + ASSERT( s ); // deletes must have succeeded by here + + if ( B->pfn == 0 ) + { + // we can use this head + ASSERT( B->next == 0 ); + B->pfn = gpfn; + B->spfn_and_flags = s; + shadow_audit(m,0); + return; + } + + if( unlikely(m->shadow_ht_free == NULL) ) + { + SH_LOG("allocate more shadow hashtable blocks"); + + // we need to allocate more space + extra = kmalloc(sizeof(void*) + (shadow_ht_extra_size * + sizeof(struct shadow_status))); + + if( ! extra ) BUG(); // should be more graceful here.... + + memset(extra, 0, sizeof(void*) + (shadow_ht_extra_size * + sizeof(struct shadow_status))); + + m->shadow_extras_count++; + + // add extras to free list + fptr = &m->shadow_ht_free; + for ( i=0; ishadow_ht_extras; + m->shadow_ht_extras = extra; + + } + + // should really put this in B to go right to front + b = m->shadow_ht_free; + m->shadow_ht_free = b->next; + b->spfn_and_flags = s; + b->pfn = gpfn; + b->next = B->next; + B->next = b; + + shadow_audit(m,0); + + return; +} + +static inline void __shadow_mk_pagetable( struct mm_struct *mm ) +{ + unsigned long gpfn, spfn=0; + + gpfn = pagetable_val(mm->pagetable) >> PAGE_SHIFT; + + if ( unlikely((spfn=__shadow_status(mm, gpfn)) == 0 ) ) + { + spfn = shadow_l2_table(mm, gpfn ); + } + mm->shadow_table = mk_pagetable(spfn<pagetable), mm->shadow_mode ); + + if ( unlikely(mm->shadow_mode) ) + { + ASSERT(local_irq_is_enabled()); + spin_lock(&mm->shadow_lock); + + __shadow_mk_pagetable( mm ); + + spin_unlock(&mm->shadow_lock); + } + + SH_VVLOG("leaving shadow_mk_pagetable( gptbase=%08lx, mode=%d ) sh=%08lx", + pagetable_val(mm->pagetable), mm->shadow_mode, + pagetable_val(mm->shadow_table) ); + +} + + +#if SHADOW_DEBUG +extern int check_pagetable(struct mm_struct *m, pagetable_t pt, char *s); +#else +#define check_pagetable(m, pt, s) ((void)0) +#endif + + +#endif /* XEN_SHADOW_H */ + + diff --git a/xen/include/xen/shadow.h b/xen/include/xen/shadow.h index e4dbd1b061..c59e02e14c 100644 --- a/xen/include/xen/shadow.h +++ b/xen/include/xen/shadow.h @@ -1,599 +1 @@ -/* -*- Mode:C; c-basic-offset:4; tab-width:4 -*- */ - -#ifndef _XEN_SHADOW_H -#define _XEN_SHADOW_H - -#include -#include -#include -#include - - -/* Shadow PT flag bits in pfn_info */ -#define PSH_shadowed (1<<31) /* page has a shadow. PFN points to shadow */ -#define PSH_pending (1<<29) /* page is in the process of being shadowed */ -#define PSH_pfn_mask ((1<<21)-1) - -/* Shadow PT operation mode : shadowmode variable in mm_struct */ -#define SHM_test (1) /* just run domain on shadow PTs */ -#define SHM_logdirty (2) /* log pages that are dirtied */ -#define SHM_translate (3) /* lookup machine pages in translation table */ -//#define SHM_cow (4) /* copy on write all dirtied pages */ - - -#define shadow_linear_pg_table ((l1_pgentry_t *)SH_LINEAR_PT_VIRT_START) -#define shadow_linear_l2_table ((l2_pgentry_t *)(SH_LINEAR_PT_VIRT_START+(SH_LINEAR_PT_VIRT_START>>(L2_PAGETABLE_SHIFT-L1_PAGETABLE_SHIFT)))) - -extern void shadow_mode_init(void); -extern int shadow_mode_control( struct domain *p, dom0_shadow_control_t *sc ); -extern int shadow_fault( unsigned long va, long error_code ); -extern void shadow_l1_normal_pt_update( unsigned long pa, unsigned long gpte, - unsigned long *prev_spfn_ptr, - l1_pgentry_t **prev_spl1e_ptr ); -extern void shadow_l2_normal_pt_update( unsigned long pa, unsigned long gpte ); -extern void unshadow_table( unsigned long gpfn, unsigned int type ); -extern int shadow_mode_enable( struct domain *p, unsigned int mode ); -extern void shadow_mode_disable( struct domain *p ); -extern unsigned long shadow_l2_table( - struct mm_struct *m, unsigned long gpfn ); - -#define SHADOW_DEBUG 0 -#define SHADOW_HASH_DEBUG 0 -#define SHADOW_OPTIMISE 1 - -struct shadow_status { - unsigned long pfn; // gpfn - unsigned long spfn_and_flags; // spfn plus flags - struct shadow_status *next; // use pull-to-front list. -}; - -#define shadow_ht_extra_size 128 /*128*/ -#define shadow_ht_buckets 256 /*256*/ - -#ifndef NDEBUG -#define SH_LOG(_f, _a...) \ -printk("DOM%u: (file=shadow.c, line=%d) " _f "\n", \ - current->domain , __LINE__ , ## _a ) -#else -#define SH_LOG(_f, _a...) -#endif - -#if SHADOW_DEBUG -#define SH_VLOG(_f, _a...) \ - printk("DOM%u: (file=shadow.c, line=%d) " _f "\n", \ - current->domain , __LINE__ , ## _a ) -#else -#define SH_VLOG(_f, _a...) -#endif - -#if 0 -#define SH_VVLOG(_f, _a...) \ - printk("DOM%u: (file=shadow.c, line=%d) " _f "\n", \ - current->domain , __LINE__ , ## _a ) -#else -#define SH_VVLOG(_f, _a...) -#endif - - -/************************************************************************/ - -static inline int __mark_dirty( struct mm_struct *m, unsigned int mfn ) -{ - unsigned int pfn; - int rc = 0; - - ASSERT(spin_is_locked(&m->shadow_lock)); - - pfn = machine_to_phys_mapping[mfn]; - - /* We use values with the top bit set to mark MFNs that aren't - really part of the domain's psuedo-physical memory map e.g. - the shared info frame. Nothing to do here... - */ - if ( unlikely(pfn & 0x80000000U) ) return rc; - - ASSERT(m->shadow_dirty_bitmap); - if( likely(pfnshadow_dirty_bitmap_size) ) - { - /* These updates occur with mm.shadow_lock held, so use - (__) version of test_and_set */ - if( __test_and_set_bit( pfn, m->shadow_dirty_bitmap ) == 0 ) - { - // if we set it - m->shadow_dirty_count++; - rc = 1; - } - } - else - { - extern void show_traceX(void); - SH_LOG("mark_dirty OOR! mfn=%x pfn=%x max=%x (mm %p)", - mfn, pfn, m->shadow_dirty_bitmap_size, m ); - SH_LOG("dom=%u caf=%08x taf=%08x\n", - frame_table[mfn].u.domain->domain, - frame_table[mfn].count_and_flags, - frame_table[mfn].type_and_flags ); - } - - return rc; -} - - -static inline int mark_dirty( struct mm_struct *m, unsigned int mfn ) -{ - int rc; - ASSERT(local_irq_is_enabled()); - //if(spin_is_locked(&m->shadow_lock)) printk("+"); - spin_lock(&m->shadow_lock); - rc = __mark_dirty( m, mfn ); - spin_unlock(&m->shadow_lock); - return rc; -} - - -/************************************************************************/ - -static inline void l1pte_write_fault( struct mm_struct *m, - unsigned long *gpte_p, unsigned long *spte_p ) -{ - unsigned long gpte = *gpte_p; - unsigned long spte = *spte_p; - - switch( m->shadow_mode ) - { - case SHM_test: - spte = gpte; - gpte |= _PAGE_DIRTY | _PAGE_ACCESSED; - spte |= _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED; - break; - - case SHM_logdirty: - spte = gpte; - gpte |= _PAGE_DIRTY | _PAGE_ACCESSED; - spte |= _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED; - __mark_dirty( m, (gpte >> PAGE_SHIFT) ); - break; - } - - *gpte_p = gpte; - *spte_p = spte; -} - -static inline void l1pte_read_fault( struct mm_struct *m, - unsigned long *gpte_p, unsigned long *spte_p ) -{ - unsigned long gpte = *gpte_p; - unsigned long spte = *spte_p; - - switch( m->shadow_mode ) - { - case SHM_test: - spte = gpte; - gpte |= _PAGE_ACCESSED; - spte |= _PAGE_ACCESSED; - if ( ! (gpte & _PAGE_DIRTY ) ) - spte &= ~ _PAGE_RW; - break; - - case SHM_logdirty: - spte = gpte; - gpte |= _PAGE_ACCESSED; - spte |= _PAGE_ACCESSED; - spte &= ~ _PAGE_RW; - break; - } - - *gpte_p = gpte; - *spte_p = spte; -} - -static inline void l1pte_no_fault( struct mm_struct *m, - unsigned long *gpte_p, unsigned long *spte_p ) -{ - unsigned long gpte = *gpte_p; - unsigned long spte = *spte_p; - - switch( m->shadow_mode ) - { - case SHM_test: - spte = 0; - if ( (gpte & (_PAGE_PRESENT|_PAGE_ACCESSED) ) == - (_PAGE_PRESENT|_PAGE_ACCESSED) ) - { - spte = gpte; - if ( ! (gpte & _PAGE_DIRTY ) ) - spte &= ~ _PAGE_RW; - } - break; - - case SHM_logdirty: - spte = 0; - if ( (gpte & (_PAGE_PRESENT|_PAGE_ACCESSED) ) == - (_PAGE_PRESENT|_PAGE_ACCESSED) ) - { - spte = gpte; - spte &= ~ _PAGE_RW; - } - - break; - } - - *gpte_p = gpte; - *spte_p = spte; -} - -static inline void l2pde_general( struct mm_struct *m, - unsigned long *gpde_p, unsigned long *spde_p, - unsigned long sl1pfn) -{ - unsigned long gpde = *gpde_p; - unsigned long spde = *spde_p; - - spde = 0; - - if ( sl1pfn ) - { - spde = (gpde & ~PAGE_MASK) | (sl1pfn<shadow_ht[j]; - if(a->pfn){live++; ASSERT(a->spfn_and_flags&PSH_pfn_mask);} - ASSERT((a->pfn&0xf0000000)==0); - ASSERT(a->pfn<0x00100000); - a=a->next; - while(a && live<9999) - { - live++; - if(a->pfn == 0 || a->spfn_and_flags == 0) - { - printk("XXX live=%d pfn=%08lx sp=%08lx next=%p\n", - live, a->pfn, a->spfn_and_flags, a->next); - BUG(); - } - ASSERT(a->pfn); - ASSERT((a->pfn&0xf0000000)==0); - ASSERT(a->pfn<0x00100000); - ASSERT(a->spfn_and_flags&PSH_pfn_mask); - a=a->next; - } - ASSERT(live<9999); - } - - a = m->shadow_ht_free; - while(a) { free++; a=a->next; } - - if(print) printk("Xlive=%d free=%d\n",live,free); - - abs=(perfc_value(shadow_l1_pages)+perfc_value(shadow_l2_pages))-live; - if( abs < -1 || abs > 1 ) - { - printk("live=%d free=%d l1=%d l2=%d\n",live,free, - perfc_value(shadow_l1_pages), perfc_value(shadow_l2_pages) ); - BUG(); - } - -} - -#else -#define shadow_audit(p, print) -#endif - - - -static inline struct shadow_status* hash_bucket( struct mm_struct *m, - unsigned int gpfn ) -{ - return &(m->shadow_ht[gpfn % shadow_ht_buckets]); -} - - -static inline unsigned long __shadow_status( struct mm_struct *m, - unsigned int gpfn ) -{ - struct shadow_status **ob, *b, *B = hash_bucket( m, gpfn ); - - b = B; - ob = NULL; - - SH_VVLOG("lookup gpfn=%08x bucket=%p", gpfn, b ); - shadow_audit(m,0); // if in debug mode - - do - { - if ( b->pfn == gpfn ) - { - unsigned long t; - struct shadow_status *x; - - // swap with head - t=B->pfn; B->pfn=b->pfn; b->pfn=t; - t=B->spfn_and_flags; B->spfn_and_flags=b->spfn_and_flags; - b->spfn_and_flags=t; - - if( ob ) - { // pull to front - *ob=b->next; - x=B->next; - B->next=b; - b->next=x; - } - return B->spfn_and_flags; - } -#if SHADOW_HASH_DEBUG - else - { - if(b!=B)ASSERT(b->pfn); - } -#endif - ob=&b->next; - b=b->next; - } - while (b); - - return 0; -} - -/* we can make this locking more fine grained e.g. per shadow page if it -ever becomes a problem, but since we need a spin lock on the hash table -anyway its probably not worth being too clever. */ - -static inline unsigned long get_shadow_status( struct mm_struct *m, - unsigned int gpfn ) -{ - unsigned long res; - - /* If we get here, we know that this domain is running in shadow mode. - We also know that some sort of update has happened to the underlying - page table page: either a PTE has been updated, or the page has - changed type. If we're in log dirty mode, we should set the approrpiate - bit in the dirty bitmap. - NB: the VA update path doesn't use this so needs to be handled - independnetly. - */ - - ASSERT(local_irq_is_enabled()); - //if(spin_is_locked(&m->shadow_lock)) printk("*"); - spin_lock(&m->shadow_lock); - - if( m->shadow_mode == SHM_logdirty ) - __mark_dirty( m, gpfn ); - - res = __shadow_status( m, gpfn ); - if (!res) spin_unlock(&m->shadow_lock); - return res; -} - - -static inline void put_shadow_status( struct mm_struct *m ) -{ - spin_unlock(&m->shadow_lock); -} - - -static inline void delete_shadow_status( struct mm_struct *m, - unsigned int gpfn ) -{ - struct shadow_status *b, *B, **ob; - - ASSERT(spin_is_locked(&m->shadow_lock)); - - B = b = hash_bucket( m, gpfn ); - - SH_VVLOG("delete gpfn=%08x bucket=%p", gpfn, b ); - shadow_audit(m,0); - ASSERT(gpfn); - - if( b->pfn == gpfn ) - { - if (b->next) - { - struct shadow_status *D=b->next; - b->spfn_and_flags = b->next->spfn_and_flags; - b->pfn = b->next->pfn; - - b->next = b->next->next; - D->next = m->shadow_ht_free; - D->pfn = 0; - D->spfn_and_flags = 0; - m->shadow_ht_free = D; - } - else - { - b->pfn = 0; - b->spfn_and_flags = 0; - } - -#if SHADOW_HASH_DEBUG - if( __shadow_status(m,gpfn) ) BUG(); - shadow_audit(m,0); -#endif - return; - } - - ob = &b->next; - b=b->next; - - do - { - if ( b->pfn == gpfn ) - { - b->pfn = 0; - b->spfn_and_flags = 0; - - // b is in the list - *ob=b->next; - b->next = m->shadow_ht_free; - m->shadow_ht_free = b; - -#if SHADOW_HASH_DEBUG - if( __shadow_status(m,gpfn) ) BUG(); -#endif - shadow_audit(m,0); - return; - } - - ob = &b->next; - b=b->next; - } - while (b); - - // if we got here, it wasn't in the list - BUG(); -} - - -static inline void set_shadow_status( struct mm_struct *m, - unsigned int gpfn, unsigned long s ) -{ - struct shadow_status *b, *B, *extra, **fptr; - int i; - - ASSERT(spin_is_locked(&m->shadow_lock)); - - B = b = hash_bucket( m, gpfn ); - - ASSERT(gpfn); - SH_VVLOG("set gpfn=%08x s=%08lx bucket=%p(%p)", gpfn, s, b, b->next ); - - shadow_audit(m,0); - - do - { - if ( b->pfn == gpfn ) - { - b->spfn_and_flags = s; - shadow_audit(m,0); - return; - } - - b=b->next; - } - while (b); - - // if we got here, this is an insert rather than update - - ASSERT( s ); // deletes must have succeeded by here - - if ( B->pfn == 0 ) - { - // we can use this head - ASSERT( B->next == 0 ); - B->pfn = gpfn; - B->spfn_and_flags = s; - shadow_audit(m,0); - return; - } - - if( unlikely(m->shadow_ht_free == NULL) ) - { - SH_LOG("allocate more shadow hashtable blocks"); - - // we need to allocate more space - extra = kmalloc(sizeof(void*) + (shadow_ht_extra_size * - sizeof(struct shadow_status))); - - if( ! extra ) BUG(); // should be more graceful here.... - - memset(extra, 0, sizeof(void*) + (shadow_ht_extra_size * - sizeof(struct shadow_status))); - - m->shadow_extras_count++; - - // add extras to free list - fptr = &m->shadow_ht_free; - for ( i=0; ishadow_ht_extras; - m->shadow_ht_extras = extra; - - } - - // should really put this in B to go right to front - b = m->shadow_ht_free; - m->shadow_ht_free = b->next; - b->spfn_and_flags = s; - b->pfn = gpfn; - b->next = B->next; - B->next = b; - - shadow_audit(m,0); - - return; -} - -static inline void __shadow_mk_pagetable( struct mm_struct *mm ) -{ - unsigned long gpfn, spfn=0; - - gpfn = pagetable_val(mm->pagetable) >> PAGE_SHIFT; - - if ( unlikely((spfn=__shadow_status(mm, gpfn)) == 0 ) ) - { - spfn = shadow_l2_table(mm, gpfn ); - } - mm->shadow_table = mk_pagetable(spfn<pagetable), mm->shadow_mode ); - - if ( unlikely(mm->shadow_mode) ) - { - ASSERT(local_irq_is_enabled()); - spin_lock(&mm->shadow_lock); - - __shadow_mk_pagetable( mm ); - - spin_unlock(&mm->shadow_lock); - } - - SH_VVLOG("leaving shadow_mk_pagetable( gptbase=%08lx, mode=%d ) sh=%08lx", - pagetable_val(mm->pagetable), mm->shadow_mode, - pagetable_val(mm->shadow_table) ); - -} - - -#if SHADOW_DEBUG -extern int check_pagetable(struct mm_struct *m, pagetable_t pt, char *s); -#else -#define check_pagetable(m, pt, s) ((void)0) -#endif - - -#endif /* XEN_SHADOW_H */ - - +#include From 2a2726fd6294e16be2093438a7d9a15fb25f46b5 Mon Sep 17 00:00:00 2001 From: "djm@kirby.fc.hp.com" Date: Wed, 30 Jun 2004 23:08:19 +0000 Subject: [PATCH 04/36] bitkeeper revision 1.1041.2.4 (40e347e3mOn-qpOvThklRxuxrNeFVQ) More changes to encapsulate shadow mode Changes to move machdep dom0 ops to machdep file --- .rootkeys | 1 + xen/arch/x86/dom0_ops.c | 223 ++++++++++++++++++++++++++++++++++++++++ xen/common/debug.c | 2 +- xen/common/dom0_ops.c | 182 +------------------------------- xen/common/domain.c | 5 +- xen/common/kernel.c | 1 - 6 files changed, 229 insertions(+), 185 deletions(-) create mode 100644 xen/arch/x86/dom0_ops.c diff --git a/.rootkeys b/.rootkeys index 26357f0617..d0ce50f487 100644 --- a/.rootkeys +++ b/.rootkeys @@ -305,6 +305,7 @@ 3ddb79bcsjinG9k1KcvbVBuas1R2dA xen/arch/x86/apic.c 3ddb79bcSC_LvnmFlX-T5iTgaR0SKg xen/arch/x86/boot/boot.S 3ddb79bcUrk2EIaM5VsT6wUudH1kkg xen/arch/x86/delay.c +40e34414WiQO4h2m3tcpaCPn7SyYyg xen/arch/x86/dom0_ops.c 3e32af9aRnYGl4GMOaDKp7JdfhOGhg xen/arch/x86/domain_page.c 3ddb79bcecupHj56ZbTa3B0FxDowMg xen/arch/x86/entry.S 3ddb79bcY5zW7KhvI9gvfuPi3ZumEg xen/arch/x86/extable.c diff --git a/xen/arch/x86/dom0_ops.c b/xen/arch/x86/dom0_ops.c new file mode 100644 index 0000000000..1ec26d583d --- /dev/null +++ b/xen/arch/x86/dom0_ops.c @@ -0,0 +1,223 @@ +/****************************************************************************** + * Arch-specific dom0_ops.c + * + * Process command requests from domain-0 guest OS. + * + * Copyright (c) 2002, K A Fraser + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TRC_DOM0OP_ENTER_BASE 0x00020000 +#define TRC_DOM0OP_LEAVE_BASE 0x00030000 + +extern unsigned int alloc_new_dom_mem(struct domain *, unsigned int); + +static int msr_cpu_mask; +static unsigned long msr_addr; +static unsigned long msr_lo; +static unsigned long msr_hi; + +static void write_msr_for(void *unused) +{ + if (((1 << current->processor) & msr_cpu_mask)) + wrmsr(msr_addr, msr_lo, msr_hi); +} + +static void read_msr_for(void *unused) +{ + if (((1 << current->processor) & msr_cpu_mask)) + rdmsr(msr_addr, msr_lo, msr_hi); +} + +long arch_do_dom0_op(dom0_op_t *op, dom0_op_t *u_dom0_op) +{ + long ret = 0; + + if ( !IS_PRIV(current) ) + return -EPERM; + + switch ( op->cmd ) + { + + case DOM0_MSR: + { + if ( op->u.msr.write ) + { + msr_cpu_mask = op->u.msr.cpu_mask; + msr_addr = op->u.msr.msr; + msr_lo = op->u.msr.in1; + msr_hi = op->u.msr.in2; + smp_call_function(write_msr_for, NULL, 1, 1); + write_msr_for(NULL); + } + else + { + msr_cpu_mask = op->u.msr.cpu_mask; + msr_addr = op->u.msr.msr; + smp_call_function(read_msr_for, NULL, 1, 1); + read_msr_for(NULL); + + op->u.msr.out1 = msr_lo; + op->u.msr.out2 = msr_hi; + copy_to_user(u_dom0_op, op, sizeof(*op)); + } + ret = 0; + } + break; + + case DOM0_GETDOMAININFO: + { + full_execution_context_t *c; + struct domain *d; + unsigned long flags; + int i; + + read_lock_irqsave(&tasklist_lock, flags); + + for_each_domain ( d ) + { + if ( d->domain >= op->u.getdomaininfo.domain ) + break; + } + + if ( (d == NULL) || !get_domain(d) ) + { + read_unlock_irqrestore(&tasklist_lock, flags); + ret = -ESRCH; + break; + } + + read_unlock_irqrestore(&tasklist_lock, flags); + + op->u.getdomaininfo.domain = d->domain; + strcpy(op->u.getdomaininfo.name, d->name); + + op->u.getdomaininfo.flags = + (test_bit(DF_DYING, &d->flags) ? DOMFLAGS_DYING : 0) | + (test_bit(DF_CRASHED, &d->flags) ? DOMFLAGS_CRASHED : 0) | + (test_bit(DF_SHUTDOWN, &d->flags) ? DOMFLAGS_SHUTDOWN : 0) | + (test_bit(DF_CTRLPAUSE, &d->flags) ? DOMFLAGS_PAUSED : 0) | + (test_bit(DF_BLOCKED, &d->flags) ? DOMFLAGS_BLOCKED : 0) | + (test_bit(DF_RUNNING, &d->flags) ? DOMFLAGS_RUNNING : 0); + + op->u.getdomaininfo.flags |= d->processor << DOMFLAGS_CPUSHIFT; + op->u.getdomaininfo.flags |= + d->shutdown_code << DOMFLAGS_SHUTDOWNSHIFT; + + op->u.getdomaininfo.tot_pages = d->tot_pages; + op->u.getdomaininfo.max_pages = d->max_pages; + op->u.getdomaininfo.cpu_time = d->cpu_time; + op->u.getdomaininfo.shared_info_frame = + __pa(d->shared_info) >> PAGE_SHIFT; + + if ( op->u.getdomaininfo.ctxt != NULL ) + { + if ( (c = kmalloc(sizeof(*c))) == NULL ) + { + ret = -ENOMEM; + put_domain(d); + break; + } + + if ( d != current ) + domain_pause(d); + + c->flags = 0; + memcpy(&c->cpu_ctxt, + &d->shared_info->execution_context, + sizeof(d->shared_info->execution_context)); + if ( test_bit(DF_DONEFPUINIT, &d->flags) ) + c->flags |= ECF_I387_VALID; + memcpy(&c->fpu_ctxt, + &d->thread.i387, + sizeof(d->thread.i387)); + memcpy(&c->trap_ctxt, + d->thread.traps, + sizeof(d->thread.traps)); +#ifdef ARCH_HAS_FAST_TRAP + if ( (d->thread.fast_trap_desc.a == 0) && + (d->thread.fast_trap_desc.b == 0) ) + c->fast_trap_idx = 0; + else + c->fast_trap_idx = + d->thread.fast_trap_idx; +#endif + c->ldt_base = d->mm.ldt_base; + c->ldt_ents = d->mm.ldt_ents; + c->gdt_ents = 0; + if ( GET_GDT_ADDRESS(d) == GDT_VIRT_START ) + { + for ( i = 0; i < 16; i++ ) + c->gdt_frames[i] = + l1_pgentry_to_pagenr(d->mm.perdomain_pt[i]); + c->gdt_ents = + (GET_GDT_ENTRIES(d) + 1) >> 3; + } + c->guestos_ss = d->thread.guestos_ss; + c->guestos_esp = d->thread.guestos_sp; + c->pt_base = + pagetable_val(d->mm.pagetable); + memcpy(c->debugreg, + d->thread.debugreg, + sizeof(d->thread.debugreg)); + c->event_callback_cs = + d->event_selector; + c->event_callback_eip = + d->event_address; + c->failsafe_callback_cs = + d->failsafe_selector; + c->failsafe_callback_eip = + d->failsafe_address; + + if ( d != current ) + domain_unpause(d); + + if ( copy_to_user(op->u.getdomaininfo.ctxt, c, sizeof(*c)) ) + ret = -EINVAL; + + if ( c != NULL ) + kfree(c); + } + + if ( copy_to_user(u_dom0_op, op, sizeof(*op)) ) + ret = -EINVAL; + + put_domain(d); + } + break; + + case DOM0_SHADOW_CONTROL: + { + struct domain *d; + ret = -ESRCH; + d = find_domain_by_id(op->u.shadow_control.domain); + if ( d != NULL ) + { + ret = shadow_mode_control(d, &op->u.shadow_control); + put_domain(d); + copy_to_user(u_dom0_op, op, sizeof(*op)); + } + } + break; + + default: + ret = -ENOSYS; + + } + + return ret; +} diff --git a/xen/common/debug.c b/xen/common/debug.c index fd2d7d28c3..1cf4c57d37 100644 --- a/xen/common/debug.c +++ b/xen/common/debug.c @@ -69,7 +69,7 @@ void pdb_do_debug (dom0_op_t *op) struct domain *d; d = find_domain_by_id(op->u.debug.domain); - if ( d->mm.shadow_mode ) + if ( shadow_mode(d) ) cr3 = pagetable_val(d->mm.shadow_table); else cr3 = pagetable_val(d->mm.pagetable); diff --git a/xen/common/dom0_ops.c b/xen/common/dom0_ops.c index 96d7197b3e..28b2671e5f 100644 --- a/xen/common/dom0_ops.c +++ b/xen/common/dom0_ops.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include @@ -25,23 +24,7 @@ #define TRC_DOM0OP_LEAVE_BASE 0x00030000 extern unsigned int alloc_new_dom_mem(struct domain *, unsigned int); - -static int msr_cpu_mask; -static unsigned long msr_addr; -static unsigned long msr_lo; -static unsigned long msr_hi; - -static void write_msr_for(void *unused) -{ - if (((1 << current->processor) & msr_cpu_mask)) - wrmsr(msr_addr, msr_lo, msr_hi); -} - -static void read_msr_for(void *unused) -{ - if (((1 << current->processor) & msr_cpu_mask)) - rdmsr(msr_addr, msr_lo, msr_hi); -} +extern long arch_do_dom0_op(dom0_op_t *op, dom0_op_t *u_dom0_op); long do_dom0_op(dom0_op_t *u_dom0_op) { @@ -271,127 +254,6 @@ long do_dom0_op(dom0_op_t *u_dom0_op) } break; - case DOM0_GETDOMAININFO: - { - full_execution_context_t *c; - struct domain *d; - unsigned long flags; - int i; - - read_lock_irqsave(&tasklist_lock, flags); - - for_each_domain ( d ) - { - if ( d->domain >= op->u.getdomaininfo.domain ) - break; - } - - if ( (d == NULL) || !get_domain(d) ) - { - read_unlock_irqrestore(&tasklist_lock, flags); - ret = -ESRCH; - break; - } - - read_unlock_irqrestore(&tasklist_lock, flags); - - op->u.getdomaininfo.domain = d->domain; - strcpy(op->u.getdomaininfo.name, d->name); - - op->u.getdomaininfo.flags = - (test_bit(DF_DYING, &d->flags) ? DOMFLAGS_DYING : 0) | - (test_bit(DF_CRASHED, &d->flags) ? DOMFLAGS_CRASHED : 0) | - (test_bit(DF_SHUTDOWN, &d->flags) ? DOMFLAGS_SHUTDOWN : 0) | - (test_bit(DF_CTRLPAUSE, &d->flags) ? DOMFLAGS_PAUSED : 0) | - (test_bit(DF_BLOCKED, &d->flags) ? DOMFLAGS_BLOCKED : 0) | - (test_bit(DF_RUNNING, &d->flags) ? DOMFLAGS_RUNNING : 0); - - op->u.getdomaininfo.flags |= d->processor << DOMFLAGS_CPUSHIFT; - op->u.getdomaininfo.flags |= - d->shutdown_code << DOMFLAGS_SHUTDOWNSHIFT; - - op->u.getdomaininfo.tot_pages = d->tot_pages; - op->u.getdomaininfo.max_pages = d->max_pages; - op->u.getdomaininfo.cpu_time = d->cpu_time; - op->u.getdomaininfo.shared_info_frame = - __pa(d->shared_info) >> PAGE_SHIFT; - - if ( op->u.getdomaininfo.ctxt != NULL ) - { - if ( (c = kmalloc(sizeof(*c))) == NULL ) - { - ret = -ENOMEM; - put_domain(d); - break; - } - - if ( d != current ) - domain_pause(d); - - c->flags = 0; - memcpy(&c->cpu_ctxt, - &d->shared_info->execution_context, - sizeof(d->shared_info->execution_context)); - if ( test_bit(DF_DONEFPUINIT, &d->flags) ) - c->flags |= ECF_I387_VALID; - memcpy(&c->fpu_ctxt, - &d->thread.i387, - sizeof(d->thread.i387)); - memcpy(&c->trap_ctxt, - d->thread.traps, - sizeof(d->thread.traps)); -#ifdef ARCH_HAS_FAST_TRAP - if ( (d->thread.fast_trap_desc.a == 0) && - (d->thread.fast_trap_desc.b == 0) ) - c->fast_trap_idx = 0; - else - c->fast_trap_idx = - d->thread.fast_trap_idx; -#endif - c->ldt_base = d->mm.ldt_base; - c->ldt_ents = d->mm.ldt_ents; - c->gdt_ents = 0; - if ( GET_GDT_ADDRESS(d) == GDT_VIRT_START ) - { - for ( i = 0; i < 16; i++ ) - c->gdt_frames[i] = - l1_pgentry_to_pagenr(d->mm.perdomain_pt[i]); - c->gdt_ents = - (GET_GDT_ENTRIES(d) + 1) >> 3; - } - c->guestos_ss = d->thread.guestos_ss; - c->guestos_esp = d->thread.guestos_sp; - c->pt_base = - pagetable_val(d->mm.pagetable); - memcpy(c->debugreg, - d->thread.debugreg, - sizeof(d->thread.debugreg)); - c->event_callback_cs = - d->event_selector; - c->event_callback_eip = - d->event_address; - c->failsafe_callback_cs = - d->failsafe_selector; - c->failsafe_callback_eip = - d->failsafe_address; - - if ( d != current ) - domain_unpause(d); - - if ( copy_to_user(op->u.getdomaininfo.ctxt, c, sizeof(*c)) ) - ret = -EINVAL; - - if ( c != NULL ) - kfree(c); - } - - if ( copy_to_user(u_dom0_op, op, sizeof(*op)) ) - ret = -EINVAL; - - put_domain(d); - } - break; - case DOM0_GETPAGEFRAMEINFO: { struct pfn_info *page; @@ -448,32 +310,6 @@ long do_dom0_op(dom0_op_t *u_dom0_op) } break; - case DOM0_MSR: - { - if ( op->u.msr.write ) - { - msr_cpu_mask = op->u.msr.cpu_mask; - msr_addr = op->u.msr.msr; - msr_lo = op->u.msr.in1; - msr_hi = op->u.msr.in2; - smp_call_function(write_msr_for, NULL, 1, 1); - write_msr_for(NULL); - } - else - { - msr_cpu_mask = op->u.msr.cpu_mask; - msr_addr = op->u.msr.msr; - smp_call_function(read_msr_for, NULL, 1, 1); - read_msr_for(NULL); - - op->u.msr.out1 = msr_lo; - op->u.msr.out2 = msr_hi; - copy_to_user(u_dom0_op, op, sizeof(*op)); - } - ret = 0; - } - break; - #ifdef XEN_DEBUGGER case DOM0_DEBUG: { @@ -543,20 +379,6 @@ long do_dom0_op(dom0_op_t *u_dom0_op) } break; - case DOM0_SHADOW_CONTROL: - { - struct domain *d; - ret = -ESRCH; - d = find_domain_by_id(op->u.shadow_control.domain); - if ( d != NULL ) - { - ret = shadow_mode_control(d, &op->u.shadow_control); - put_domain(d); - copy_to_user(u_dom0_op, op, sizeof(*op)); - } - } - break; - case DOM0_SCHED_ID: { op->u.sched_id.sched_id = sched_id(); @@ -696,7 +518,7 @@ long do_dom0_op(dom0_op_t *u_dom0_op) break; default: - ret = -ENOSYS; + ret = arch_do_dom0_op(op,u_dom0_op); } diff --git a/xen/common/domain.c b/xen/common/domain.c index 5375a5de18..58ed42b25f 100644 --- a/xen/common/domain.c +++ b/xen/common/domain.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include @@ -57,7 +56,7 @@ struct domain *do_createdomain(domid_t dom_id, unsigned int cpu) atomic_set(&d->refcnt, 1); atomic_set(&d->pausecnt, 0); - spin_lock_init(&d->mm.shadow_lock); + shadow_lock_init(d); d->domain = dom_id; d->processor = cpu; @@ -335,7 +334,7 @@ void domain_relinquish_memory(struct domain *d) write_ptbase(¤t->mm); /* Exit shadow mode before deconstructing final guest page table. */ - if ( d->mm.shadow_mode ) + if ( shadow_mode(d) ) shadow_mode_disable(d); /* Drop the in-use reference to the page-table base. */ diff --git a/xen/common/kernel.c b/xen/common/kernel.c index 92602e0bf5..23b0fb348d 100644 --- a/xen/common/kernel.c +++ b/xen/common/kernel.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include From 798ce800b1fede6de291fa96f76ae6c2b42b8205 Mon Sep 17 00:00:00 2001 From: "mjw@wray-m-3.hpl.hp.com" Date: Thu, 1 Jul 2004 07:41:45 +0000 Subject: [PATCH 05/36] bitkeeper revision 1.1041.1.4 (40e3c039GLJ7sRSdIoNOD2_oAJinLQ) Small fixes. --- tools/python/xen/xend/server/SrvDaemon.py | 56 ++++++++++++++++++----- tools/python/xen/xend/server/channel.py | 8 +++- 2 files changed, 51 insertions(+), 13 deletions(-) diff --git a/tools/python/xen/xend/server/SrvDaemon.py b/tools/python/xen/xend/server/SrvDaemon.py index 31ace1b84e..9050166bf4 100644 --- a/tools/python/xen/xend/server/SrvDaemon.py +++ b/tools/python/xen/xend/server/SrvDaemon.py @@ -14,6 +14,7 @@ import socket import pwd import re import StringIO +import traceback from twisted.internet import pollreactor pollreactor.install() @@ -396,6 +397,12 @@ class EventProtocol(protocol.Protocol): eserver.inject(sxp.name(event), event) return ['ok'] + def op_traceon(self, name, v): + self.daemon.tracing(1) + + def op_traceoff(self, name, v): + self.daemon.tracing(0) + class EventFactory(protocol.Factory): """Asynchronous handler for the event server socket. @@ -428,6 +435,7 @@ class Daemon: """ def __init__(self): self.shutdown = 0 + self.traceon = 0 def daemon_pids(self): pids = [] @@ -486,7 +494,7 @@ class Daemon: while code > 0: code = os.waitpid(-1, os.WNOHANG) - def start(self,trace=0): + def start(self, trace=0): if self.cleanup(kill=False): return 1 @@ -510,7 +518,21 @@ class Daemon: # Child logfile = self.open_logfile() self.redirect_output(logfile) - if trace: + + self.tracing(trace) + + self.run() + return 0 + + def tracing(self, traceon): + """Turn tracing on or off. + + traceon tracing flag + """ + if traceon == self.traceon: + return + self.traceon = traceon + if traceon: self.tracefile = open('/var/log/xend.trace', 'w+', 1) self.traceindent = 0 sys.settrace(self.trace) @@ -518,26 +540,35 @@ class Daemon: threading.settrace(self.trace) # Only in Python >= 2.3 except: pass - self.run() - return 0 - def print_trace(self,str): + def print_trace(self, str): for i in range(self.traceindent): - self.tracefile.write(" ") + ch = " " + if (i % 5): + ch = ' ' + else: + ch = '|' + self.tracefile.write(ch) self.tracefile.write(str) def trace(self, frame, event, arg): + if not self.traceon: + print >>self.tracefile + print >>self.tracefile, '-' * 20, 'TRACE OFF', '-' * 20 + self.tracefile.close() + self.tracefile = None + return None if event == 'call': code = frame.f_code filename = code.co_filename - m = re.search('.*xenmgr/(.*)', code.co_filename) + m = re.search('.*xend/(.*)', filename) if not m: return None modulename = m.group(1) if re.search('sxp.py', modulename): return None self.traceindent += 1 - self.print_trace("++++ %s:%s\n" + self.print_trace("> %s:%s\n" % (modulename, code.co_name)) elif event == 'line': filename = frame.f_code.co_filename @@ -547,15 +578,18 @@ class Daemon: elif event == 'return': code = frame.f_code filename = code.co_filename - m = re.search('.*xenmgr/(.*)', code.co_filename) + m = re.search('.*xend/(.*)', filename) if not m: return None modulename = m.group(1) - self.print_trace("---- %s:%s\n" + self.print_trace("< %s:%s\n" % (modulename, code.co_name)) self.traceindent -= 1 elif event == 'exception': - pass + self.print_trace("! Exception:\n") + (ex, val, tb) = arg + traceback.print_exception(ex, val, tb, 10, self.tracefile) + #del tb return self.trace def open_logfile(self): diff --git a/tools/python/xen/xend/server/channel.py b/tools/python/xen/xend/server/channel.py index d68f84fa37..3382890034 100755 --- a/tools/python/xen/xend/server/channel.py +++ b/tools/python/xen/xend/server/channel.py @@ -216,11 +216,13 @@ class Channel(BaseChannel): def getLocalPort(self): """Get the local port. """ + if self.closed: return -1 return self.port.local_port def getRemotePort(self): """Get the remote port. """ + if self.closed: return -1 return self.port.remote_port def close(self): @@ -233,6 +235,7 @@ class Channel(BaseChannel): self.factory.channelClosed(self) self.devs = [] self.devs_by_type = {} + del self.port def registerDevice(self, types, dev): """Register a device controller. @@ -273,8 +276,8 @@ class Channel(BaseChannel): def __repr__(self): return ('' % (self.dom, - self.port.local_port, - self.port.remote_port)) + self.getLocalPort(), + self.getRemotePort())) def handleNotification(self, type): work = 0 @@ -285,6 +288,7 @@ class Channel(BaseChannel): self.notify() def notify(self): + if self.closed: return self.port.notify() def handleRequests(self): From 50b66608c9eaa88f4daafc7e3b03726ed31f2ef6 Mon Sep 17 00:00:00 2001 From: "mjw@wray-m-3.hpl.hp.com" Date: Thu, 1 Jul 2004 10:20:24 +0000 Subject: [PATCH 06/36] bitkeeper revision 1.1041.1.6 (40e3e568dXMUca5bKVlAd9SLsmVpEw) Release the channel and port when a domain is destroyed. Allows the domain to finally go away. --- tools/python/xen/xend/XendDomainInfo.py | 3 ++ tools/python/xen/xend/server/SrvDaemon.py | 9 +++++ tools/python/xen/xend/server/channel.py | 41 +++++++++++++++++------ 3 files changed, 42 insertions(+), 11 deletions(-) diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index e3e4e92cbd..c0de8fed01 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -504,6 +504,9 @@ class XendDomainInfo: devices have been released. """ if self.dom is None: return 0 + chan = xend.getDomChannel(self.dom) + if chan: + chan.close() return xc.domain_destroy(dom=self.dom) def cleanup(self): diff --git a/tools/python/xen/xend/server/SrvDaemon.py b/tools/python/xen/xend/server/SrvDaemon.py index 7dde51f68f..63c4dd1bee 100644 --- a/tools/python/xen/xend/server/SrvDaemon.py +++ b/tools/python/xen/xend/server/SrvDaemon.py @@ -663,6 +663,15 @@ class Daemon: reactor.diconnectAll() sys.exit(0) + def getDomChannel(self, dom): + """Get the channel to a domain. + + dom domain + + returns channel (or None) + """ + return self.channelF.getDomChannel(dom) + def blkif_set_control_domain(self, dom, recreate=0): """Set the block device backend control domain. """ diff --git a/tools/python/xen/xend/server/channel.py b/tools/python/xen/xend/server/channel.py index ecd9cf93f3..da19d621c2 100755 --- a/tools/python/xen/xend/server/channel.py +++ b/tools/python/xen/xend/server/channel.py @@ -48,15 +48,31 @@ class ChannelFactory: def domChannel(self, dom): """Get the channel for the given domain. Construct if necessary. + + dom domain + + returns channel + """ + chan = self.getDomChannel(dom) + if not chan: + chan = Channel(self, dom) + self.addChannel(chan) + return chan + + def getDomChannel(self, dom): + """Get the channel for the given domain. + + dom domain + + returns channel (or None) """ dom = int(dom) for chan in self.channels.values(): if not isinstance(chan, Channel): continue if chan.dom == dom: return chan - chan = Channel(self, dom) - self.addChannel(chan) - return chan + return None + def virqChannel(self, virq): """Get the channel for the given virq. @@ -109,12 +125,11 @@ class BaseChannel: def notificationReceived(self): """Called when a notification is received. - Closes the channel on error, otherwise calls - handleNotification(type), which should be defined + Calls handleNotification(), which should be defined in a subclass. """ - if not self.closed: - self.handleNotification(type) + if self.closed: return + self.handleNotification() def close(self): """Close the channel. Calls channelClosed() on the factory. @@ -122,7 +137,7 @@ class BaseChannel: """ self.factory.channelClosed(self) - def handleNotification(self, type): + def handleNotification(self): """Handle notification. Define in subclass. """ @@ -172,7 +187,7 @@ class VirqChannel(BaseChannel): """ self.clients.append(client) - def handleNotification(self, type): + def handleNotification(self): for c in self.clients: c.virqReceived(self.virq) @@ -221,13 +236,14 @@ class Channel(BaseChannel): """Close the channel. Calls lostChannel() on all its devices and channelClosed() on the factory. """ + if self.closed: return self.closed = 1 for d in self.devs: d.lostChannel() self.factory.channelClosed(self) self.devs = [] self.devs_by_type = {} - del self.port + self.port.disconnect() def registerDevice(self, types, dev): """Register a device controller. @@ -271,7 +287,10 @@ class Channel(BaseChannel): self.getLocalPort(), self.getRemotePort())) - def handleNotification(self, type): + def handleNotification(self): + if self.closed: + print 'handleNotification> Notification on closed channel', self + return work = 0 work += self.handleRequests() work += self.handleResponses() From 293728f07f101743c4cb30ebe6c0fd7b1eb7ae25 Mon Sep 17 00:00:00 2001 From: "kaf24@scramble.cl.cam.ac.uk" Date: Thu, 1 Jul 2004 11:04:02 +0000 Subject: [PATCH 07/36] bitkeeper revision 1.1041.1.7 (40e3efa2LdNbC7qtT4aE-QoVd4n6yw) Remove redundant files. --- .rootkeys | 2 -- tools/libxutil/debug.h | 72 -------------------------------------- tools/libxutil/sys_ctype.h | 12 ------- 3 files changed, 86 deletions(-) delete mode 100644 tools/libxutil/debug.h delete mode 100644 tools/libxutil/sys_ctype.h diff --git a/.rootkeys b/.rootkeys index 40c0fe962f..92c6f42e9e 100644 --- a/.rootkeys +++ b/.rootkeys @@ -181,7 +181,6 @@ 40e1b09dMYB4ItGCqcMIzirdMd9I-w tools/libxutil/Makefile 40e033325Sjqs-_4TuzeUEprP_gYFg tools/libxutil/allocate.c 40e03332KYz7o1bn2MG_KPbBlyoIMA tools/libxutil/allocate.h -40e03332IyRttYoXKoJla5qCC514SQ tools/libxutil/debug.h 40e03332p5Dc_owJQRuN72ymJZddFQ tools/libxutil/file_stream.c 40e03332jWfB2viAhLSkq1WK0r_iDQ tools/libxutil/file_stream.h 40e03332rUjNMGg11n2rN6V4DCrvOg tools/libxutil/gzip_stream.c @@ -192,7 +191,6 @@ 40e03332aK0GkgpDdc-PVTkWKTeOBg tools/libxutil/kernel_stream.h 40e03332KT_tnnoAMbPVAZBB7kSOAQ tools/libxutil/string_stream.c 40e03332-VtK6_OZa1vMHXFil8uq6w tools/libxutil/string_stream.h -40e03332gKUInsqtxQOV4mPiMqf_dg tools/libxutil/sys_ctype.h 40e03332Rkvq6nn_UNjzAAK_Tk9v1g tools/libxutil/sys_net.c 40e03332lQHvQHw4Rh7VsT1_sui29A tools/libxutil/sys_net.h 40e033321smklZd7bDSdWvQCeIshtg tools/libxutil/sys_string.c diff --git a/tools/libxutil/debug.h b/tools/libxutil/debug.h deleted file mode 100644 index 4f5228faa3..0000000000 --- a/tools/libxutil/debug.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2004 Mike Wray - * - * 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.1 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 - */ -#ifndef _XEN_LIB_DEBUG_H_ -#define _XEN_LIB_DEBUG_H_ - -#ifndef MODULE_NAME -#define MODULE_NAME "" -#endif - -#ifdef __KERNEL__ -#include -#include - -#ifdef DEBUG - -#define dprintf(fmt, args...) printk(KERN_DEBUG "[DBG] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args) -#define wprintf(fmt, args...) printk(KERN_WARNING "[WRN] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args) -#define iprintf(fmt, args...) printk(KERN_INFO "[INF] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args) -#define eprintf(fmt, args...) printk(KERN_ERR "[ERR] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args) - -#else - -#define dprintf(fmt, args...) do {} while(0) -#define wprintf(fmt, args...) printk(KERN_WARNING "[WRN] " MODULE_NAME fmt, ##args) -#define iprintf(fmt, args...) printk(KERN_INFO "[INF] " MODULE_NAME fmt, ##args) -#define eprintf(fmt, args...) printk(KERN_ERR "[ERR] " MODULE_NAME fmt, ##args) - -#endif - -#else - -#include - -#ifdef DEBUG - -#define dprintf(fmt, args...) fprintf(stdout, "[DBG] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args) -#define wprintf(fmt, args...) fprintf(stderr, "[WRN] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args) -#define iprintf(fmt, args...) fprintf(stderr, "[INF] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args) -#define eprintf(fmt, args...) fprintf(stderr, "[ERR] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args) - -#else - -#define dprintf(fmt, args...) do {} while(0) -#define wprintf(fmt, args...) fprintf(stderr, "[WRN] " MODULE_NAME fmt, ##args) -#define iprintf(fmt, args...) fprintf(stderr, "[INF] " MODULE_NAME fmt, ##args) -#define eprintf(fmt, args...) fprintf(stderr, "[ERR] " MODULE_NAME fmt, ##args) - -#endif - -#endif - -/** Print format for an IP address. - * See NIPQUAD(), HIPQUAD() - */ -#define IPFMT "%u.%u.%u.%u" - -#endif /* ! _XEN_LIB_DEBUG_H_ */ diff --git a/tools/libxutil/sys_ctype.h b/tools/libxutil/sys_ctype.h deleted file mode 100644 index 1dc6cf2fac..0000000000 --- a/tools/libxutil/sys_ctype.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef _XENO_SYS_CTYPE_H_ -#define _XENO_SYS_CTYPE_H_ -/** @file - ** Replacement for ctype include that can be used - * from user or kernel code. - */ -#ifdef __KERNEL__ -# include -#else -# include -#endif -#endif /* ! _XENO_SYS_CTYPE_H_ */ From 76e8d2ff6ad9e25ef46356efe22dc0a53446747c Mon Sep 17 00:00:00 2001 From: "mjw@wray-m-3.hpl.hp.com" Date: Thu, 1 Jul 2004 12:06:02 +0000 Subject: [PATCH 08/36] bitkeeper revision 1.1041.3.1 (40e3fe2a5JO0HpkIeSaP8q6IITbNAQ) Documentation and a couple of tidies. --- tools/python/xen/xend/server/SrvDomainDir.py | 20 +++- tools/python/xen/xend/server/blkif.py | 59 +++++++--- tools/python/xen/xend/server/channel.py | 12 +- tools/python/xen/xend/server/console.py | 24 +--- tools/python/xen/xend/server/controller.py | 87 +++++++++++++-- tools/python/xen/xend/server/domain.py | 21 ++++ tools/python/xen/xend/server/messages.py | 27 +++++ tools/python/xen/xend/server/netif.py | 111 ++++++++++++------- 8 files changed, 265 insertions(+), 96 deletions(-) diff --git a/tools/python/xen/xend/server/SrvDomainDir.py b/tools/python/xen/xend/server/SrvDomainDir.py index af4bc7a15c..03c869051e 100644 --- a/tools/python/xen/xend/server/SrvDomainDir.py +++ b/tools/python/xen/xend/server/SrvDomainDir.py @@ -1,5 +1,6 @@ # Copyright (C) 2004 Mike Wray +import traceback from StringIO import StringIO from twisted.protocols import http @@ -24,6 +25,7 @@ class SrvDomainDir(SrvDir): val = None try: dom = self.xd.domain_get(x) + if not dom: raise KeyError('No such domain') val = SrvDomain(dom) except KeyError, ex: print 'SrvDomainDir>', ex @@ -38,6 +40,9 @@ class SrvDomainDir(SrvDir): return v def op_create(self, op, req): + """Create a domain. + Expects the domain config in request parameter 'config' in SXP format. + """ ok = 0 try: configstring = req.args.get('config')[0] @@ -48,7 +53,8 @@ class SrvDomainDir(SrvDir): config = pin.get_val() ok = 1 except Exception, ex: - print 'op_create>', ex + print 'op_create> Exception in config', ex + traceback.print_exc() if not ok: req.setResponseCode(http.BAD_REQUEST, "Invalid configuration") return "Invalid configuration" @@ -60,10 +66,10 @@ class SrvDomainDir(SrvDir): deferred.addCallback(self._cb_op_create, configstring, req) return deferred except Exception, ex: - raise - #return ['err', str(ex) ] - #req.setResponseCode(http.BAD_REQUEST, "Error creating domain") - #return str(ex) + print 'op_create> Exception creating domain:' + traceback.print_exc() + req.setResponseCode(http.BAD_REQUEST, "Error creating domain") + return str(ex) #return error.ErrorPage(http.BAD_REQUEST, # "Error creating domain", # str(ex)) @@ -90,6 +96,8 @@ class SrvDomainDir(SrvDir): return val def op_restore(self, op, req): + """Restore a domain from file. + """ fn = FormFn(self.xd.domain_restore, [['file', 'str']]) val = fn(req.args) @@ -131,6 +139,8 @@ class SrvDomainDir(SrvDir): req.write('') def form(self, req): + """Generate the form(s) for domain dir operations. + """ req.write('
' % req.prePathURL()) req.write('') diff --git a/tools/python/xen/xend/server/blkif.py b/tools/python/xen/xend/server/blkif.py index 4e2a49f7d8..7310494377 100755 --- a/tools/python/xen/xend/server/blkif.py +++ b/tools/python/xen/xend/server/blkif.py @@ -1,3 +1,5 @@ +# Copyright (C) 2004 Mike Wray + from twisted.internet import defer from xen.xend import sxp @@ -28,6 +30,11 @@ class BlkifControllerFactory(controller.ControllerFactory): self.registerChannel() def createInstance(self, dom, recreate=0): + """Create a block device controller for a domain. + + dom domain + recreate if true it's a recreate (after xend restart) + """ d = self.addDeferred() blkif = self.getInstanceByDom(dom) if blkif: @@ -42,29 +49,50 @@ class BlkifControllerFactory(controller.ControllerFactory): return d def getDomainDevices(self, dom): + """Get the block devices for a domain. + + dom domain + + returns devices + """ blkif = self.getInstanceByDom(dom) return (blkif and blkif.getDevices()) or [] def getDomainDevice(self, dom, vdev): + """Get a block device from a domain. + + dom domain + vdev device index + + returns device + """ blkif = self.getInstanceByDom(dom) return (blkif and blkif.getDevice(vdev)) or None def setControlDomain(self, dom, recreate=0): + """Set the back-end block device controller domain. + + dom domain + recreate if true it's a recreate (after xend restart) + """ if self.dom == dom: return self.deregisterChannel() if not recreate: self.attached = 0 self.dom = dom self.registerChannel() - # - #if xend.blkif.be_port: - # xend.blkif.recovery = True - #xend.blkif.be_port = xend.main.port_from_dom(dom) def getControlDomain(self): + """Get the back-end block device controller domain. + """ return self.dom def reattachDevice(self, dom, vdev): + """Reattach a device (on changing control domain). + + dom domain + vdev device index + """ blkif = self.getInstanceByDom(dom) if blkif: blkif.reattachDevice(vdev) @@ -83,6 +111,9 @@ class BlkifControllerFactory(controller.ControllerFactory): return attached def reattached(self): + """Notify all block interface we have been reattached + (after changing control domain). + """ for blkif in self.getInstances(): blkif.reattached() @@ -147,7 +178,6 @@ class BlkDev(controller.Dev): return val def destroy(self): - print 'BlkDev>destroy>', self.vdev PrettyPrint.prettyprint(self.sxpr()) self.controller.send_be_vbd_destroy(self.vdev) @@ -157,7 +187,6 @@ class BlkifController(controller.Controller): """ def __init__(self, factory, dom): - #print 'BlkifController> dom=', dom controller.Controller.__init__(self, factory, dom) self.devices = {} @@ -172,7 +201,6 @@ class BlkifController(controller.Controller): self.attached = 1 self.evtchn = None self.registerChannel() - #print 'BlkifController<', 'dom=', self.dom, 'idx=', self.idx def sxpr(self): val = ['blkif', ['dom', self.dom]] @@ -183,8 +211,6 @@ class BlkifController(controller.Controller): return val def lostChannel(self): - print 'BlkifController>lostChannel>', 'dom=', self.dom - #self.destroyDevices() controller.Controller.lostChannel(self) def getDevices(self): @@ -201,8 +227,14 @@ class BlkifController(controller.Controller): def attachDevice(self, vdev, mode, segment, recreate=0): """Attach a device to the specified interface. + + vdev device index + mode read/write mode + segment segment + recreate if true it's being recreated (after xend restart) + + returns deferred """ - #print 'BlkifController>attach_device>', self.dom, vdev, mode, segment dev = self.addDevice(vdev, mode, segment) if not dev: return -1 if recreate: @@ -214,13 +246,11 @@ class BlkifController(controller.Controller): return d def destroy(self): - print 'BlkifController>destroy> dom=', self.dom def cb_destroy(val): self.send_be_destroy() d = self.factory.addDeferred() d.addCallback(cb_destroy) self.send_be_disconnect() - #self.destroyDevices() def destroyDevices(self): for dev in self.getDevices(): @@ -276,11 +306,6 @@ class BlkifController(controller.Controller): self.factory.writeRequest(msg) pass - #def recv_fe_interface_status_changed(self, msg, req): - # (hnd, status, chan) = unpackMsg('blkif_fe_interface_status_changed_t', msg) - # print 'recv_fe_interface_status_changed>', hnd, status, chan - # pass - def send_fe_interface_status_changed(self): msg = packMsg('blkif_fe_interface_status_changed_t', { 'handle' : 0, diff --git a/tools/python/xen/xend/server/channel.py b/tools/python/xen/xend/server/channel.py index da19d621c2..0c9d316dec 100755 --- a/tools/python/xen/xend/server/channel.py +++ b/tools/python/xen/xend/server/channel.py @@ -1,3 +1,5 @@ +# Copyright (C) 2004 Mike Wray + import xen.lowlevel.xc; xc = xen.lowlevel.xc.new() from xen.lowlevel import xu from messages import msgTypeName @@ -24,14 +26,11 @@ class ChannelFactory: self.notifier = xu.notifier() def addChannel(self, channel): - """Add a channel. + """Add a channel. Registers with the notifier. """ idx = channel.idx self.channels[idx] = channel self.notifier.bind(idx) - # Try to wake it up - #self.notifier.unmask(idx) - #channel.notify() def getChannel(self, idx): """Get the channel with the given index (if any). @@ -40,6 +39,7 @@ class ChannelFactory: def delChannel(self, idx): """Remove the channel with the given index (if any). + Deregisters with the notifier. """ if idx in self.channels: del self.channels[idx] @@ -288,6 +288,8 @@ class Channel(BaseChannel): self.getRemotePort())) def handleNotification(self): + """Process outstanding messages in repsonse to notification on the port. + """ if self.closed: print 'handleNotification> Notification on closed channel', self return @@ -299,6 +301,8 @@ class Channel(BaseChannel): self.notify() def notify(self): + """Notify the other end of the port that messages have been processed. + """ if self.closed: return self.port.notify() diff --git a/tools/python/xen/xend/server/console.py b/tools/python/xen/xend/server/console.py index 3227dc1b5e..336ccacca0 100755 --- a/tools/python/xen/xend/server/console.py +++ b/tools/python/xen/xend/server/console.py @@ -1,3 +1,4 @@ +# Copyright (C) 2004 Mike Wray from twisted.internet import reactor from twisted.internet import protocol @@ -12,11 +13,6 @@ import controller from messages import * from params import * -"""Telnet binary option.""" -TRANSMIT_BINARY = '0' -WILL = chr(251) -IAC = chr(255) - class ConsoleProtocol(protocol.Protocol): """Asynchronous handler for a console TCP socket. """ @@ -36,19 +32,12 @@ class ConsoleProtocol(protocol.Protocol): self.loseConnection() return else: - # KAF: A nice quiet successful connect. Don't bother with telnet - # control sequence -- telnet is not the appropriate protocol here. + # KAF: A nice quiet successful connect. #self.transport.write("Connected to console %d on domain %d\n" # % (self.idx, self.controller.dom)) - #self.setTelnetTransmitBinary() eserver.inject('xend.console.connect', [self.idx, self.addr[0], self.addr[1]]) - def setTelnetTransmitBinary(self): - """Send the sequence to set the telnet TRANSMIT-BINARY option. - """ - self.write(IAC + WILL + TRANSMIT_BINARY) - def dataReceived(self, data): if self.controller.handleInput(self, data): self.loseConnection() @@ -105,7 +94,6 @@ class ConsoleController(controller.Controller): """ def __init__(self, factory, dom, console_port): - #print 'ConsoleController> dom=', dom, type(dom) controller.Controller.__init__(self, factory, dom) self.majorTypes = [ CMSG_CONSOLE ] self.status = "new" @@ -118,7 +106,6 @@ class ConsoleController(controller.Controller): self.registerChannel() self.listener = None self.listen() - #print 'ConsoleController<', 'dom=', self.dom, 'idx=', self.idx def sxpr(self): val =['console', @@ -143,7 +130,6 @@ class ConsoleController(controller.Controller): def close(self): try: - #print 'ConsoleController> close dom=', self.dom self.status = "closed" if self.conn: self.conn.loseConnection() @@ -183,11 +169,11 @@ class ConsoleController(controller.Controller): self.listen() def requestReceived(self, msg, type, subtype): - #print '***Console', self.dom, msg.get_payload() self.rbuf.write(msg.get_payload()) self.handleOutput() def responseReceived(self, msg, type, subtype): + # Just ignore responses. pass def produceRequests(self): @@ -215,18 +201,14 @@ class ConsoleController(controller.Controller): Sends it to the connected console (if any). """ if self.closed(): - #print 'Console>handleOutput> closed' return -1 if not self.conn: - #print 'Console>handleOutput> not connected' return 0 while not self.rbuf.empty(): try: - #print 'Console>handleOutput> writing...' bytes = self.conn.write(self.rbuf.peek()) if bytes > 0: self.rbuf.discard(bytes) except socket.error, error: pass - #print 'Console>handleOutput<' return 0 diff --git a/tools/python/xen/xend/server/controller.py b/tools/python/xen/xend/server/controller.py index 900c2d55b0..299bd621f6 100755 --- a/tools/python/xen/xend/server/controller.py +++ b/tools/python/xen/xend/server/controller.py @@ -1,3 +1,5 @@ +# Copyright (C) 2004 Mike Wray + from twisted.internet import defer import channel @@ -5,6 +7,15 @@ from messages import msgTypeName class CtrlMsgRcvr: """Abstract class for things that deal with a control interface to a domain. + + Instance variables: + + dom : the domain we are a control interface for + majorTypes: list of major message types we are interested in + subTypes : mapping of message subtypes to methods + + channel : channel to the domain + idx : channel index """ @@ -17,6 +28,12 @@ class CtrlMsgRcvr: self.idx = None def requestReceived(self, msg, type, subtype): + """Dispatch a request to handlers. + + msg message + type major message type + subtype minor message type + """ method = self.subTypes.get(subtype) if method: method(msg, 1) @@ -25,6 +42,12 @@ class CtrlMsgRcvr: % (msgTypeName(type, subtype), type, subtype)), self def responseReceived(self, msg, type, subtype): + """Dispatch a response to handlers. + + msg message + type major message type + subtype minor message type + """ method = self.subTypes.get(subtype) if method: method(msg, 0) @@ -33,9 +56,14 @@ class CtrlMsgRcvr: % (msgTypeName(type, subtype), type, subtype)), self def lostChannel(self): + """Called when the channel to the domain is lost. + """ pass def registerChannel(self): + """Register interest in our major message types with the + channel to our domain. + """ #print 'CtrlMsgRcvr>registerChannel>', self self.channel = self.channelFactory.domChannel(self.dom) self.idx = self.channel.getIndex() @@ -43,21 +71,32 @@ class CtrlMsgRcvr: self.channel.registerDevice(self.majorTypes, self) def deregisterChannel(self): + """Deregister interest in our major message types with the + channel to our domain. + """ #print 'CtrlMsgRcvr>deregisterChannel>', self if self.channel: self.channel.deregisterDevice(self) del self.channel def produceRequests(self): + """Produce any queued requests. + + return number produced + """ return 0 def writeRequest(self, msg): + """Write a request to the channel. + """ if self.channel: self.channel.writeRequest(msg) else: print 'CtrlMsgRcvr>writeRequest>', 'no channel!', self def writeResponse(self, msg): + """Write a response to the channel. + """ if self.channel: self.channel.writeResponse(msg) else: @@ -66,6 +105,13 @@ class CtrlMsgRcvr: class ControllerFactory(CtrlMsgRcvr): """Abstract class for factories creating controllers. Maintains a table of instances. + + Instance variables: + + instances : mapping of index to controller instance + dlist : list of deferreds + dom : domain + timeout : deferred timeout """ def __init__(self): @@ -77,34 +123,49 @@ class ControllerFactory(CtrlMsgRcvr): self.timeout = 10 def addInstance(self, instance): + """Add a controller instance (under its index). + """ self.instances[instance.idx] = instance def getInstance(self, idx): + """Get a controller instance from its index. + """ return self.instances.get(idx) def getInstances(self): + """Get a list of all controller instances. + """ return self.instances.values() def getInstanceByDom(self, dom): + """Get the controller instance for the given domain. + """ for inst in self.instances.values(): if inst.dom == dom: return inst return None def delInstance(self, instance): - #print 'ControllerFactory>delInstance>', instance.idx + """Delete an instance from the table. + """ if instance.idx in self.instances: - #print 'ControllerFactory>delInstance> remove', instance.idx del self.instances[instance.idx] def createInstance(self, dom, recreate=0): + """Create an instance. Define in a subclass. + """ raise NotImplementedError() def instanceClosed(self, instance): - #print 'ControllerFactory>instanceClosed>', instance.idx, instance + """Callback called when an instance is closed (usually by the instance). + """ self.delInstance(instance) def addDeferred(self): + """Add a deferred object. + + returns deferred + """ d = defer.Deferred() if self.timeout > 0: # The deferred will error if not called before timeout. @@ -113,11 +174,19 @@ class ControllerFactory(CtrlMsgRcvr): return d def callDeferred(self, *args): + """Call the top deferred object + + args arguments + """ if self.dlist: d = self.dlist.pop(0) d.callback(*args) def errDeferred(self, *args): + """Signal an error to the top deferred object. + + args arguments + """ if self.dlist: d = self.dlist.pop(0) d.errback(*args) @@ -134,15 +203,20 @@ class Controller(CtrlMsgRcvr): self.idx = None def close(self): + """Close the controller. + """ self.deregisterChannel() self.lostChannel() def lostChannel(self): - #print 'Controller>lostChannel>', self, self.factory + """The controller channel has been lost. + """ self.factory.instanceClosed(self) class Dev: - + """Abstract class for a device attached to a device controller. + """ + def __init__(self, controller): self.controller = controller self.props = {} @@ -160,9 +234,6 @@ class Dev: if k in self.props: del self.props[k] - #def __repr__(self): - # return str(self.sxpr()) - def sxpr(self): raise NotImplementedError() diff --git a/tools/python/xen/xend/server/domain.py b/tools/python/xen/xend/server/domain.py index ab22234480..683d352ec0 100644 --- a/tools/python/xen/xend/server/domain.py +++ b/tools/python/xen/xend/server/domain.py @@ -1,3 +1,5 @@ +# Copyright (C) 2004 Mike Wray + import channel import controller from messages import * @@ -7,11 +9,23 @@ class DomainControllerFactory(controller.ControllerFactory): """ def createInstance(self, dom): + """Create a domain controller. + + dom domain + + returns domain controller + """ d = DomainController(self, dom) self.addInstance(d) return d def getInstanceByDom(self, dom): + """Get a domain controller for a domain, creating if necessary. + + dom domain + + returns domain controller + """ for inst in self.instances.values(): if inst.dom == dom: return inst @@ -21,8 +35,11 @@ class DomainControllerFactory(controller.ControllerFactory): class DomainController(controller.Controller): """Generic controller for a domain. + Used for domain shutdown. """ + """Map shutdown reasons to the message type to use. + """ reasons = {'poweroff' : 'shutdown_poweroff_t', 'reboot' : 'shutdown_reboot_t', 'suspend' : 'shutdown_suspend_t' } @@ -34,6 +51,10 @@ class DomainController(controller.Controller): print 'DomainController>', self, self.channel, self.idx def shutdown(self, reason): + """Shutdown a domain. + + reason shutdown reason + """ msgtype = self.reasons.get(reason) if not msgtype: raise ValueError('invalid reason:' + reason) diff --git a/tools/python/xen/xend/server/messages.py b/tools/python/xen/xend/server/messages.py index f3257ca832..bd2c1eed0e 100644 --- a/tools/python/xen/xend/server/messages.py +++ b/tools/python/xen/xend/server/messages.py @@ -148,6 +148,9 @@ netif_formats = { msg_formats.update(netif_formats) #============================================================================ +# Domain shutdown message types. +#============================================================================ + CMSG_SHUTDOWN = 6 CMSG_SHUTDOWN_POWEROFF = 0 @@ -177,6 +180,14 @@ class Msg: pass def packMsg(ty, params): + """Pack a message. + Any 'mac' parameter is passed in as an int[6] array and converted. + + ty message type name + params message parameter dict + + returns xu message + """ if DEBUG: print '>packMsg', ty, params (major, minor) = msg_formats[ty] args = {} @@ -194,6 +205,15 @@ def packMsg(ty, params): return msg def unpackMsg(ty, msg): + """Unpack a message. + Any mac addresses in the message are converted to int[6] array + in the return dict. + + ty message type + msg xu message + + returns parameter dict + """ args = msg.get_payload() mac = [0, 0, 0, 0, 0, 0] macs = [] @@ -212,6 +232,13 @@ def unpackMsg(ty, msg): return args def msgTypeName(ty, subty): + """Convert a message type, subtype pair (ints) to a message type name (string). + + ty integer message type + subty integer message subtype + + returns message type name (or None) + """ for (name, info) in msg_formats.items(): if info[0] == ty and info[1] == subty: return name diff --git a/tools/python/xen/xend/server/netif.py b/tools/python/xen/xend/server/netif.py index 2b01805be6..5760552e8b 100755 --- a/tools/python/xen/xend/server/netif.py +++ b/tools/python/xen/xend/server/netif.py @@ -1,3 +1,5 @@ +# Copyright (C) 2004 Mike Wray + import random from twisted.internet import defer @@ -30,8 +32,12 @@ class NetifControllerFactory(controller.ControllerFactory): def createInstance(self, dom, recreate=0): """Create or find the network interface controller for a domain. + + dom domain + recreate if true this is a recreate (xend restarted) + + returns netif controller """ - #print 'netif>createInstance> dom=', dom netif = self.getInstanceByDom(dom) if netif is None: netif = NetifController(self, dom) @@ -39,15 +45,31 @@ class NetifControllerFactory(controller.ControllerFactory): return netif def getDomainDevices(self, dom): + """Get the network device controllers for a domain. + + dom domain + + returns netif controller + """ netif = self.getInstanceByDom(dom) return (netif and netif.getDevices()) or [] def getDomainDevice(self, dom, vif): + """Get a virtual network interface device for a domain. + + dom domain + vif virtual interface index + + returns NetDev + """ netif = self.getInstanceByDom(dom) return (netif and netif.getDevice(vif)) or None def setControlDomain(self, dom, recreate=0): """Set the 'back-end' device driver domain. + + dom domain + recreate if true this is a recreate (xend restarted) """ if self.dom == dom: return self.deregisterChannel() @@ -55,13 +77,10 @@ class NetifControllerFactory(controller.ControllerFactory): self.attached = 0 self.dom = dom self.registerChannel() - # - #if xend.netif.be_port.remote_dom != 0: - # xend.netif.recovery = True - # xend.netif.be_port = xend.main.port_from_dom(dom) - # def getControlDomain(self): + """Get the domain id of the back-end control domain. + """ return self.dom def recv_be_create(self, msg, req): @@ -88,23 +107,6 @@ class NetifControllerFactory(controller.ControllerFactory): netif.reattach_devices() self.attached = 1 -## pl = msg.get_payload() -## status = pl['status'] -## if status == NETIF_DRIVER_STATUS_UP: -## if xend.netif.recovery: -## print "New netif backend now UP, notifying guests:" -## for netif_key in interface.list.keys(): -## netif = interface.list[netif_key] -## netif.create() -## print " Notifying %d" % netif.dom -## msg = xu.message( -## CMSG_NETIF_FE, -## CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED, 0, -## { 'handle' : 0, 'status' : 1 }) -## netif.ctrlif_tx_req(xend.main.port_from_dom(netif.dom),msg) -## print "Done notifying guests" -## recovery = False - class NetDev(controller.Dev): """Info record for a network device. """ @@ -130,9 +132,13 @@ class NetDev(controller.Dev): return val def get_vifname(self): + """Get the virtual interface device name. + """ return "vif%d.%d" % (self.controller.dom, self.vif) def get_mac(self): + """Get the MAC address as a string. + """ return ':'.join(map(lambda x: "%x" % x, self.mac)) def vifctl_params(self): @@ -141,23 +147,30 @@ class NetDev(controller.Dev): 'ipaddr': self.ipaddr } def up(self, bridge=None, ipaddr=[]): + """Bring the device up. + + bridge ethernet bridge to connect to + ipaddr list of ipaddrs to filter using iptables + """ self.bridge = bridge self.ipaddr = ipaddr Vifctl.up(self.get_vifname(), **self.vifctl_params()) def down(self): + """Bring the device down. + """ Vifctl.down(self.get_vifname(), **self.vifctl_params()) def destroy(self): + """Destroy the device's resources and disconnect from the back-end + device controller. + """ def cb_destroy(val): self.controller.send_be_destroy(self.vif) - print 'NetDev>destroy>', 'vif=', self.vif - PrettyPrint.prettyprint(self.sxpr()) self.down() d = self.controller.factory.addDeferred() d.addCallback(cb_destroy) self.controller.send_be_disconnect(self.vif) - #self.controller.send_be_destroy(self.vif) class NetifController(controller.Controller): @@ -165,7 +178,6 @@ class NetifController(controller.Controller): """ def __init__(self, factory, dom): - #print 'NetifController> dom=', dom controller.Controller.__init__(self, factory, dom) self.devices = {} @@ -178,21 +190,22 @@ class NetifController(controller.Controller): self.recv_fe_interface_connect, } self.registerChannel() - #print 'NetifController<', 'dom=', self.dom, 'idx=', self.idx def sxpr(self): val = ['netif', ['dom', self.dom]] return val def randomMAC(self): - # VIFs get a random MAC address with a "special" vendor id. - # - # NB. The vendor is currently an "obsolete" one that used to belong - # to DEC (AA-00-00). Using it is probably a bit rude :-) - # - # NB2. The first bit of the first random octet is set to zero for - # all dynamic MAC addresses. This may allow us to manually specify - # MAC addresses for some VIFs with no fear of clashes. + """Generate a random MAC address. + + The OUI (Organisation Unique Identifier) used is AA:00:00, which + is a currently unassigned one that used to belong to DEC. + + The remaining 3 fields are random, with the first bit of the first + random field set 0. + + returns array of 6 ints + """ mac = [ 0xaa, 0x00, 0x00, random.randint(0x00, 0x7f), random.randint(0x00, 0xff), @@ -200,29 +213,46 @@ class NetifController(controller.Controller): return mac def lostChannel(self): - print 'NetifController>lostChannel>', 'dom=', self.dom - #self.destroyDevices() + """Method called when the channel has been lost. + """ controller.Controller.lostChannel(self) def getDevices(self): + """Get a list of the devices. + """ return self.devices.values() def getDevice(self, vif): + """Get a device. + + vif device index + + returns device (or None) + """ return self.devices.get(vif) def addDevice(self, vif, vmac): + """Add a network interface. If vmac is None a random MAC is + assigned. If specified, vmac must be a string of the form + XX:XX:XX:XX:XX where X is hex digit. + + vif device index + vmac device MAC + + returns device + """ if vmac is None: mac = self.randomMAC() else: mac = [ int(x, 16) for x in vmac.split(':') ] if len(mac) != 6: raise ValueError("invalid mac") - #print "attach_device>", "vif=", vif, "mac=", mac dev = NetDev(self, vif, mac) self.devices[vif] = dev return dev def destroy(self): - print 'NetifController>destroy>', 'dom=', self.dom + """Destroy the controller and all devices. + """ self.destroyDevices() def destroyDevices(self): @@ -306,7 +336,6 @@ class NetifController(controller.Controller): self.factory.writeRequest(msg) def send_be_destroy(self, vif): - print 'NetifController>send_be_destroy>', 'dom=', self.dom, 'vif=', vif PrettyPrint.prettyprint(self.sxpr()) dev = self.devices[vif] del self.devices[vif] From da4eba9f1e914c1bfd16644d7f8cc1f418d84bb5 Mon Sep 17 00:00:00 2001 From: "mjw@wray-m-3.hpl.hp.com" Date: Thu, 1 Jul 2004 14:16:50 +0000 Subject: [PATCH 09/36] bitkeeper revision 1.1041.3.2 (40e41cd2iveMByv37PKjiwl04MigLQ) Help for defaults files. --- .rootkeys | 2 +- tools/examples/xmdefaults | 21 +- tools/python/xen/xend/XendClient.py | 30 +++ tools/python/xen/xend/server/cstruct.py | 269 ------------------------ tools/python/xen/xm/create.py | 49 ++++- tools/python/xen/xm/help.py | 82 ++++++++ tools/python/xen/xm/main.py | 25 +++ tools/python/xen/xm/opts.py | 18 +- 8 files changed, 206 insertions(+), 290 deletions(-) delete mode 100755 tools/python/xen/xend/server/cstruct.py create mode 100644 tools/python/xen/xm/help.py diff --git a/.rootkeys b/.rootkeys index 40c0fe962f..3cbef2d421 100644 --- a/.rootkeys +++ b/.rootkeys @@ -259,7 +259,6 @@ 40c9c469N2-b3GqpLHHHPZykJPLVvA tools/python/xen/xend/server/channel.py 40c9c469hJ_IlatRne-9QEa0-wlquw tools/python/xen/xend/server/console.py 40c9c469UcNJh_NuLU0ytorM0Lk5Ow tools/python/xen/xend/server/controller.py -40c9c469vHh-qLiiubdbKEQbJf18Zw tools/python/xen/xend/server/cstruct.py 40d83983OXjt-y3HjSCcuoPp9rzvmw tools/python/xen/xend/server/domain.py 40c9c469yrm31i60pGKslTi2Zgpotg tools/python/xen/xend/server/messages.py 40c9c46925x-Rjb0Cv2f1-l2jZrPYg tools/python/xen/xend/server/netif.py @@ -267,6 +266,7 @@ 40c9c469LNxLVizOUpOjEaTKKCm8Aw tools/python/xen/xend/sxp.py 40d05079aFRp6NQdo5wIh5Ly31c0cg tools/python/xen/xm/__init__.py 40cf2937gKQcATgXKGtNeWb1PDH5nA tools/python/xen/xm/create.py +40e41cd2w0I4En6qrJn4em8HkK_oxQ tools/python/xen/xm/help.py 40cf2937isyS250zyd0Q2GuEDoNXfQ tools/python/xen/xm/main.py 40cf2937PSslwBliN1g7ofDy2H_RhA tools/python/xen/xm/opts.py 40cf2937Z8WCNOnO2FcWdubvEAF9QQ tools/python/xen/xm/shutdown.py diff --git a/tools/examples/xmdefaults b/tools/examples/xmdefaults index f7b2f53c21..cf9e9861db 100644 --- a/tools/examples/xmdefaults +++ b/tools/examples/xmdefaults @@ -2,17 +2,24 @@ #============================================================================ # Python defaults setup for 'xm create'. # Edit this file to reflect the configuration of your system. -# This file expects the variable 'vmid' to be set. + #============================================================================ -try: - vmid = int(vmid) # convert to integer -except: - raise ValueError, "Variable 'vmid' must be an integer" +# Define script variables here. +# xm_vars is defined automatically, use xm_vars.var() to define a variable. -if vmid <= 0: - raise ValueError, "Variable 'vmid' must be greater than 0" +def vmid_check(var, val): + val = int(val) + if val <= 0: + raise ValueError + return val + +xm_vars.var('vmid', + use="Virtual machine id. Integer greater than 0.", + check=vmid_check) +# This checks the script variables. +xm_vars.check() #---------------------------------------------------------------------------- # Kernel image file. diff --git a/tools/python/xen/xend/XendClient.py b/tools/python/xen/xend/XendClient.py index 13dc3dbb1e..12a21c2c9c 100644 --- a/tools/python/xen/xend/XendClient.py +++ b/tools/python/xen/xend/XendClient.py @@ -1,6 +1,11 @@ # Copyright (C) 2004 Mike Wray """Client API for the HTTP interface on xend. Callable as a script - see main(). + +This API is the 'control-plane' for xend. +The 'data-plane' is done separately. For example, consoles +are accessed via sockets on xend, but the list of consoles +is accessible via this API. """ import sys import httplib @@ -27,6 +32,8 @@ class Foo(httplib.HTTPResponse): def sxprio(sxpr): + """Convert an sxpr to a string. + """ io = StringIO() sxp.show(sxpr, out=io) print >> io @@ -80,6 +87,12 @@ def eventurl(location, root, id=''): return urljoin(location, root, 'event/', id) def xend_request(url, method, data=None): + """Make a request to xend. + + url xend request url + method http method: POST or GET + data request argument data (dict) + """ urlinfo = urlparse.urlparse(url) (uproto, ulocation, upath, uparam, uquery, ufrag) = urlinfo if DEBUG: print url, urlinfo @@ -122,20 +135,37 @@ def xend_request(url, method, data=None): return val def xend_get(url, args=None): + """Make a xend request using GET. + Requests using GET are 'safe' and may be repeated without + nasty side-effects. + """ return xend_request(url, "GET", args) def xend_call(url, data): + """Make xend request using POST. + Requests using POST potentially cause side-effects and should + not be repeated unless it really is wanted to do the side + effect again. + """ return xend_request(url, "POST", data) class Xend: + """Default location of the xend server.""" SRV_DEFAULT = "localhost:8000" + + """Default path to the xend root on the server.""" ROOT_DEFAULT = "/xend/" def __init__(self, srv=None, root=None): self.bind(srv, root) def bind(self, srv=None, root=None): + """Bind to a given server. + + srv server location (host:port) + root server xend root path + """ if srv is None: srv = self.SRV_DEFAULT if root is None: root = self.ROOT_DEFAULT if not root.endswith('/'): root += '/' diff --git a/tools/python/xen/xend/server/cstruct.py b/tools/python/xen/xend/server/cstruct.py deleted file mode 100755 index 880931b41f..0000000000 --- a/tools/python/xen/xend/server/cstruct.py +++ /dev/null @@ -1,269 +0,0 @@ -import struct - -class Struct: - - maxDepth = 10 - - base = ['x', 'B', 'H', 'I', 'L', 'Q', 'c', 'h', 'i', 'l', 'q', ] - - sizes = {'B': 1, - 'H': 2, - 'I': 4, - 'L': 4, - 'Q': 8, - 'c': 1, - 'h': 2, - 'i': 4, - 'l': 4, - 'q': 8, - 'x': 1, - } - - formats = { - 'int8' : 'B', - 'int16' : 'H', - 'int32' : 'I', - 'int64' : 'Q', - 'u8' : 'B', - 'u16' : 'H', - 'u32' : 'I', - 'u64' : 'Q' - } - - def typedef(self, name, val): - self.formats[name] = val - - def struct(self, name, *f): - self.typedef(name, StructInfo(self, f)) - - def getType(self, name): - return self.formats[name] - - def format(self, ty): - d = 0 - f = ty - while d < self.maxDepth: - d += 1 - f = self.formats[f] - if isinstance(f, StructInfo): - return f.format() - if f in self.base: - return f - return -1 - - def alignedformat(self, ty): - fmt = self.format(ty) - #print 'alignedformat> %s |%s|' %(ty, fmt) - afmt = self.align(fmt) - #print 'alignedformat< %s |%s| |%s|' % (ty, fmt, afmt) - return afmt - - def align(self, fmt): - n1 = 0 - afmt = '' - for a in fmt: - n2 = self.getSize(a) - m = n1 % n2 - if m: - d = (n2 - m) - afmt += 'x' * d - n1 += d - afmt += a - n1 += n2 - return afmt - - def fmtsize(self, fmt): - s = 0 - for f in fmt: - s += self.getSize(f) - return s - - def getSize(self, f): - return self.sizes[f] - - def pack(self, ty, data): - return self.getType(ty).pack(data) - - def unpack(self, ty, data): - return self.getType(ty).unpack(data) - - def show(self): - l = self.formats.keys() - l.sort() - for v in l: - print "%-35s %-10s %s" % (v, self.format(v), self.alignedformat(v)) - - -class StructInfo: - - def __init__(self, s, f): - self.fmt = None - self.structs = s - self.fields = f - - def alignedformat(self): - if self.afmt: return self.afmt - self.afmt = self.structs.align(self.format()) - return self.afmt - - def format(self): - if self.fmt: return self.fmt - fmt = "" - for (ty, name) in self.fields: - fmt += self.formatString(ty) - self.fmt = fmt - return fmt - - def formatString(self, ty): - if ty in self.fields: - ty = self.fields[ty] - return self.structs.format(ty) - - def pack(self, *args): - return struct.pack(self.alignedformat(), *args) - - def unpack(self, data): - return struct.unpack(self.alignedformat(), data) - -types = Struct() - -types.typedef('short' , 'h') -types.typedef('int' , 'i') -types.typedef('long' , 'l') -types.typedef('unsigned short', 'H') -types.typedef('unsigned int' , 'I') -types.typedef('unsigned long' , 'L') -types.typedef('domid_t' , 'u64') -types.typedef('blkif_vdev_t' , 'u16') -types.typedef('blkif_pdev_t' , 'u16') -types.typedef('blkif_sector_t', 'u64') - -types.struct('u8[6]', - ('u8', 'a1'), - ('u8', 'a2'), - ('u8', 'a3'), - ('u8', 'a4'), - ('u8', 'a5'), - ('u8', 'a6')) - -types.struct('blkif_fe_interface_status_changed_t', - ('unsigned int', 'handle'), - ('unsigned int', 'status'), - ('unsigned int', 'evtchn')) - -types.struct('blkif_fe_driver_status_changed_t', - ('unsigned int', 'status'), - ('unsigned int', 'nr_interfaces')) - -types.struct('blkif_fe_interface_connect_t', - ('unsigned int' , 'handle'), - ('unsigned long', 'shmem_frame')) - -types.struct('blkif_fe_interface_disconnect_t', - ('unsigned int', 'handle')) - -types.struct('blkif_extent_t', - ('blkif_pdev_t' , 'device'), - ('blkif_sector_t', 'sector_start'), - ('blkif_sector_t', 'sector_length')) - -types.struct('blkif_be_create_t', - ('domid_t' , 'domid'), - ('unsigned int', 'blkif_handle'), - ('unsigned int', 'status')) - -types.struct('blkif_be_destroy_t', - ('domid_t' , 'domid'), - ('unsigned int', 'blkif_handle'), - ('unsigned int', 'status')) - -types.struct('blkif_be_connect_t', - ('domid_t' , 'domid'), - ('unsigned int' , 'blkif_handle'), - ('unsigned int' , 'evtchn'), - ('unsigned long', 'shmem_frame'), - ('unsigned int' , 'status')) - -types.struct('blkif_be_disconnect_t', - ('domid_t' , 'domid'), - ('unsigned int', 'blkif_handle'), - ('unsigned int', 'status')) - -types.struct('blkif_be_vbd_create_t', - ('domid_t' , 'domid'), #Q - ('unsigned int', 'blkif_handle'), #I - ('blkif_vdev_t', 'vdevice'), #H - ('int' , 'readonly'), #i - ('unsigned int', 'status')) #I - -types.struct('blkif_be_vbd_destroy_t', - ('domid_t' , 'domid'), - ('unsigned int', 'blkif_handle'), - ('blkif_vdev_t', 'vdevice'), - ('unsigned int', 'status')) - -types.struct('blkif_be_vbd_grow_t', - ('domid_t' , 'domid'), #Q - ('unsigned int' , 'blkif_handle'), #I - ('blkif_vdev_t' , 'vdevice'), #H - ('blkif_extent_t', 'extent'), #HQQ - ('unsigned int' , 'status')) #I - -types.struct('blkif_be_vbd_shrink_t', - ('domid_t' , 'domid'), - ('unsigned int', 'blkif_handle'), - ('blkif_vdev_t', 'vdevice'), - ('unsigned int', 'status')) - -types.struct('blkif_be_driver_status_changed_t', - ('unsigned int', 'status'), - ('unsigned int', 'nr_interfaces')) - -types.struct('netif_fe_interface_status_changed_t', - ('unsigned int', 'handle'), - ('unsigned int', 'status'), - ('unsigned int', 'evtchn'), - ('u8[6]', 'mac')) - -types.struct('netif_fe_driver_status_changed_t', - ('unsigned int', 'status'), - ('unsigned int', 'nr_interfaces')) - -types.struct('netif_fe_interface_connect_t', - ('unsigned int', 'handle'), - ('unsigned long', 'tx_shmem_frame'), - ('unsigned long', 'rx_shmem_frame')) - -types.struct('netif_fe_interface_disconnect_t', - ('unsigned int', 'handle')) - -types.struct('netif_be_create_t', - ('domid_t' , 'domid'), - ('unsigned int', 'netif_handle'), - ('u8[6]' , 'mac'), - ('unsigned int', 'status')) - -types.struct('netif_be_destroy_t', - ('domid_t' , 'domid'), - ('unsigned int', 'netif_handle'), - ('unsigned int', 'status')) - -types.struct('netif_be_connect_t', - ('domid_t' , 'domid'), - ('unsigned int' , 'netif_handle'), - ('unsigned int' , 'evtchn'), - ('unsigned long', 'tx_shmem_frame'), - ('unsigned long', 'rx_shmem_frame'), - ('unsigned int' , 'status')) - -types.struct('netif_be_disconnect_t', - ('domid_t' , 'domid'), - ('unsigned int', 'netif_handle'), - ('unsigned int', 'status')) - -types.struct('netif_be_driver_status_changed_t', - ('unsigned int', 'status'), - ('unsigned int', 'nr_interfaces')) - -if 1 or __name__ == "__main__": - types.show() diff --git a/tools/python/xen/xm/create.py b/tools/python/xen/xm/create.py index 7819243adb..36bcddef92 100644 --- a/tools/python/xen/xm/create.py +++ b/tools/python/xen/xm/create.py @@ -1,4 +1,5 @@ # Copyright (C) 2004 Mike Wray + """Domain creation. """ import string @@ -15,12 +16,22 @@ from xen.xm.opts import * gopts = Opts(use="""[options] Create a domain. + +Domain creation parameters can be set by command-line switches, from +a python configuration script or an SXP config file. See documentation +for --defaults, --config. Configuration variables can be set using +VAR=VAL on the command line. For example vmid=3 sets vmid to 3. + """) gopts.opt('help', short='h', fn=set_true, default=0, use="Print this help.") +gopts.opt('help_config', + fn=set_true, default=0, + use="Print help for configuration file.") + gopts.opt('quiet', short='q', fn=set_true, default=0, use="Quiet.") @@ -31,24 +42,40 @@ gopts.opt('path', val='PATH', gopts.opt('defaults', short='f', val='FILE', fn=set_value, default='xmdefaults', - use="Use the given default script.") + use="""Use the given Python defaults script. +The defaults script is loaded after arguments have been processed. +Each command-line option sets a configuration variable named after +its long option name, and these variables are placed in the +environment of the script before it is loaded. +Variables for options that may be repeated have list values. +Other variables can be set using VAR=VAL on the command line. + +After the script is loaded, option values that were not set on the +command line are replaced by the values set in the script. +""") gopts.opt('config', short='F', val='FILE', fn=set_value, default=None, - use='Domain configuration to use (SXP).') + use="""Domain configuration to use (SXP). +SXP is the underlying configuration format used by Xen. +SXP configs can be hand-written or generated from Python defaults +scripts, using the -n (dryrun) option to print the config. +""") gopts.opt('load', short='L', val='FILE', fn=set_value, default=None, use='Domain saved state to load.') -gopts.opt('define', short='D', val='VAR=VAL', - fn=set_var, default=None, - use="""Set a variable before loading defaults, e.g. '-D vmid=3' - to set vmid. May be repeated to set more thanone variable.""") +#gopts.opt('define', short='D', val='VAR=VAL', +# fn=set_var, default=None, +# use="""Set a variable before loading defaults, e.g. '-D vmid=3' +# to set vmid. May be repeated to set more than one variable.""") gopts.opt('dryrun', short='n', fn=set_true, default=0, - use="Dry run - print the config but don't create the domain.") + use="""Dry run - print the config but don't create the domain. +The defaults file is loaded and the SXP configuration is created and printed. +""") gopts.opt('name', short='N', val='NAME', fn=set_value, default=None, @@ -352,7 +379,15 @@ def main(argv): args = opts.parse(argv) if opts.vals.help: opts.usage() + if opts.vals.help or opts.vals.help_config: + opts.load_defaults(help=1) + if opts.vals.help or opts.vals.help_config: return + # Process remaining args as config variables. + for arg in args: + if '=' in arg: + (var, val) = arg.strip().split('=') + gopts.setvar(var.strip(), val.strip()) if opts.vals.config: pass else: diff --git a/tools/python/xen/xm/help.py b/tools/python/xen/xm/help.py new file mode 100644 index 0000000000..88df4412c0 --- /dev/null +++ b/tools/python/xen/xm/help.py @@ -0,0 +1,82 @@ +# Copyright (C) 2004 Mike Wray + +"""Variable definition and help support for Python defaults files. +""" + +import sys + +class Vars: + """A set of configuration variables. + """ + + def __init__(self, name, help, env): + """Create a variable set. + + name name of the defaults file + help help flag + env local environment + """ + self.name = name + self.help = help + self.env = env + self.vars = [] + + def var(self, name, use=None, check=None): + """Define a configuration variable. + If provided, the check function will be called as check(var, val) + where var is the variable name and val is its value (string). + It should return a new value for the variable, or raise ValueError if + the value is not acceptable. + + name variable name + use variable usage string + check variable check function + """ + self.vars.append(Var(name, use, check)) + + def check(self): + """Execute the variable checks or print help, depending on the value + of the help flag passed to the constructor. + """ + if self.help: + self.doHelp() + else: + for v in self.vars: + v.doCheck(self.env) + + def doHelp(self, out=sys.stderr): + """Print help for the variables. + """ + if self.vars: + print >>out, "\nConfiguration variables for %s:\n" % self.name + for v in self.vars: + v.doHelp(out) + print >>out + +class Var: + """A single variable. + """ + + def __init__(self, name, use, check): + """Create a variable. + + name variable name + use variable use string + check variable value check function + """ + self.name = name + self.use = use or '' + self.check = check + + def doCheck(self, env): + """Execute the check and set the variable to the new value. + """ + if not self.check: return + env[self.name] = self.check(self.name, env.get(self.name)) + + def doHelp(self, out): + """Print help for the variable. + """ + print >>out, "%-12s" % self.name, self.use + + diff --git a/tools/python/xen/xm/main.py b/tools/python/xen/xm/main.py index 3ab5d23cf7..97a36f6711 100644 --- a/tools/python/xen/xm/main.py +++ b/tools/python/xen/xm/main.py @@ -5,10 +5,12 @@ import os import os.path import sys from getopt import getopt +import socket from xen.xend import PrettyPrint from xen.xend import sxp from xen.xend.XendClient import server +from xen.xend.XendClient import main as xend_client_main from xen.xm import create, shutdown class Prog: @@ -65,6 +67,13 @@ class Xm: sys.exit(1) def main(self, args): + try: + self.main_call(args) + except socket.error, ex: + print >>sys.stderr, ex + self.err("Error connecting to xend, is xend running?") + + def main_call(self, args): """Main entry point. Dispatches to the progs. """ self.name = args[0] @@ -444,5 +453,21 @@ class ProgConsole(Prog): xm.prog(ProgConsole) +class ProgCall(Prog): + name = "call" + info = "Call xend api functions." + + def help (self, args): + print "call fn argss..." + print """ + Call a xend HTTP API function. The leading 'xend_' on the function +can be omitted. See xen.xend.XendClient for the API functions. +""" + + def main(self, args): + xend_client_main(args) + +xm.prog(ProgCall) + def main(args): xm.main(args) diff --git a/tools/python/xen/xm/opts.py b/tools/python/xen/xm/opts.py index eb07936f1e..25f11abad2 100644 --- a/tools/python/xen/xm/opts.py +++ b/tools/python/xen/xm/opts.py @@ -259,7 +259,7 @@ class Opts: for opt in self.options: opt.show() - def load_defaults(self): + def load_defaults(self, help=0): """Load a defaults script. Assumes these options set: 'path' search path 'default' script name @@ -270,12 +270,12 @@ class Opts: else: p = self.vals.defaults if os.path.exists(p): - self.load(p) + self.load(p, help) break else: self.err("Cannot open defaults file %s" % self.vals.defaults) - def load(self, defaults, help=0): + def load(self, defaults, help): """Load a defaults file. Local variables in the file are used to set options with the same names. Variables are not used to set options that are already specified. @@ -290,11 +290,17 @@ class Opts: cmd = '\n'.join(["import sys", "import os", "import os.path", - "import xen.util.ip", + "from xen.xm.help import Vars", + "from xen.util import ip", "xm_file = '%s'" % defaults, - "xm_help = %d" % help ]) + "xm_help = %d" % help, + "xm_vars = Vars(xm_file, xm_help, locals())", + ]) exec cmd in globals, locals - execfile(defaults, globals, locals) + try: + execfile(defaults, globals, locals) + except: + if not help: raise if help: return # Extract the values set by the script and set the corresponding # options, if not set on the command line. From 788b1c4771038b1d0bc1bdf1600f13cf584e98ea Mon Sep 17 00:00:00 2001 From: "kaf24@scramble.cl.cam.ac.uk" Date: Thu, 1 Jul 2004 15:20:59 +0000 Subject: [PATCH 10/36] bitkeeper revision 1.1041.1.8 (40e42bdbxRgFLnyaLAVXrbfK0RQrgg) Cleanups. --- .rootkeys | 3 +- xen/arch/x86/Makefile | 4 +- xen/arch/x86/boot/{boot.S => x86_32.S} | 128 +++++------------ xen/arch/x86/boot/x86_64.S | 185 +++++++++++++++++++++++++ xen/arch/x86/setup.c | 1 - xen/common/kernel.c | 16 ++- xen/include/asm-x86/config.h | 3 +- 7 files changed, 239 insertions(+), 101 deletions(-) rename xen/arch/x86/boot/{boot.S => x86_32.S} (67%) create mode 100644 xen/arch/x86/boot/x86_64.S diff --git a/.rootkeys b/.rootkeys index 92c6f42e9e..e843df9b04 100644 --- a/.rootkeys +++ b/.rootkeys @@ -281,7 +281,8 @@ 3ddb79bcBQF85CfLS4i1WGZ4oLLaCA xen/arch/x86/Rules.mk 3e5636e5FAYZ5_vQnmgwFJfSdmO5Mw xen/arch/x86/acpi.c 3ddb79bcsjinG9k1KcvbVBuas1R2dA xen/arch/x86/apic.c -3ddb79bcSC_LvnmFlX-T5iTgaR0SKg xen/arch/x86/boot/boot.S +3ddb79bcSC_LvnmFlX-T5iTgaR0SKg xen/arch/x86/boot/x86_32.S +40e42bdbNu4MjI750THP_8J1S-Sa0g xen/arch/x86/boot/x86_64.S 3ddb79bcUrk2EIaM5VsT6wUudH1kkg xen/arch/x86/delay.c 3e32af9aRnYGl4GMOaDKp7JdfhOGhg xen/arch/x86/domain_page.c 3ddb79bcecupHj56ZbTa3B0FxDowMg xen/arch/x86/entry.S diff --git a/xen/arch/x86/Makefile b/xen/arch/x86/Makefile index 7a6d659d0b..f6ef36afce 100644 --- a/xen/arch/x86/Makefile +++ b/xen/arch/x86/Makefile @@ -15,9 +15,9 @@ LOAD_BASE := 0x00100000 # Xen is loaded here # segment offsets from LINK_BASE-relative to LOAD_BASE-relative. # (NB. Linux gets round this by turning its image into raw binary, then # wrapping that with a low-memory bootstrapper.) -default: boot/boot.o $(OBJS) +default: boot/$(TARGET_SUBARCH).o $(OBJS) $(LD) -r -o arch.o $(OBJS) - $(LD) $(LDFLAGS) boot/boot.o $(ALL_OBJS) -o $(TARGET)-syms + $(LD) $(LDFLAGS) boot/$(TARGET_SUBARCH).o $(ALL_OBJS) -o $(TARGET)-syms objcopy -R .note -R .comment -S $(TARGET)-syms $(TARGET) $(BASEDIR)/tools/elf-reloc $(LINK_BASE) $(LOAD_BASE) $(TARGET) diff --git a/xen/arch/x86/boot/boot.S b/xen/arch/x86/boot/x86_32.S similarity index 67% rename from xen/arch/x86/boot/boot.S rename to xen/arch/x86/boot/x86_32.S index 55a4cc4cc2..ae1d72ad23 100644 --- a/xen/arch/x86/boot/boot.S +++ b/xen/arch/x86/boot/x86_32.S @@ -7,7 +7,7 @@ .text ENTRY(start) - jmp hal_entry + jmp __start .align 4 @@ -19,7 +19,10 @@ ENTRY(start) /* Checksum: must be the negated sum of the first two fields. */ .long -0x1BADB004 -hal_entry: +bad_cpu: + jmp bad_cpu + +__start: /* Set up a few descriptors: on entry only CS is guaranteed good. */ lgdt %cs:nopaging_gdt_descr-__PAGE_OFFSET mov $(__HYPERVISOR_DS),%ecx @@ -47,34 +50,18 @@ hal_entry: and %edx,%ecx je bad_cpu # ID bit should be set - /* Set up CR0. */ - mov %cr0,%ecx - and $0x00000011,%ecx # save ET and PE - or $0x00050022,%ecx # set AM, WP, NE and MP - mov %ecx,%cr0 - /* Set up FPU. */ fninit /* Set up CR4, except global flag which Intel requires should be */ /* left until after paging is enabled (IA32 Manual Vol. 3, Sec. 2.5) */ - mov %cr4,%ecx - or mmu_cr4_features-__PAGE_OFFSET,%ecx - mov %ecx,mmu_cr4_features-__PAGE_OFFSET - and $0x7f,%ecx /* disable GLOBAL bit */ + mov mmu_cr4_features-__PAGE_OFFSET,%ecx + and $0x7f,%cl # CR4.PGE (global enable) mov %ecx,%cr4 -#ifdef CONFIG_SMP - /* Is this a non-boot processor? */ cmp $(SECONDARY_CPU_FLAG),%ebx - jne continue_boot_cpu - - call start_paging - lidt idt_descr - jmp start_secondary -#endif - -continue_boot_cpu: + je start_paging + add $__PAGE_OFFSET,%ebx push %ebx /* Multiboot info struct */ push %eax /* Multiboot magic value */ @@ -86,31 +73,6 @@ continue_boot_cpu: xor %eax,%eax rep stosb - /* Copy all modules (dom0 + initrd if present) out of the Xen heap */ - mov (%esp),%eax - cmp $0x2BADB002,%eax - jne skip_dom0_copy - sub $__PAGE_OFFSET,%ebx /* turn back into a phys addr */ - mov 0x14(%ebx),%edi /* mbi->mods_count */ - dec %edi /* mbi->mods_count-- */ - jb skip_dom0_copy /* skip if no modules */ - mov 0x18(%ebx),%eax /* mbi->mods_addr */ - mov (%eax),%ebx /* %ebx = mod[0]->mod_start */ - shl $4,%edi - add %edi,%eax - mov 0x4(%eax),%eax /* %eax = mod[mod_count-1]->end */ - mov %eax,%ecx - sub %ebx,%ecx /* %ecx = byte len of all mods */ - mov $(DIRECTMAP_PHYS_END), %edi - add %ecx, %edi /* %edi = src + length */ - shr $2,%ecx /* %ecx = length/4 */ -1: sub $4,%eax /* %eax = src, %edi = dst */ - sub $4,%edi - mov (%eax),%ebx - mov %ebx,(%edi) - loop 1b -skip_dom0_copy: - /* Initialize low and high mappings of all memory with 4MB pages */ mov $idle_pg_table-__PAGE_OFFSET,%edi mov $0x1e3,%eax /* PRESENT+RW+A+D+4MB+GLOBAL */ @@ -119,20 +81,27 @@ skip_dom0_copy: add $(1< +#include +#include + +#define SECONDARY_CPU_FLAG 0xA5A5A5A5 + + .text + .code32 + +ENTRY(start) + jmp __start + + .align 4 + +/*** MULTIBOOT HEADER ****/ + /* Magic number indicating a Multiboot header. */ + .long 0x1BADB002 + /* Flags to bootloader (see Multiboot spec). */ + .long 0x00000002 + /* Checksum: must be the negated sum of the first two fields. */ + .long -0x1BADB004 + +bad_cpu: + jmp bad_cpu + +__start: + /* We begin by interrogating the CPU for the presence of long mode. */ + mov $0x80000000,%eax + cpuid + cmp $0x80000000,%eax # any function > 0x80000000? + jbe bad_cpu + mov $0x80000001,%eax + cpuid + bt $29,%edx # Long mode feature? + jnc bad_cpu + + /* Set up a few descriptors: on entry only CS is guaranteed good. */ + lgdt %cs:nopaging_gdt_descr-__PAGE_OFFSET + mov $(__HYPERVISOR_DS),%ecx + mov %ecx,%ds + mov %ecx,%es + mov %ecx,%fs + mov %ecx,%gs + ljmp $(__HYPERVISOR_CS32),$(1f)-__PAGE_OFFSET +1: lss stack_start-__PAGE_OFFSET,%esp + + /* Reset EFLAGS (subsumes CLI and CLD). */ + pushl $0 + popf + + /* Set up FPU. */ + fninit + + /* Set up CR4, except global flag which Intel requires should be */ + /* left until after paging is enabled (IA32 Manual Vol. 3, Sec. 2.5) */ + mov mmu_cr4_features-__PAGE_OFFSET,%ecx + and $0x7f,%cl # CR4.PGE (global enable) + mov %ecx,%cr4 + + cmp $(SECONDARY_CPU_FLAG),%ebx + je start_paging + + add $__PAGE_OFFSET,%ebx + push %ebx /* Multiboot info struct */ + push %eax /* Multiboot magic value */ + + /* Initialize BSS (no nasty surprises!) */ + mov $__bss_start-__PAGE_OFFSET,%edi + mov $_end-__PAGE_OFFSET,%ecx + sub %edi,%ecx + xor %eax,%eax + rep stosb + + /* Initialize low and high mappings of all memory with 4MB pages */ + mov $idle_pg_table-__PAGE_OFFSET,%edi + mov $0x1e3,%eax /* PRESENT+RW+A+D+4MB+GLOBAL */ +1: mov %eax,__PAGE_OFFSET>>20(%edi) /* high mapping */ + stosl /* low mapping */ + add $(1<mods_count-1].mod_end - mod[0].mod_start); + if ( initial_images_end > (max_page << PAGE_SHIFT) ) + { + printk("Not enough memory to stash the DOM0 kernel image.\n"); + for ( ; ; ) ; + } + memmove((void *)initial_images_start, /* use low mapping */ + (void *)mod[0].mod_start, /* use low mapping */ + mod[mbi->mods_count-1].mod_end - mod[0].mod_start); + if ( opt_xenheap_megabytes > XENHEAP_DEFAULT_MB ) { printk("Xen heap size is limited to %dMB - you specified %dMB.\n", @@ -214,10 +226,6 @@ void cmain(unsigned long magic, multiboot_info_t *mbi) init_frametable((void *)FRAMETABLE_VIRT_START, max_page); - /* Initial images stashed away above DIRECTMAP area in boot.S. */ - initial_images_start = DIRECTMAP_PHYS_END; - initial_images_end = initial_images_start + - (mod[mbi->mods_count-1].mod_end - mod[0].mod_start); #elif defined(__x86_64__) diff --git a/xen/include/asm-x86/config.h b/xen/include/asm-x86/config.h index af0172df90..f61f6aeedd 100644 --- a/xen/include/asm-x86/config.h +++ b/xen/include/asm-x86/config.h @@ -164,7 +164,8 @@ extern void __out_of_line_bug(int line) __attribute__((noreturn)); #define DIRECTMAP_PHYS_END (40*1024*1024) /* Hypervisor owns top 64MB of virtual address space. */ -#define HYPERVISOR_VIRT_START (0xFC000000UL) +#define __HYPERVISOR_VIRT_START 0xFC000000 +#define HYPERVISOR_VIRT_START (0xFC000000UL) /* * First 4MB are mapped read-only for all. It's for the machine->physical From 87a12f54d3388557c476de27828ac06d19bdb69f Mon Sep 17 00:00:00 2001 From: "tw275@striker.cl.cam.ac.uk" Date: Thu, 1 Jul 2004 16:37:02 +0000 Subject: [PATCH 11/36] bitkeeper revision 1.1041.1.9 (40e43dae6tkOjKpGS7n77Q_WIw-vwg) Fixing drive finding with scsi arrays in Xend --- BitKeeper/etc/logging_ok | 1 + tools/python/xen/xend/XendDomainInfo.py | 9 +++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok index 04eb20bb84..bcbf3eae42 100644 --- a/BitKeeper/etc/logging_ok +++ b/BitKeeper/etc/logging_ok @@ -39,4 +39,5 @@ smh22@uridium.cl.cam.ac.uk sos22@labyrinth.cl.cam.ac.uk tlh20@elite.cl.cam.ac.uk tlh20@labyrinth.cl.cam.ac.uk +tw275@striker.cl.cam.ac.uk xenbk@gandalf.hpl.hp.com diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index c0de8fed01..869fc28e07 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -79,8 +79,13 @@ def lookup_raw_partn(partition): if not re.match( '/dev/', partition ): partition = '/dev/' + partition - - drive = re.split( '[0-9]', partition )[0] + + """Try and match non-standard scsi raid arraysa + """ + if re.match( '/dev/cciss/c[0-9]+d[0-9]+p[0-9]+', partition ): + drive = re.split( 'p[0-9]+', partition )[0] + else: + drive = re.split( '[0-9]', partition )[0] if drive == partition: fd = os.popen( '/sbin/sfdisk -s ' + drive + ' 2>/dev/null' ) From 85f794d3f0d3888f9d5456020d13d4e6ecf5b7fc Mon Sep 17 00:00:00 2001 From: "kaf24@scramble.cl.cam.ac.uk" Date: Thu, 1 Jul 2004 23:32:34 +0000 Subject: [PATCH 12/36] bitkeeper revision 1.1041.4.1 (40e49f12Fj3pygWG3LxLQ2tcwBx24A) Fix common files when compiled without CONFIG_SMP (some x86-specific files still don't work). --- xen/drivers/pci/quirks.c | 1 + xen/include/asm-x86/io_apic.h | 1 + xen/include/asm-x86/page.h | 2 ++ xen/include/asm-x86/smp.h | 1 - xen/include/xen/sched.h | 1 + xen/include/xen/smp.h | 4 +++- xen/include/xen/spinlock.h | 2 ++ 7 files changed, 10 insertions(+), 2 deletions(-) diff --git a/xen/drivers/pci/quirks.c b/xen/drivers/pci/quirks.c index 4e920c5234..71c0bb428d 100644 --- a/xen/drivers/pci/quirks.c +++ b/xen/drivers/pci/quirks.c @@ -18,6 +18,7 @@ #include #include #include +#include #undef DEBUG diff --git a/xen/include/asm-x86/io_apic.h b/xen/include/asm-x86/io_apic.h index 89e0fc0b5b..1c2b24085a 100644 --- a/xen/include/asm-x86/io_apic.h +++ b/xen/include/asm-x86/io_apic.h @@ -3,6 +3,7 @@ #include #include +#include /* * Intel IO-APIC support for SMP and UP systems. diff --git a/xen/include/asm-x86/page.h b/xen/include/asm-x86/page.h index 8eb30e35ea..8e4a7ec093 100644 --- a/xen/include/asm-x86/page.h +++ b/xen/include/asm-x86/page.h @@ -180,6 +180,8 @@ static __inline__ int get_order(unsigned long size) } while (size); return order; } + +extern void zap_low_mappings(void); #endif #endif /* _I386_PAGE_H */ diff --git a/xen/include/asm-x86/smp.h b/xen/include/asm-x86/smp.h index ac9cc5292f..25c29de2e8 100644 --- a/xen/include/asm-x86/smp.h +++ b/xen/include/asm-x86/smp.h @@ -42,7 +42,6 @@ extern void smp_message_irq(int cpl, void *dev_id, struct pt_regs *regs); extern void smp_send_reschedule(int cpu); extern void smp_invalidate_rcv(void); /* Process an NMI */ extern void (*mtrr_hook) (void); -extern void zap_low_mappings (void); /* * On x86 all CPUs are mapped 1:1 to the APIC space. diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h index 009ce5f5e3..976a12bbe3 100644 --- a/xen/include/xen/sched.h +++ b/xen/include/xen/sched.h @@ -15,6 +15,7 @@ #include #include #include +#include #define STACK_SIZE (2*PAGE_SIZE) #include diff --git a/xen/include/xen/smp.h b/xen/include/xen/smp.h index d7f71b6fae..12885a5037 100644 --- a/xen/include/xen/smp.h +++ b/xen/include/xen/smp.h @@ -72,7 +72,9 @@ extern volatile int smp_msg_id; /* * These macros fold the SMP functionality into a single CPU system */ - + +#define smp_send_event_check_mask(_m) ((void)0) +#define smp_send_event_check_cpu(_p) ((void)0) #define smp_num_cpus 1 #define smp_processor_id() 0 #define hard_smp_processor_id() 0 diff --git a/xen/include/xen/spinlock.h b/xen/include/xen/spinlock.h index 206f3c1762..b74b5f802f 100644 --- a/xen/include/xen/spinlock.h +++ b/xen/include/xen/spinlock.h @@ -54,6 +54,8 @@ typedef struct { int gcc_is_buggy; } spinlock_t; #define spin_trylock(lock) ({1; }) #define spin_unlock_wait(lock) do { } while(0) #define spin_unlock(lock) do { } while(0) +#define spin_lock_recursive(lock) do { } while(0) +#define spin_unlock_recursive(lock) do { } while(0) #if (__GNUC__ > 2) typedef struct { } rwlock_t; From dc44ed47647fd67da4a395dd34c6f7297b93e509 Mon Sep 17 00:00:00 2001 From: "kaf24@scramble.cl.cam.ac.uk" Date: Fri, 2 Jul 2004 08:51:38 +0000 Subject: [PATCH 13/36] bitkeeper revision 1.1041.6.1 (40e5221awCqaZfcsO_ny2z3p_6BiEg) nsplitd.c, Makefile: mvdir Makefile: Rename: BitKeeper/deleted/.del-Makefile~9f548ce6ff509eac -> tools/nsplitd/Makefile nsplitd.c: Rename: BitKeeper/deleted/.del-nsplitd.c~8b67653f8e377176 -> tools/nsplitd/nsplitd.c --- .rootkeys | 2 + tools/misc/nsplitd/Makefile | 22 ++ tools/misc/nsplitd/nsplitd.c | 686 +++++++++++++++++++++++++++++++++++ 3 files changed, 710 insertions(+) create mode 100644 tools/misc/nsplitd/Makefile create mode 100644 tools/misc/nsplitd/nsplitd.c diff --git a/.rootkeys b/.rootkeys index e843df9b04..c575ef31d3 100644 --- a/.rootkeys +++ b/.rootkeys @@ -201,6 +201,8 @@ 3f6dc140C8tAeBfroAF24VrmCS4v_w tools/misc/miniterm/README 3f6dc142IHaf6XIcAYGmhV9nNSIHFQ tools/misc/miniterm/miniterm.c 40c9c469kT0H9COWzA4XzPBjWK0WsA tools/misc/netfix +4022a73cEKvrYe_DVZW2JlAxobg9wg tools/misc/nsplitd/Makefile +4022a73cKms4Oq030x2JBzUB426lAQ tools/misc/nsplitd/nsplitd.c 3f870808_8aFBAcZbWiWGdgrGQyIEw tools/misc/p4perf.h 3f5ef5a2ir1kVAthS14Dc5QIRCEFWg tools/misc/xen-clone 3f5ef5a2dTZP0nnsFoeq2jRf3mWDDg tools/misc/xen-clone.README diff --git a/tools/misc/nsplitd/Makefile b/tools/misc/nsplitd/Makefile new file mode 100644 index 0000000000..c5c4c9ed40 --- /dev/null +++ b/tools/misc/nsplitd/Makefile @@ -0,0 +1,22 @@ + +CC = gcc +CFLAGS = -Wall -O3 +CFILES = $(wildcard *.c) + +HDRS = $(wildcard *.h) +OBJS = $(patsubst %.c,%.o,$(wildcard *.c)) + +TARGET = nsplitd + +all: $(TARGET) + +install: all + +clean: + $(RM) *.o $(TARGET) *~ + +$(TARGET): $(OBJS) + $(CC) $(CFLAGS) -o $@ $^ + +%.o: %.c $(HDRS) Makefile + $(CC) $(CFLAGS) -c -o $@ $< diff --git a/tools/misc/nsplitd/nsplitd.c b/tools/misc/nsplitd/nsplitd.c new file mode 100644 index 0000000000..48fbd65103 --- /dev/null +++ b/tools/misc/nsplitd/nsplitd.c @@ -0,0 +1,686 @@ +/* + * nsplitd.c + * --------- + * + * $Id: nsplitd.c,v 2.6 1998/09/17 14:28:37 sde1000 Exp $ + * + * Copyright (c) 1995, University of Cambridge Computer Laboratory, + * Copyright (c) 1995, Richard Black, All Rights Reserved. + * + * + * A complete re-implementation of DME's nsplitd for use from inetd + * + */ + +/* The basic stream comes in (via inetd) and we then conenct to + * somewhere else providing a loop-through service, except we offer + * two other ports for connection - one of which gets a second channel + * using the top bit to distinguish, and the other is a master control + * port (normally used for gdb) which gets complete exclusive access + * for its duration. + * + * Originally designed for multiplexing a xwcons/telnet with a gdb + * post-mortem debugging session. + * + * Here is a picture: + * + * port0 (from inetd) + * 8-bit connection / + * made by us <----> nsplitd <-----gdbport (default port0+2) + * to host:port/tcp |\ + * | port1 (default port0+1) + * \ + * control (default port0+3) + * + * If port1 is explicitly disabled (through a command-line option) then + * port0 becomes 8-bit clean. + */ + +/* + * N.B.: We do NOT support 8 bit stdin/stdout usage on a + * /dev/... because to do that right involves much messing with ioctl + * and TIOC... etc. If you want to do that sort of thing then the + * right way to do it is to chain this onto wconsd (which does know + * about and understand all the ioctl and TIOC grief). + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef FALSE +#define FALSE 0 +#endif +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef LOG_DAEMON +#define LOG_DAEMON 0 +#endif + +#define DB(x) /* ((x), fflush(stderr)) */ + +extern char *optarg; + +extern int optind, opterr, optopt; + +static char *prog_name; + +static void usage(void) +{ + fprintf(stderr, "This program (%s) should be run via inetd (tcp)\n\n", + prog_name); + fprintf(stderr, "usage: %s [-h][-g]" + "[-c][-8] host:service\n", + prog_name); + exit(1); +} + +static void fault(char *format, ...) +{ + va_list ap; + char logbuf[1024]; + + va_start(ap, format); + fprintf(stderr, "%s: ", prog_name); + vfprintf(stderr, format, ap); + fflush(stderr); + va_end(ap); + + /* XXX This is a bit dubious, but there is no vsyslog */ + va_start(ap, format); + vsprintf(logbuf, format, ap); + syslog(LOG_ERR, logbuf); + va_end(ap); + exit(1); +} + +static int getservice(char *name, unsigned short *port) +{ + struct servent *se; + + if (!name) return -1; + + if (isdigit(name[0])) + *port = atoi(name); + else + { + if (!(se = getservbyname(name, "tcp"))) + return -1; + *port = ntohs(se->s_port); + } + return 0; +} + +/* + * connect_host: connect to ("name", "port") + */ +static int connect_host (char *name, unsigned int port) +{ + int fd; + struct hostent *hostent; + struct sockaddr_in sin; + int on; + + if ((fd = socket (AF_INET, SOCK_STREAM, 0)) < 0) + fault("socket"); + + if (!(hostent = gethostbyname(name))) + fault("gethostbyname: %s: %s\n", name, strerror(errno)); + + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_port = htons (port); + memcpy(&sin.sin_addr.s_addr, hostent->h_addr, sizeof(struct in_addr)); + + if (connect(fd, (struct sockaddr *) &sin, sizeof (sin)) < 0) + fault("connect: %s:%u: %s\n", name, port, strerror(errno)); + + on = 1; + if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof (on)) < 0) + syslog(LOG_WARNING, "setsockopt (TCP_NODELAY): %m"); + + on = 1; + if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) + syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); + + return fd; +} + +/* + * open a tcp socket and start listening for connections on it + */ +static int startlistening(unsigned short port) +{ + int fd, on; + struct sockaddr_in sin; + + if ((fd = socket (AF_INET, SOCK_STREAM, 0)) < 0) + fault("socket"); + + on = 1; + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) < 0) + syslog(LOG_WARNING, "setsockopt (SO_REUSEADDR): %m"); + + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_port = htons (port); + sin.sin_addr.s_addr = INADDR_ANY; + if (bind(fd, &sin, sizeof(sin)) < 0) + fault("bind: %u: %s\n", port, strerror(errno)); + + if (listen(fd, 1) < 0) + fault("listen: %s\n", strerror(errno)); + + return fd; +} + +static void noblock(int fd) +{ + int on=1; + + if (ioctl(fd, FIONBIO, &on) < 0) + fault("ioctl: FIONBIO: %s\n", strerror(errno)); +} + + +/* You might not believe this, but fd_sets don't have to be a 32-bit + * integer. In particular, in glibc2 it is an array of unsigned + * longs. Hence, this hacked up FD_SET_rjb() that works out if it + * would have been a nop. */ +#define FD_SET_rjb(fd, setp) \ +do { \ + if ((fd) != 32) \ + FD_SET((fd), (setp)); \ +} while(0) + +#define FD_ISSET_rjb(fd, setp) (((fd) != 32)? FD_ISSET((fd), (setp)) : 0) + +#define MAXSIZE 256 + +/* ----------------------------------------------------------------- + * The main bit of the algorithm. Note we use 32 to mean not connected + * because this gives us 1<<32 == 0. We could have done this one + * character at a time, but that would have been very inefficient and + * not the unix way. */ +static int debug; + +static void doit(int actl, int acto, int lish, int lisg, int lisc) +{ + int acth, actg, actc; + int gdbmode = FALSE; + char gibuf[MAXSIZE], oibuf[MAXSIZE]; + char libuf[MAXSIZE], lobuf[MAXSIZE]; + char hibuf[MAXSIZE], hobuf[MAXSIZE]; + char ctlbuf[MAXSIZE]; + fd_set rdfs, wrfs, exfs; + int gicc, oicc, licc, locc, hicc, hocc, ctlcc; + char *giptr, *oiptr, *liptr, *loptr, *hiptr, *hoptr; + int rc, fromlen; + struct sockaddr_in from; + + gicc = oicc = licc = locc = hicc = hocc = ctlcc = 0; + acth = actg = actc = 32; /* XXX yummy */ + + noblock(actl); + noblock(acto); + + for(;;) + { + FD_ZERO(&rdfs); + FD_ZERO(&wrfs); + FD_ZERO(&exfs); + + /* always take input from the control port (if it's connected) */ + FD_SET_rjb(actc, &rdfs); + + if (gdbmode) + { + if (oicc) + FD_SET_rjb(actg, &wrfs); + else + FD_SET_rjb(acto, &rdfs); + + if (gicc) + FD_SET_rjb(acto, &wrfs); + else + FD_SET_rjb(actg, &rdfs); + } + else + { + /* There is no such thing as oibuf because its been split into + * lobuf and hobuf + */ + if (locc || hocc) + { + if (locc) + FD_SET_rjb(actl, &wrfs); + if (hocc) + FD_SET_rjb(acth, &wrfs); + } + else + FD_SET_rjb(acto, &rdfs); + + if (licc) + FD_SET_rjb(acto, &wrfs); + else + FD_SET_rjb(actl, &rdfs); + + if (hicc) + FD_SET_rjb(acto, &wrfs); + else + FD_SET_rjb(acth, &rdfs); + } + + if (acth == 32 && lish>=0) FD_SET_rjb(lish, &rdfs); + if (actg == 32) FD_SET_rjb(lisg, &rdfs); + if (actc == 32) FD_SET_rjb(lisc, &rdfs); + + /* now make exfs the union of the read and write fd sets, plus + * "actl" */ + { + int i; + exfs = rdfs; + for(i=0; i<32; i++) /* XXX we only copy fd numbers up to 31 */ + if (FD_ISSET(i, &wrfs)) + FD_SET_rjb(i, &exfs); + FD_SET_rjb(actl, &exfs); + } + + /* XXX AND: can't print something of type fd_set as %x - it + * might be an array */ + DB(fprintf(stderr, "%s: before select: %08x %08x %08x\n", + prog_name, rdfs, wrfs, exfs)); + + if (select(32, &rdfs, &wrfs, &exfs, NULL) < 0) + fault("select: %s\n", strerror(errno)); + + DB(fprintf(stderr, "%s: after select: %08x %08x %08x\n", + prog_name, rdfs, wrfs, exfs)); + + /* XXX it appears that a non-blocking socket may not show up + * correctly in exfs but instead goes readable with no data in + * it. Thus we check for zero and goto the appropriate close + * method. */ + + /* Deal with exceptions */ + if (FD_ISSET_rjb(actg, &exfs)) + { + exfs_actg: + close(actg); + gdbmode = FALSE; + oicc = 0; + oiptr = oibuf; + actg = 32; + continue; /* because assumptions changed */ + } + if (FD_ISSET_rjb(acth, &exfs)) + { + exfs_acth: + close(acth); + hicc = hocc = 0; + hiptr = hibuf; + hoptr = hibuf; + acth = 32; + continue; /* because assumptions changed */ + } + if (FD_ISSET_rjb(actl, &exfs) || + FD_ISSET_rjb(acto, &exfs)) + { + exfs_actl: + exfs_acto: + /* Thats all folks ... */ + break; + } + if (FD_ISSET_rjb(actc, &exfs)) + { + exfs_ctl: + close(actc); + actc = 32; + ctlcc = 0; + continue; + } + + /* Deal with reading */ + if (FD_ISSET_rjb(acto, &rdfs)) + { + if ((oicc = read(acto, oiptr = oibuf, MAXSIZE)) < 0) + fault("read acto: %d: %s\n", oicc, strerror(errno)); + if (!oicc) goto exfs_acto; + + if (!gdbmode) + { + int t; + + assert((locc == 0) && (hocc == 0)); + loptr = lobuf; + hoptr = hobuf; + + if (lish>=0) { + for(t=0; t=0 && (FD_ISSET_rjb(lish, &rdfs))) + { + fromlen = sizeof(from); + if ((acth = accept(lish, &from, &fromlen)) < 0) + { + syslog(LOG_WARNING, "accept: %m"); + acth = 32; + } + else + { + noblock(acth); + hicc = hocc = 0; + syslog(LOG_INFO, "highbit client peer is %s:%u\n", + inet_ntoa(from.sin_addr), ntohs(from.sin_port)); + } + } + + if ((actg == 32) && (FD_ISSET_rjb(lisg, &rdfs))) + { + fromlen = sizeof(from); + if ((actg = accept(lisg, &from, &fromlen)) < 0) + { + syslog(LOG_WARNING, "accept: %m"); + actg = 32; + } + else + { + noblock(actg); + gicc = 0; + gdbmode = TRUE; + syslog(LOG_INFO, "gdb client peer is %s:%u\n", + inet_ntoa(from.sin_addr), ntohs(from.sin_port)); + } + } + + if ((actc == 32) && (FD_ISSET_rjb(lisc, &rdfs))) + { + fromlen = sizeof(from); + if ((actc = accept(lisc, &from, &fromlen)) < 0) + { + syslog(LOG_WARNING, "accept (ctl): %m"); + actc = 32; + } + else + { + noblock(actc); + syslog(LOG_INFO, "ctl client peer is %s:%u\n", + inet_ntoa(from.sin_addr), ntohs(from.sin_port)); + } + } + + /* Back to top of loop */ + } + + /* We are bailing because one of the primary connections has gone + * away. We close these all explicitly here because that way the + * timeout on reusing the port numbers is smnaller. */ + + close(acth); + close(actg); + /* XXX AND: why are we closing all these "character counts" ?? */ + close(gicc); + close(oicc); + close(licc); + close(locc); + close(hicc); + close(hocc); +} + +/* + * ------------------------------------------------------------ + */ +int main(int argc, char **argv) +{ + /* In general, suffix "l" is low channel, "h" is high channel, "g" + * is gdb channel, "c" is control channel and "o" is output channel. + */ + struct sockaddr_in from; + int infd = 0, outfd; + unsigned short portl, porth, portg, portc, porto; + int on = 1, c; + char *outname, *outservice; + int fromlen; + int lish, lisg, lisc; +#if 0 + FILE *newerr; +#endif /* 0 */ + + prog_name = argv[0]; + + if (isatty(infd)) + usage(); + + /* Here, then not just a simple idiot. */ + + signal(SIGPIPE, SIG_IGN); + + openlog(prog_name, LOG_PID, LOG_DAEMON); + + fromlen = sizeof(from); + if (getsockname(infd, &from, &fromlen) < 0) + fault("getsockname: %s", strerror(errno)); + if ((fromlen != sizeof(from)) || (from.sin_family != AF_INET)) + fault("not an inet socket (family=%d)\n", from.sin_family); + + portl = ntohs(from.sin_port); + porth = portl+1; + portg = porth+1; + portc = portg+1; + + fromlen = sizeof(from); + if (getpeername(infd, &from, &fromlen) < 0) + fault("getpeername: %s", strerror(errno)); + if ((fromlen != sizeof(from)) || (from.sin_family != AF_INET)) + fault("not an inet socket (family=%d)\n", from.sin_family); + + syslog(LOG_INFO, "on port %u peer is %s:%u\n", portl, + inet_ntoa(from.sin_addr), ntohs(from.sin_port)); + + if (setsockopt(infd, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) + syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); + + /* from here on, we map stderr to output on the connection so we can + * report errors to the remote user. + */ +#if 0 + if (!(newerr = fdopen(infd, "w"))) + syslog(LOG_WARNING, "fdopen: %m"); + else + *stderr = *newerr; +#endif + + while((c = getopt(argc, argv, "d8h:g:c:")) != EOF) + { + switch(c) + { + case 'd': + debug++; + break; + + case 'h': + /* high bit port */ + if (getservice(optarg, &porth) < 0) + fault("getservice failed (high port '%s')\n", optarg); + break; + + case 'g': + /* gdb port */ + if (getservice(optarg, &portg) < 0) + fault("getservice failed (gdb port '%s')\n", optarg); + break; + + case 'c': + /* control port */ + if (getservice(optarg, &portc) < 0) + fault("getservice failed (control port '%s')\n", optarg); + break; + + case '8': + /* 8-bit clean; no high port */ + porth=0; + break; + + default: + fault("bad argument list!\n"); + } + } + + if (argc != optind + 1) + fault("unparsed arguments (%d!=%d)\n", argc, optind+1); + + outname = argv[optind]; + if (!(outservice = strchr(outname, ':'))) + fault("output arg '%s' doesn't contain ':'\n", outname); + *outservice++ = 0; + if (getservice(outservice, &porto) < 0) + fault("getservice failed (output port '%s')\n", outservice); + + /* Time to start the sockets */ + + if (porth) { + lish = startlistening(porth); + } else { + lish = -1; + } + lisg = startlistening(portg); + lisc = startlistening(portc); + + outfd = connect_host(outname, porto); + + doit(infd, outfd, lish, lisg, lisc); + + syslog(LOG_INFO, "terminating normally\n"); + + fclose(stderr); + + closelog(); + exit(0); +} + +/* End $Id: nsplitd.c,v 2.6 1998/09/17 14:28:37 sde1000 Exp $ */ From d479cd810edc7596e3843f06a3aff5039070e753 Mon Sep 17 00:00:00 2001 From: "kaf24@scramble.cl.cam.ac.uk" Date: Fri, 2 Jul 2004 08:53:06 +0000 Subject: [PATCH 14/36] bitkeeper revision 1.1041.6.2 (40e52272y6_U6CzuMhfEqO8UT-l_fA) doc fix --- docs/HOWTOs/XenDebugger-HOWTO | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/HOWTOs/XenDebugger-HOWTO b/docs/HOWTOs/XenDebugger-HOWTO index 8d5dc69e69..1aba294abb 100644 --- a/docs/HOWTOs/XenDebugger-HOWTO +++ b/docs/HOWTOs/XenDebugger-HOWTO @@ -77,7 +77,7 @@ Serial Port Configuration one stream (without the high bit) is the console and one stream (with the high bit stripped) is the pdb communication. - See: xeno.bk/tools/nsplitd + See: xeno.bk/tools/misc/nsplitd nsplitd configuration --------------------- @@ -107,7 +107,7 @@ Serial Port Configuration characters received. You can connect to the nsplitd using - 'tools/xenctl/lib/console_client.py ' + 'tools/misc/xencons ' GDB 6.0 pdb has been tested with gdb 6.0. It should also work with From 6ce830f58a290214b431378cb0cbe8c33624945a Mon Sep 17 00:00:00 2001 From: "mjw@wray-m-3.hpl.hp.com" Date: Fri, 2 Jul 2004 09:22:56 +0000 Subject: [PATCH 15/36] bitkeeper revision 1.1041.3.3 (40e52970DgkhtxD_Mq--sUEE6uPUZg) Change console cleanup for domains so that it gets called when the domain channel goes away. Stops console listeners hanging around. --- tools/python/xen/xend/server/blkif.py | 3 - tools/python/xen/xend/server/channel.py | 6 +- tools/python/xen/xend/server/console.py | 73 ++++++++++++++++------ tools/python/xen/xend/server/controller.py | 2 +- tools/python/xen/xend/server/netif.py | 5 +- 5 files changed, 62 insertions(+), 27 deletions(-) diff --git a/tools/python/xen/xend/server/blkif.py b/tools/python/xen/xend/server/blkif.py index 7310494377..d265ae382e 100755 --- a/tools/python/xen/xend/server/blkif.py +++ b/tools/python/xen/xend/server/blkif.py @@ -210,9 +210,6 @@ class BlkifController(controller.Controller): self.evtchn['port2']]) return val - def lostChannel(self): - controller.Controller.lostChannel(self) - def getDevices(self): return self.devices.values() diff --git a/tools/python/xen/xend/server/channel.py b/tools/python/xen/xend/server/channel.py index 0c9d316dec..caaa66e28c 100755 --- a/tools/python/xen/xend/server/channel.py +++ b/tools/python/xen/xend/server/channel.py @@ -174,9 +174,9 @@ class VirqChannel(BaseChannel): """Close the channel. Calls lostChannel(self) on all its clients and channelClosed() on the factory. """ - for c in self.clients: + for c in self.clients[:]: c.lostChannel(self) - del self.clients + self.clients = [] BaseChannel.close(self) def registerClient(self, client): @@ -238,7 +238,7 @@ class Channel(BaseChannel): """ if self.closed: return self.closed = 1 - for d in self.devs: + for d in self.devs[:]: d.lostChannel() self.factory.channelClosed(self) self.devs = [] diff --git a/tools/python/xen/xend/server/console.py b/tools/python/xen/xend/server/console.py index 336ccacca0..77f6343c3d 100755 --- a/tools/python/xen/xend/server/console.py +++ b/tools/python/xen/xend/server/console.py @@ -93,10 +93,15 @@ class ConsoleController(controller.Controller): output and the connected TCP sockets to post console input. """ + STATUS_NEW = 'new' + STATUS_CLOSED = 'closed' + STATUS_CONNECTED = 'connected' + STATUS_LISTENING = 'listening' + def __init__(self, factory, dom, console_port): controller.Controller.__init__(self, factory, dom) self.majorTypes = [ CMSG_CONSOLE ] - self.status = "new" + self.status = self.STATUS_NEW self.addr = None self.conn = None self.rbuf = xu.buffer() @@ -123,28 +128,31 @@ class ConsoleController(controller.Controller): return not (self.closed() or self.rbuf.empty()) def closed(self): - return self.status == 'closed' + return self.status == self.STATUS_CLOSED def connected(self): - return self.status == 'connected' + return self.status == self.STATUS_CONNECTED def close(self): - try: - self.status = "closed" - if self.conn: - self.conn.loseConnection() - self.listener.stopListening() - self.deregisterChannel() - self.lostChannel() - except Exception, ex: - print 'ConsoleController>close>', ex - raise + """Close the console controller. + """ + self.lostChannel() + + def lostChannel(self): + """The channel to the domain has been lost. + Cleanup: disconnect TCP connections and listeners, notify the controller. + """ + self.status = self.STATUS_CLOSED + if self.conn: + self.conn.loseConnection() + self.listener.stopListening() + controller.Controller.lostChannel(self) def listen(self): """Listen for TCP connections to the console port.. """ if self.closed(): return - self.status = "listening" + self.status = self.STATUS_LISTENING if self.listener: #self.listener.startListening() pass @@ -153,15 +161,25 @@ class ConsoleController(controller.Controller): self.listener = reactor.listenTCP(self.console_port, f) def connect(self, addr, conn): + """Connect a TCP connection to the console. + Fails if closed or already connected. + + addr peer address + conn connection + + returns 0 if ok, negative otherwise + """ if self.closed(): return -1 if self.connected(): return -1 self.addr = addr self.conn = conn - self.status = "connected" + self.status = self.STATUS_CONNECTED self.handleOutput() return 0 def disconnect(self): + """Disconnect the TCP connection to the console. + """ if self.conn: self.conn.loseConnection() self.addr = None @@ -169,15 +187,29 @@ class ConsoleController(controller.Controller): self.listen() def requestReceived(self, msg, type, subtype): + """Receive console data from the console channel. + + msg console message + type major message type + subtype minor message typ + """ self.rbuf.write(msg.get_payload()) self.handleOutput() def responseReceived(self, msg, type, subtype): - # Just ignore responses. + """Handle a response to a request written to the console channel. + Just ignore it because the return values are not interesting. + + msg console message + type major message type + subtype minor message typ + """ pass def produceRequests(self): - # Send as much pending console data as there is room for. + """Write pending console data to the console channel. + Writes as much to the channel as it can. + """ work = 0 while not self.wbuf.empty() and self.channel.writeReady(): msg = xu.message(CMSG_CONSOLE, 0, 0) @@ -187,7 +219,12 @@ class ConsoleController(controller.Controller): def handleInput(self, conn, data): """Handle some external input aimed at the console. - Called from a TCP connection (conn). + Called from a TCP connection (conn). Ignores the input + if the calling connection (conn) is not the one connected + to the console (self.conn). + + conn connection + data input data """ if self.closed(): return -1 if conn != self.conn: return 0 diff --git a/tools/python/xen/xend/server/controller.py b/tools/python/xen/xend/server/controller.py index 299bd621f6..49d6e26ea8 100755 --- a/tools/python/xen/xend/server/controller.py +++ b/tools/python/xen/xend/server/controller.py @@ -205,12 +205,12 @@ class Controller(CtrlMsgRcvr): def close(self): """Close the controller. """ - self.deregisterChannel() self.lostChannel() def lostChannel(self): """The controller channel has been lost. """ + self.deregisterChannel() self.factory.instanceClosed(self) class Dev: diff --git a/tools/python/xen/xend/server/netif.py b/tools/python/xen/xend/server/netif.py index 5760552e8b..0096511b7c 100755 --- a/tools/python/xen/xend/server/netif.py +++ b/tools/python/xen/xend/server/netif.py @@ -198,8 +198,9 @@ class NetifController(controller.Controller): def randomMAC(self): """Generate a random MAC address. - The OUI (Organisation Unique Identifier) used is AA:00:00, which - is a currently unassigned one that used to belong to DEC. + Uses OUI (Organizationally Unique Identifier) AA:00:00, an + unassigned one that used to belong to DEC. The OUI list is + available at 'standards.ieee.org'. The remaining 3 fields are random, with the first bit of the first random field set 0. From dc2ff4c74341a46eefabf08b6d080a5e2a7b7201 Mon Sep 17 00:00:00 2001 From: "mjw@wray-m-3.hpl.hp.com" Date: Fri, 2 Jul 2004 09:32:24 +0000 Subject: [PATCH 16/36] bitkeeper revision 1.1041.3.4 (40e52ba8BG52Ja01pk085Hoa4GWGqQ) Fix headers. --- tools/libxutil/Makefile | 2 +- tools/libxutil/allocate.h | 6 +++--- tools/libxutil/debug.h | 6 +++--- tools/libxutil/file_stream.h | 6 +++--- tools/libxutil/gzip_stream.c | 1 - tools/libxutil/gzip_stream.h | 7 +++---- tools/libxutil/kernel_stream.h | 6 +++--- tools/libxutil/string_stream.h | 7 +++---- tools/libxutil/sys_ctype.h | 6 +++--- tools/libxutil/sys_net.h | 6 +++--- tools/libxutil/sys_string.h | 6 +++--- 11 files changed, 28 insertions(+), 31 deletions(-) diff --git a/tools/libxutil/Makefile b/tools/libxutil/Makefile index 8ba9eb3454..8be24daa92 100644 --- a/tools/libxutil/Makefile +++ b/tools/libxutil/Makefile @@ -8,7 +8,7 @@ LIB_SRCS += allocate.c LIB_SRCS += file_stream.c LIB_SRCS += gzip_stream.c LIB_SRCS += iostream.c -LIB_SRCS += sys_net.c +#LIB_SRCS += sys_net.c LIB_SRCS += sys_string.c LIB_OBJS := $(LIB_SRCS:.c=.o) diff --git a/tools/libxutil/allocate.h b/tools/libxutil/allocate.h index 08bc67b910..391b7be2bd 100644 --- a/tools/libxutil/allocate.h +++ b/tools/libxutil/allocate.h @@ -16,8 +16,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef _XEN_LIB_ALLOCATE_H_ -#define _XEN_LIB_ALLOCATE_H_ +#ifndef _XUTIL_ALLOCATE_H_ +#define _XUTIL_ALLOCATE_H_ /** Allocate memory for a given type, and cast. */ #define ALLOCATE(ctype) (ctype *)allocate(sizeof(ctype)) @@ -33,7 +33,7 @@ extern void memzero(void *p, int size); typedef void AllocateFailedFn(int size, int type); extern AllocateFailedFn *allocate_failed_fn; -#endif /* _XEN_LIB_ALLOCATE_H_ */ +#endif /* _XUTIL_ALLOCATE_H_ */ diff --git a/tools/libxutil/debug.h b/tools/libxutil/debug.h index 4f5228faa3..69a6b49937 100644 --- a/tools/libxutil/debug.h +++ b/tools/libxutil/debug.h @@ -15,8 +15,8 @@ * along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef _XEN_LIB_DEBUG_H_ -#define _XEN_LIB_DEBUG_H_ +#ifndef _XUTIL_DEBUG_H_ +#define _XUTIL_DEBUG_H_ #ifndef MODULE_NAME #define MODULE_NAME "" @@ -69,4 +69,4 @@ */ #define IPFMT "%u.%u.%u.%u" -#endif /* ! _XEN_LIB_DEBUG_H_ */ +#endif /* ! _XUTIL_DEBUG_H_ */ diff --git a/tools/libxutil/file_stream.h b/tools/libxutil/file_stream.h index 36a0f928b2..f717656c24 100644 --- a/tools/libxutil/file_stream.h +++ b/tools/libxutil/file_stream.h @@ -16,8 +16,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef _XEN_LIB_FILE_STREAM_H_ -#define _XEN_LIB_FILE_STREAM_H_ +#ifndef _XUTIL_FILE_STREAM_H_ +#define _XUTIL_FILE_STREAM_H_ #ifndef __KERNEL__ #include "iostream.h" @@ -32,4 +32,4 @@ extern IOStream get_stream_stdin(void); extern int file_stream_setvbuf(IOStream *io, char *buf, int mode, size_t size); #endif -#endif /* !_XEN_LIB_FILE_STREAM_H_ */ +#endif /* !_XUTIL_FILE_STREAM_H_ */ diff --git a/tools/libxutil/gzip_stream.c b/tools/libxutil/gzip_stream.c index af46023f9d..a933c5ff73 100644 --- a/tools/libxutil/gzip_stream.c +++ b/tools/libxutil/gzip_stream.c @@ -1,4 +1,3 @@ -/* $Id: gzip_stream.c,v 1.4 2003/09/30 15:22:53 mjw Exp $ */ /* * Copyright (C) 2003 Hewlett-Packard Company. * diff --git a/tools/libxutil/gzip_stream.h b/tools/libxutil/gzip_stream.h index cf76d25275..fd28e39575 100644 --- a/tools/libxutil/gzip_stream.h +++ b/tools/libxutil/gzip_stream.h @@ -1,4 +1,3 @@ -#/* $Id: gzip_stream.h,v 1.3 2003/09/30 15:22:53 mjw Exp $ */ /* * Copyright (C) 2003 Hewlett-Packard Company. * @@ -17,8 +16,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef _SP_GZIP_STREAM_H_ -#define _SP_GZIP_STREAM_H_ +#ifndef _XUTIL_GZIP_STREAM_H_ +#define _XUTIL_GZIP_STREAM_H_ #ifndef __KERNEL__ #include "iostream.h" @@ -28,4 +27,4 @@ extern IOStream *gzip_stream_new(gzFile *f); extern IOStream *gzip_stream_fopen(const char *file, const char *flags); extern IOStream *gzip_stream_fdopen(int fd, const char *flags); #endif -#endif /* !_SP_FILE_STREAM_H_ */ +#endif /* !_XUTIL_GZIP_STREAM_H_ */ diff --git a/tools/libxutil/kernel_stream.h b/tools/libxutil/kernel_stream.h index be370f2a45..0f18058d59 100644 --- a/tools/libxutil/kernel_stream.h +++ b/tools/libxutil/kernel_stream.h @@ -16,8 +16,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef _XEN_LIB_KERNEL_STREAM_H_ -#define _XEN_LIB_KERNEL_STREAM_H_ +#ifndef _XUTIL_KERNEL_STREAM_H_ +#define _XUTIL_KERNEL_STREAM_H_ #ifdef __KERNEL__ #include "iostream.h" @@ -26,4 +26,4 @@ extern IOStream get_stream_kernel(void); #define get_stream_stdout get_stream_kernel #endif /* __KERNEL__ */ -#endif /* !_XEN_LIB_KERNEL_STREAM_H_ */ +#endif /* !_XUTIL_KERNEL_STREAM_H_ */ diff --git a/tools/libxutil/string_stream.h b/tools/libxutil/string_stream.h index 36d764b265..b6cbc0f3df 100644 --- a/tools/libxutil/string_stream.h +++ b/tools/libxutil/string_stream.h @@ -1,4 +1,3 @@ -/* $Id: string_stream.h,v 1.1 2003/08/22 14:25:48 mjw Exp $ */ /* * Copyright (C) 2001, 2002 Hewlett-Packard Company. * @@ -17,8 +16,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef _SP_STRING_STREAM_H_ -#define _SP_STRING_STREAM_H_ +#ifndef _XUTIL_STRING_STREAM_H_ +#define _XUTIL_STRING_STREAM_H_ #include "iostream.h" @@ -43,4 +42,4 @@ extern IOMethods *string_stream_get_methods(void); extern IOStream *string_stream_new(char *s, int n); extern void string_stream_init(IOStream *stream, StringData *data, char *s, int n); -#endif /* !_SP_STRING_STREAM_H_ */ +#endif /* !_XUTIL_STRING_STREAM_H_ */ diff --git a/tools/libxutil/sys_ctype.h b/tools/libxutil/sys_ctype.h index 1dc6cf2fac..debcc8921b 100644 --- a/tools/libxutil/sys_ctype.h +++ b/tools/libxutil/sys_ctype.h @@ -1,5 +1,5 @@ -#ifndef _XENO_SYS_CTYPE_H_ -#define _XENO_SYS_CTYPE_H_ +#ifndef _XUTIL_SYS_CTYPE_H_ +#define _XUTIL_SYS_CTYPE_H_ /** @file ** Replacement for ctype include that can be used * from user or kernel code. @@ -9,4 +9,4 @@ #else # include #endif -#endif /* ! _XENO_SYS_CTYPE_H_ */ +#endif /* ! _XUTIL_SYS_CTYPE_H_ */ diff --git a/tools/libxutil/sys_net.h b/tools/libxutil/sys_net.h index da6c1e8fd5..61754940f2 100644 --- a/tools/libxutil/sys_net.h +++ b/tools/libxutil/sys_net.h @@ -16,8 +16,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef _XEN_LIB_SYS_NET_H_ -#define _XEN_LIB_SYS_NET_H_ +#ifndef _XUTIL_SYS_NET_H_ +#define _XUTIL_SYS_NET_H_ /** @file * * Replacement for standard network includes. @@ -72,7 +72,7 @@ extern int inet_aton(const char *address, struct in_addr *inp); extern char *mac_ntoa(const unsigned char *macaddr); extern int mac_aton(const char *addr, unsigned char *macaddr); -#endif /* !_SP_SYS_NET_H_ */ +#endif /* !_XUTIL_SYS_NET_H_ */ diff --git a/tools/libxutil/sys_string.h b/tools/libxutil/sys_string.h index f39935f669..ea60401168 100644 --- a/tools/libxutil/sys_string.h +++ b/tools/libxutil/sys_string.h @@ -16,8 +16,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef _XEN_LIB_SYS_STRING_H_ -#define _XEN_LIB_SYS_STRING_H_ +#ifndef _XUTIL_SYS_STRING_H_ +#define _XUTIL_SYS_STRING_H_ /** @file * Replacement for standard string includes. * Works in user or kernel code. @@ -88,4 +88,4 @@ static inline size_t strnlen(const char *s, size_t n){ extern int convert_atoul(const char *s, unsigned long *v); extern int path_concat(char *s, char *t, char **val); -#endif /* !_XEN_LIB_SYS_STRING_H_ */ +#endif /* !_XUTIL_SYS_STRING_H_ */ From 63415e21f7b80cf75edd1270a05daefed52378e2 Mon Sep 17 00:00:00 2001 From: "kaf24@scramble.cl.cam.ac.uk" Date: Fri, 2 Jul 2004 10:03:23 +0000 Subject: [PATCH 17/36] bitkeeper revision 1.1041.6.3 (40e532ebjteJL-J2vKsGbaORF1GYvw) Better bad-cpu error report. --- xen/arch/x86/boot/x86_32.S | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/xen/arch/x86/boot/x86_32.S b/xen/arch/x86/boot/x86_32.S index ae1d72ad23..fea54c1336 100644 --- a/xen/arch/x86/boot/x86_32.S +++ b/xen/arch/x86/boot/x86_32.S @@ -19,8 +19,25 @@ ENTRY(start) /* Checksum: must be the negated sum of the first two fields. */ .long -0x1BADB004 +bad_cpu_msg: + .asciz "Bad CPU: we need at least a P6-compatible core." bad_cpu: - jmp bad_cpu + mov $SYMBOL_NAME(bad_cpu_msg)-__PAGE_OFFSET,%esi + mov $0xB8000,%edi # VGA framebuffer +1: mov (%esi),%bl + test %bl,%bl # Terminate on '\0' sentinel +2: je 2b + mov $0x3f8+5,%dx # UART Line Status Register +3: in %dx,%al + test $0x20,%al # Test THR Empty flag + je 3b + mov $0x3f8+0,%dx # UART Transmit Holding Register + mov %bl,%al + out %al,%dx # Send a character over the serial line + movsb # Write a character to the VGA framebuffer + mov $7,%al + stosb # Write an attribute to the VGA framebuffer + jmp 1b __start: /* Set up a few descriptors: on entry only CS is guaranteed good. */ From 293ffba5e172f51640d40ff47e8a4dbaeb30799e Mon Sep 17 00:00:00 2001 From: "kaf24@scramble.cl.cam.ac.uk" Date: Fri, 2 Jul 2004 10:14:27 +0000 Subject: [PATCH 18/36] bitkeeper revision 1.1041.6.4 (40e53583BjAVOWv5pUOm61mHPjnztg) Fix 'halt' in xenolinux. --- linux-2.4.26-xen-sparse/arch/xen/kernel/process.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/linux-2.4.26-xen-sparse/arch/xen/kernel/process.c b/linux-2.4.26-xen-sparse/arch/xen/kernel/process.c index aa59c37790..6d80505743 100644 --- a/linux-2.4.26-xen-sparse/arch/xen/kernel/process.c +++ b/linux-2.4.26-xen-sparse/arch/xen/kernel/process.c @@ -115,7 +115,7 @@ void cpu_idle (void) } } -void machine_restart(char * __unused) +void machine_restart(char *__unused) { /* We really want to get pending console data out before we die. */ extern void xencons_force_flush(void); @@ -128,7 +128,11 @@ void machine_halt(void) /* We really want to get pending console data out before we die. */ extern void xencons_force_flush(void); xencons_force_flush(); - HYPERVISOR_shutdown(); + for ( ; ; ) /* loop without wasting cpu cycles */ + { + HYPERVISOR_shared_info->vcpu_data[0].evtchn_upcall_pending = 0; + HYPERVISOR_block(); + } } void machine_power_off(void) From 4d106af12c2d4b9b0a6dc2bca6f5d2924752b910 Mon Sep 17 00:00:00 2001 From: "kaf24@scramble.cl.cam.ac.uk" Date: Sat, 3 Jul 2004 14:01:12 +0000 Subject: [PATCH 19/36] bitkeeper revision 1.1041.6.5 (40e6bc28spUzzcq9522VffBvuZcbag) setup.c, x86_64.S: More x86_64. --- xen/arch/x86/boot/x86_64.S | 58 +++++++++++++++++++++++++------------- xen/arch/x86/setup.c | 4 +++ 2 files changed, 43 insertions(+), 19 deletions(-) diff --git a/xen/arch/x86/boot/x86_64.S b/xen/arch/x86/boot/x86_64.S index b489734ded..46af44607c 100644 --- a/xen/arch/x86/boot/x86_64.S +++ b/xen/arch/x86/boot/x86_64.S @@ -20,20 +20,27 @@ ENTRY(start) /* Checksum: must be the negated sum of the first two fields. */ .long -0x1BADB004 +bad_cpu_msg: + .asciz "Bad CPU: does not support 64-bit (long) mode." bad_cpu: - jmp bad_cpu + mov $SYMBOL_NAME(bad_cpu_msg)-__PAGE_OFFSET,%esi + mov $0xB8000,%edi # VGA framebuffer +1: mov (%esi),%bl + test %bl,%bl # Terminate on '\0' sentinel +2: je 2b + mov $0x3f8+5,%dx # UART Line Status Register +3: in %dx,%al + test $0x20,%al # Test THR Empty flag + je 3b + mov $0x3f8+0,%dx # UART Transmit Holding Register + mov %bl,%al + out %al,%dx # Send a character over the serial line + movsb # Write a character to the VGA framebuffer + mov $7,%al + stosb # Write an attribute to the VGA framebuffer + jmp 1b __start: - /* We begin by interrogating the CPU for the presence of long mode. */ - mov $0x80000000,%eax - cpuid - cmp $0x80000000,%eax # any function > 0x80000000? - jbe bad_cpu - mov $0x80000001,%eax - cpuid - bt $29,%edx # Long mode feature? - jnc bad_cpu - /* Set up a few descriptors: on entry only CS is guaranteed good. */ lgdt %cs:nopaging_gdt_descr-__PAGE_OFFSET mov $(__HYPERVISOR_DS),%ecx @@ -48,6 +55,16 @@ __start: pushl $0 popf + /* We begin by interrogating the CPU for the presence of long mode. */ + mov $0x80000000,%eax + cpuid + cmp $0x80000000,%eax # any function > 0x80000000? + jbe bad_cpu + mov $0x80000001,%eax + cpuid + bt $29,%edx # Long mode feature? + jnc bad_cpu + /* Set up FPU. */ fninit @@ -82,7 +99,7 @@ __start: /* Initialise IDT with simple error defaults. */ lea ignore_int,%edx - mov $(__HYPERVISOR_CS << 16),%eax + mov $(__HYPERVISOR_CS64 << 16),%eax mov %dx,%ax /* selector = 0x0010 = cs */ mov $0x8E00,%dx /* interrupt gate - dpl=0, present */ lea SYMBOL_NAME(idt_table)-__PAGE_OFFSET,%edi @@ -98,16 +115,19 @@ start_paging: mov $0x80050033,%eax /* hi-to-lo: PG,AM,WP,NE,ET,MP,PE */ mov %eax,%cr0 jmp 1f +1: /* Now in compatibility mode. Long-jump into 64-bit mode. */ + ljmp $(__HYPERVISOR_CS64),$1f + + .code64 1: /* Install relocated selectors (FS/GS unused). */ lgdt gdt_descr mov $(__HYPERVISOR_DS),%ecx mov %ecx,%ds mov %ecx,%es mov %ecx,%ss - ljmp $(__HYPERVISOR_CS),$1f 1: /* Paging enabled, so we can now enable GLOBAL mappings in CR4. */ - mov mmu_cr4_features,%ecx - mov %ecx,%cr4 + mov mmu_cr4_features,%rcx + mov %rcx,%cr4 /* Relocate ESP */ add $__PAGE_OFFSET,%esp @@ -123,16 +143,18 @@ start_paging: /* This is the default interrupt handler. */ int_msg: .asciz "Unknown interrupt\n" - ALIGN ignore_int: cld mov $(__HYPERVISOR_DS),%eax mov %eax,%ds mov %eax,%es - pushl $int_msg + pushq $int_msg call SYMBOL_NAME(printf) 1: jmp 1b + .code32 + .align 8 + /*** STACK LOCATION ***/ ENTRY(stack_start) @@ -144,8 +166,6 @@ ENTRY(stack_start) .globl SYMBOL_NAME(idt) .globl SYMBOL_NAME(gdt) - ALIGN - .word 0 idt_descr: .word 256*8-1 diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index 76881db1e5..ed5f3bba67 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -28,7 +28,11 @@ extern int do_timer_lists_from_pit; char ignore_irq13; /* set if exception 16 works */ struct cpuinfo_x86 boot_cpu_data = { 0, 0, 0, 0, -1 }; +#if defined(__x86_64__) +unsigned long mmu_cr4_features = X86_CR4_PSE | X86_CR4_PGE | X86_CR4_PAE; +#else unsigned long mmu_cr4_features = X86_CR4_PSE | X86_CR4_PGE; +#endif EXPORT_SYMBOL(mmu_cr4_features); unsigned long wait_init_idle; From 393024529af7c699a3ec17ad40d7935e80b8fa13 Mon Sep 17 00:00:00 2001 From: "kaf24@scramble.cl.cam.ac.uk" Date: Mon, 5 Jul 2004 15:01:15 +0000 Subject: [PATCH 20/36] bitkeeper revision 1.1041.6.6 (40e96d3bioFNWNS55cowRl9PXLQZ9Q) More x86-64 stuff. --- .rootkeys | 15 +-- xen/arch/x86/Makefile | 5 + xen/arch/x86/Rules.mk | 2 +- xen/arch/x86/apic.c | 6 +- xen/arch/x86/{process.c => domain.c} | 11 +- xen/arch/x86/irq.c | 4 + xen/arch/x86/mpparse.c | 4 +- xen/arch/x86/rwlock.c | 12 +-- xen/arch/x86/setup.c | 10 ++ xen/arch/x86/smpboot.c | 2 + xen/arch/x86/time.c | 19 ++-- xen/arch/x86/trampoline.S | 6 +- xen/arch/x86/traps.c | 4 + xen/arch/x86/{ => x86_32}/domain_page.c | 0 xen/arch/x86/{ => x86_32}/entry.S | 0 xen/arch/x86/{ => x86_32}/mm.c | 0 xen/arch/x86/{ => x86_32}/usercopy.c | 0 xen/arch/x86/{ => x86_32}/xen.lds | 0 xen/arch/x86/x86_64/entry.S | 0 xen/arch/x86/x86_64/usercopy.c | 136 ++++++++++++++++++++++++ xen/arch/x86/x86_64/xen.lds | 85 +++++++++++++++ xen/include/asm-x86/config.h | 4 +- xen/include/asm-x86/irq.h | 24 +++-- 23 files changed, 306 insertions(+), 43 deletions(-) rename xen/arch/x86/{process.c => domain.c} (98%) rename xen/arch/x86/{ => x86_32}/domain_page.c (100%) rename xen/arch/x86/{ => x86_32}/entry.S (100%) rename xen/arch/x86/{ => x86_32}/mm.c (100%) rename xen/arch/x86/{ => x86_32}/usercopy.c (100%) rename xen/arch/x86/{ => x86_32}/xen.lds (100%) create mode 100644 xen/arch/x86/x86_64/entry.S create mode 100644 xen/arch/x86/x86_64/usercopy.c create mode 100644 xen/arch/x86/x86_64/xen.lds diff --git a/.rootkeys b/.rootkeys index c575ef31d3..3adfa562aa 100644 --- a/.rootkeys +++ b/.rootkeys @@ -286,8 +286,7 @@ 3ddb79bcSC_LvnmFlX-T5iTgaR0SKg xen/arch/x86/boot/x86_32.S 40e42bdbNu4MjI750THP_8J1S-Sa0g xen/arch/x86/boot/x86_64.S 3ddb79bcUrk2EIaM5VsT6wUudH1kkg xen/arch/x86/delay.c -3e32af9aRnYGl4GMOaDKp7JdfhOGhg xen/arch/x86/domain_page.c -3ddb79bcecupHj56ZbTa3B0FxDowMg xen/arch/x86/entry.S +3ddb79bc1_2bAt67x9MFCP4AZrQnvQ xen/arch/x86/domain.c 3ddb79bcY5zW7KhvI9gvfuPi3ZumEg xen/arch/x86/extable.c 3fe443fdDDb0Sw6NQBCk4GQapayfTA xen/arch/x86/flushtlb.c 3ddb79bcesE5E-lS4QhRhlqXxqj9cA xen/arch/x86/i387.c @@ -295,7 +294,6 @@ 3ddb79bcBit4xJXbwtX0kb1hh2uO1Q xen/arch/x86/idle0_task.c 3ddb79bcKIkRR0kqWaJhe5VUDkMdxg xen/arch/x86/io_apic.c 3ddb79bdqfIcjkz_h9Hvtp8Tk_19Zw xen/arch/x86/irq.c -3ddb79bcHwuCQDjBICDTSis52hWguw xen/arch/x86/mm.c 3ddb79bdS4UeWWXDH-FaBKqcpMFcnw xen/arch/x86/mpparse.c 3f12cff65EV3qOG2j37Qm0ShgvXGRw xen/arch/x86/nmi.c 3ddb79bdHe6_Uij4-glW91vInNtBYQ xen/arch/x86/pci-irq.c @@ -304,7 +302,6 @@ 3ddb79bdIKgipvGoqExEQ7jawfVowA xen/arch/x86/pci-x86.h 40a4dfced2dnSzbKgJFlD3chKHexjQ xen/arch/x86/pdb-linux.c 4022a73czgX7d-2zfF_cb33oVemApQ xen/arch/x86/pdb-stub.c -3ddb79bc1_2bAt67x9MFCP4AZrQnvQ xen/arch/x86/process.c 3ddb79bc7KxGCEJsgBnkDX7XjD_ZEQ xen/arch/x86/rwlock.c 3ddb79bcrD6Z_rUvSDgrvjyb4846Eg xen/arch/x86/setup.c 3ddb79bcSx2e8JSR3pdSGa8x1ScYzA xen/arch/x86/smp.c @@ -312,8 +309,14 @@ 3ddb79bc-Udq7ol-NX4q9XsYnN7A2Q xen/arch/x86/time.c 3ddb79bccYVzXZJyVaxuv5T42Z1Fsw xen/arch/x86/trampoline.S 3ddb79bcOftONV9h4QCxXOfiT0h91w xen/arch/x86/traps.c -3ddb79bc4nTpGQOe6_-MbyZzkhlhFQ xen/arch/x86/usercopy.c -3ddb79bcOMCu9-5mKpjIh5d0qqBDPg xen/arch/x86/xen.lds +3e32af9aRnYGl4GMOaDKp7JdfhOGhg xen/arch/x86/x86_32/domain_page.c +3ddb79bcecupHj56ZbTa3B0FxDowMg xen/arch/x86/x86_32/entry.S +3ddb79bcHwuCQDjBICDTSis52hWguw xen/arch/x86/x86_32/mm.c +3ddb79bc4nTpGQOe6_-MbyZzkhlhFQ xen/arch/x86/x86_32/usercopy.c +3ddb79bcOMCu9-5mKpjIh5d0qqBDPg xen/arch/x86/x86_32/xen.lds +40e96d3aLDI-nViMuYneD7VKYlZrVg xen/arch/x86/x86_64/entry.S +40e96d3ahBTZqbTViInnq0lM03vs7A xen/arch/x86/x86_64/usercopy.c +40e96d3akN3Hu_J5Bk-WXD8OGscrYQ xen/arch/x86/x86_64/xen.lds 3ddb79bdff-gj-jFGKjOejeHLqL8Lg xen/common/Makefile 3e397e66AyyD5fYraAySWuwi9uqSXg xen/common/ac_timer.c 4022a73c_BbDFd2YJ_NQYVvKX5Oz7w xen/common/debug-linux.c diff --git a/xen/arch/x86/Makefile b/xen/arch/x86/Makefile index f6ef36afce..039df504ef 100644 --- a/xen/arch/x86/Makefile +++ b/xen/arch/x86/Makefile @@ -6,6 +6,9 @@ OBJS := $(subst pdb-linux.o,,$(OBJS)) OBJS := $(subst pdb-stub.o,,$(OBJS)) endif +OBJS += $(patsubst %.S,%.o,$(wildcard $(TARGET_SUBARCH)/*.S)) +OBJS += $(patsubst %.c,%.o,$(wildcard $(TARGET_SUBARCH)/*.c)) + LINK_BASE := 0xFC500000 # Xen is linked here LOAD_BASE := 0x00100000 # Xen is loaded here @@ -23,3 +26,5 @@ default: boot/$(TARGET_SUBARCH).o $(OBJS) clean: rm -f *.o *~ core boot/*.o boot/*~ boot/core + rm -f $(TARGET_SUBARCH)/*.o $(TARGET_SUBARCH)/*~ + rm -f $(TARGETSUBARCH)/core diff --git a/xen/arch/x86/Rules.mk b/xen/arch/x86/Rules.mk index 5963e99d80..560b381845 100644 --- a/xen/arch/x86/Rules.mk +++ b/xen/arch/x86/Rules.mk @@ -8,7 +8,7 @@ CFLAGS := -nostdinc -fno-builtin -fno-common -fno-strict-aliasing -O3 CFLAGS += -iwithprefix include -Wall -Werror -fomit-frame-pointer CFLAGS += -I$(BASEDIR)/include -Wno-pointer-arith -Wredundant-decls -LDFLAGS := -T xen.lds -N +LDFLAGS := -T $(TARGET_SUBARCH)/xen.lds -N ifeq ($(TARGET_SUBARCH),x86_32) CFLAGS += -m32 -march=i686 diff --git a/xen/arch/x86/apic.c b/xen/arch/x86/apic.c index cd1733c173..64974f670d 100644 --- a/xen/arch/x86/apic.c +++ b/xen/arch/x86/apic.c @@ -491,9 +491,9 @@ void __init init_apic_mappings(void) *****************************************************************************/ /* used for system time scaling */ -static unsigned int bus_freq; -static u32 bus_cycle; /* length of one bus cycle in pico-seconds */ -static u32 bus_scale; /* scaling factor convert ns to bus cycles */ +static unsigned long bus_freq; /* KAF: pointer-size avoids compile warns. */ +static u32 bus_cycle; /* length of one bus cycle in pico-seconds */ +static u32 bus_scale; /* scaling factor convert ns to bus cycles */ /* * The timer chip is already set up at HZ interrupts per second here, diff --git a/xen/arch/x86/process.c b/xen/arch/x86/domain.c similarity index 98% rename from xen/arch/x86/process.c rename to xen/arch/x86/domain.c index d3bf5ab4b8..459a85b393 100644 --- a/xen/arch/x86/process.c +++ b/xen/arch/x86/domain.c @@ -1,17 +1,10 @@ /* - * linux/arch/i386/kernel/process.c - * * Copyright (C) 1995 Linus Torvalds * * Pentium III FXSR, SSE support * Gareth Hughes , May 2000 */ -/* - * This file handles the architecture-dependent parts of process handling.. - */ - -#define __KERNEL_SYSCALLS__ #include #include #include @@ -192,6 +185,8 @@ void machine_power_off(void) machine_restart(0); } +#if defined(__i386__) + void new_thread(struct domain *p, unsigned long start_pc, unsigned long start_stack, @@ -361,3 +356,5 @@ long do_iopl(domid_t domain, unsigned int new_io_pl) ec->eflags = (ec->eflags & 0xffffcfff) | ((new_io_pl&3) << 12); return 0; } + +#endif diff --git a/xen/arch/x86/irq.c b/xen/arch/x86/irq.c index 950138849b..af0b0de1fb 100644 --- a/xen/arch/x86/irq.c +++ b/xen/arch/x86/irq.c @@ -89,7 +89,11 @@ void enable_irq(unsigned int irq) asmlinkage void do_IRQ(struct pt_regs regs) { +#if defined(__i386__) unsigned int irq = regs.orig_eax; +#else + unsigned int irq = 0; /* XXX */ +#endif irq_desc_t *desc = &irq_desc[irq]; struct irqaction *action; diff --git a/xen/arch/x86/mpparse.c b/xen/arch/x86/mpparse.c index ae1e1da93b..d10e4ce9dd 100644 --- a/xen/arch/x86/mpparse.c +++ b/xen/arch/x86/mpparse.c @@ -458,7 +458,7 @@ static int __init smp_read_mpc(struct mp_config_table *mpc) if ((clustered_apic_mode == CLUSTERED_APIC_NUMAQ) && mpc->mpc_oemptr) { /* We need to process the oem mpc tables to tell us which quad things are in ... */ mpc_record = 0; - smp_read_mpc_oem((struct mp_config_oemtable *) mpc->mpc_oemptr, mpc->mpc_oemsize); + smp_read_mpc_oem((struct mp_config_oemtable *)(unsigned long)mpc->mpc_oemptr, mpc->mpc_oemsize); mpc_record = 0; } @@ -824,7 +824,7 @@ void __init get_smp_config (void) * Read the physical hardware table. Anything here will * override the defaults. */ - if (!smp_read_mpc((void *)mpf->mpf_physptr)) { + if (!smp_read_mpc((void *)(unsigned long)mpf->mpf_physptr)) { smp_found_config = 0; printk(KERN_ERR "BIOS bug, MP table errors detected!...\n"); printk(KERN_ERR "... disabling SMP support. (tell your hw vendor)\n"); diff --git a/xen/arch/x86/rwlock.c b/xen/arch/x86/rwlock.c index 2ef7af16b1..d8c1b7dde5 100644 --- a/xen/arch/x86/rwlock.c +++ b/xen/arch/x86/rwlock.c @@ -6,22 +6,22 @@ asm( ".align 4\n" ".globl __write_lock_failed\n" "__write_lock_failed:\n" -" " LOCK "addl $" RW_LOCK_BIAS_STR ",(%eax)\n" +" " LOCK "addl $" RW_LOCK_BIAS_STR ",(%"__OP"ax)\n" "1: rep; nop\n" -" cmpl $" RW_LOCK_BIAS_STR ",(%eax)\n" +" cmpl $" RW_LOCK_BIAS_STR ",(%"__OP"ax)\n" " jne 1b\n" -" " LOCK "subl $" RW_LOCK_BIAS_STR ",(%eax)\n" +" " LOCK "subl $" RW_LOCK_BIAS_STR ",(%"__OP"ax)\n" " jnz __write_lock_failed\n" " ret\n" ".align 4\n" ".globl __read_lock_failed\n" "__read_lock_failed:\n" -" lock ; incl (%eax)\n" +" lock ; incl (%"__OP"ax)\n" "1: rep; nop\n" -" cmpl $1,(%eax)\n" +" cmpl $1,(%"__OP"ax)\n" " js 1b\n" -" lock ; decl (%eax)\n" +" lock ; decl (%"__OP"ax)\n" " js __read_lock_failed\n" " ret\n" ); diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index ed5f3bba67..831a27e092 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -54,6 +54,8 @@ int acpi_force __initdata = 0; int phys_proc_id[NR_CPUS]; int logical_proc_id[NR_CPUS]; +#if defined(__i386__) + /* Standard macro to see if a specific flag is changeable */ static inline int flag_is_changeable_p(u32 flag) { @@ -81,6 +83,12 @@ static int __init have_cpuid_p(void) return flag_is_changeable_p(X86_EFLAGS_ID); } +#elif defined(__x86_64__) + +#define have_cpuid_p() (1) + +#endif + void __init get_cpu_vendor(struct cpuinfo_x86 *c) { char *v = c->x86_vendor_id; @@ -259,6 +267,7 @@ void __init identify_cpu(struct cpuinfo_x86 *c) unsigned long cpu_initialized; void __init cpu_init(void) { +#if defined(__i386__) /* XXX */ int nr = smp_processor_id(); struct tss_struct * t = &init_tss[nr]; @@ -297,6 +306,7 @@ void __init cpu_init(void) write_ptbase(¤t->mm); init_idle_task(); +#endif } static void __init do_initcalls(void) diff --git a/xen/arch/x86/smpboot.c b/xen/arch/x86/smpboot.c index 6a643ada24..ef7a39df89 100644 --- a/xen/arch/x86/smpboot.c +++ b/xen/arch/x86/smpboot.c @@ -659,7 +659,9 @@ static void __init do_boot_cpu (int apicid) map_cpu_to_boot_apicid(cpu, apicid); +#if defined(__i386__) SET_DEFAULT_FAST_TRAP(&idle->thread); +#endif idle_task[cpu] = idle; diff --git a/xen/arch/x86/time.c b/xen/arch/x86/time.c index dec7618ed7..dfe20e415d 100644 --- a/xen/arch/x86/time.c +++ b/xen/arch/x86/time.c @@ -107,7 +107,8 @@ static struct irqaction irq0 = { timer_interrupt, "timer", NULL}; static unsigned long __init calibrate_tsc(void) { - unsigned long startlow, starthigh, endlow, endhigh, count; + u64 start, end, diff; + unsigned long count; /* Set the Gate high, disable speaker */ outb((inb(0x61) & ~0x02) | 0x01, 0x61); @@ -123,22 +124,24 @@ static unsigned long __init calibrate_tsc(void) outb(CALIBRATE_LATCH & 0xff, 0x42); /* LSB of count */ outb(CALIBRATE_LATCH >> 8, 0x42); /* MSB of count */ - rdtsc(startlow, starthigh); + rdtscll(start); for ( count = 0; (inb(0x61) & 0x20) == 0; count++ ) continue; - rdtsc(endlow, endhigh); + rdtscll(end); /* Error if the CTC doesn't behave itself. */ if ( count == 0 ) return 0; - /* [endhigh:endlow] = [endhigh:endlow] - [starthigh:startlow] */ - __asm__( "subl %2,%0 ; sbbl %3,%1" - : "=a" (endlow), "=d" (endhigh) - : "g" (startlow), "g" (starthigh), "0" (endlow), "1" (endhigh) ); + diff = end - start; +#if defined(_i386__) /* If quotient doesn't fit in 32 bits then we return error (zero). */ - return endhigh ? 0 : endlow; + if ( diff & ~0xffffffffULL ) + return 0; +#endif + + return (unsigned long)diff; } diff --git a/xen/arch/x86/trampoline.S b/xen/arch/x86/trampoline.S index 064159046d..02018f347a 100644 --- a/xen/arch/x86/trampoline.S +++ b/xen/arch/x86/trampoline.S @@ -43,7 +43,11 @@ r_base = . lmsw %ax # into protected mode jmp flush_instr flush_instr: - ljmpl $__HYPERVISOR_CS, $0x100000 # 1MB +#if defined(__x86_64__) + ljmpl $__HYPERVISOR_CS32, $0x100000 # 1MB +#else + ljmpl $__HYPERVISOR_CS, $0x100000 # 1MB +#endif idt_48: .word 0 # idt limit = 0 diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c index 59d0e320d6..c43aafea23 100644 --- a/xen/arch/x86/traps.c +++ b/xen/arch/x86/traps.c @@ -62,6 +62,8 @@ struct guest_trap_bounce { unsigned long eip; /* 12 */ } guest_trap_bounce[NR_CPUS] = { { 0 } }; +#if defined(__i386__) + #define DOUBLEFAULT_STACK_SIZE 1024 static struct tss_struct doublefault_tss; static unsigned char doublefault_stack[DOUBLEFAULT_STACK_SIZE]; @@ -906,3 +908,5 @@ unsigned long do_get_debugreg(int reg) if ( (reg < 0) || (reg > 7) ) return -EINVAL; return current->thread.debugreg[reg]; } + +#endif /* __i386__ */ diff --git a/xen/arch/x86/domain_page.c b/xen/arch/x86/x86_32/domain_page.c similarity index 100% rename from xen/arch/x86/domain_page.c rename to xen/arch/x86/x86_32/domain_page.c diff --git a/xen/arch/x86/entry.S b/xen/arch/x86/x86_32/entry.S similarity index 100% rename from xen/arch/x86/entry.S rename to xen/arch/x86/x86_32/entry.S diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/x86_32/mm.c similarity index 100% rename from xen/arch/x86/mm.c rename to xen/arch/x86/x86_32/mm.c diff --git a/xen/arch/x86/usercopy.c b/xen/arch/x86/x86_32/usercopy.c similarity index 100% rename from xen/arch/x86/usercopy.c rename to xen/arch/x86/x86_32/usercopy.c diff --git a/xen/arch/x86/xen.lds b/xen/arch/x86/x86_32/xen.lds similarity index 100% rename from xen/arch/x86/xen.lds rename to xen/arch/x86/x86_32/xen.lds diff --git a/xen/arch/x86/x86_64/entry.S b/xen/arch/x86/x86_64/entry.S new file mode 100644 index 0000000000..e69de29bb2 diff --git a/xen/arch/x86/x86_64/usercopy.c b/xen/arch/x86/x86_64/usercopy.c new file mode 100644 index 0000000000..e7c11fa501 --- /dev/null +++ b/xen/arch/x86/x86_64/usercopy.c @@ -0,0 +1,136 @@ +/* + * User address space access functions. + * + * Copyright 1997 Andi Kleen + * Copyright 1997 Linus Torvalds + * Copyright 2002 Andi Kleen + */ +#include + +/* + * Copy a null terminated string from userspace. + */ + +#define __do_strncpy_from_user(dst,src,count,res) \ +do { \ + long __d0, __d1, __d2; \ + __asm__ __volatile__( \ + " testq %1,%1\n" \ + " jz 2f\n" \ + "0: lodsb\n" \ + " stosb\n" \ + " testb %%al,%%al\n" \ + " jz 1f\n" \ + " decq %1\n" \ + " jnz 0b\n" \ + "1: subq %1,%0\n" \ + "2:\n" \ + ".section .fixup,\"ax\"\n" \ + "3: movq %5,%0\n" \ + " jmp 2b\n" \ + ".previous\n" \ + ".section __ex_table,\"a\"\n" \ + " .align 8\n" \ + " .quad 0b,3b\n" \ + ".previous" \ + : "=r"(res), "=c"(count), "=&a" (__d0), "=&S" (__d1), \ + "=&D" (__d2) \ + : "i"(-EFAULT), "0"(count), "1"(count), "3"(src), "4"(dst) \ + : "memory"); \ +} while (0) + +long +__strncpy_from_user(char *dst, const char *src, long count) +{ + long res; + __do_strncpy_from_user(dst, src, count, res); + return res; +} + +long +strncpy_from_user(char *dst, const char *src, long count) +{ + long res = -EFAULT; + if (access_ok(VERIFY_READ, src, 1)) + __do_strncpy_from_user(dst, src, count, res); + return res; +} + +/* + * Zero Userspace + */ + +unsigned long __clear_user(void *addr, unsigned long size) +{ + long __d0; + /* no memory constraint because it doesn't change any memory gcc knows + about */ + asm volatile( + " testq %[size8],%[size8]\n" + " jz 4f\n" + "0: movq %[zero],(%[dst])\n" + " addq %[eight],%[dst]\n" + " decl %%ecx ; jnz 0b\n" + "4: movq %[size1],%%rcx\n" + " testl %%ecx,%%ecx\n" + " jz 2f\n" + "1: movb %b[zero],(%[dst])\n" + " incq %[dst]\n" + " decl %%ecx ; jnz 1b\n" + "2:\n" + ".section .fixup,\"ax\"\n" + "3: lea 0(%[size1],%[size8],8),%[size8]\n" + " jmp 2b\n" + ".previous\n" + ".section __ex_table,\"a\"\n" + " .align 8\n" + " .quad 0b,3b\n" + " .quad 1b,2b\n" + ".previous" + : [size8] "=c"(size), [dst] "=&D" (__d0) + : [size1] "r"(size & 7), "[size8]" (size / 8), "[dst] "(addr), + [zero] "r" (0UL), [eight] "r" (8UL)); + return size; +} + + +unsigned long clear_user(void *to, unsigned long n) +{ + if (access_ok(VERIFY_WRITE, to, n)) + return __clear_user(to, n); + return n; +} + +/* + * Return the size of a string (including the ending 0) + * + * Return 0 on exception, a value greater than N if too long + */ + +long strnlen_user(const char *s, long n) +{ + unsigned long res = 0; + char c; + + if (!access_ok(VERIFY_READ, s, n)) + return 0; + + while (1) { + if (get_user(c, s)) + return 0; + if (!c) + return res+1; + if (res>n) + return n+1; + res++; + s++; + } +} + +unsigned long copy_in_user(void *to, const void *from, unsigned len) +{ + if (access_ok(VERIFY_WRITE, to, len) && access_ok(VERIFY_READ, from, len)) { + return copy_user_generic(to, from, len); + } + return len; +} diff --git a/xen/arch/x86/x86_64/xen.lds b/xen/arch/x86/x86_64/xen.lds new file mode 100644 index 0000000000..caea240e52 --- /dev/null +++ b/xen/arch/x86/x86_64/xen.lds @@ -0,0 +1,85 @@ +/* Excerpts written by Martin Mares */ +OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64") +OUTPUT_ARCH(i386:x86-64) +ENTRY(start) +SECTIONS +{ + . = 0xFFFF840000100000; + _text = .; /* Text and read-only data */ + .text : { + *(.text) + *(.fixup) + *(.gnu.warning) + } = 0x9090 + .text.lock : { *(.text.lock) } /* out-of-line lock text */ + + _etext = .; /* End of text section */ + + .rodata : { *(.rodata) *(.rodata.*) } + .kstrtab : { *(.kstrtab) } + + . = ALIGN(16); /* Exception table */ + __start___ex_table = .; + __ex_table : { *(__ex_table) } + __stop___ex_table = .; + + __start___ksymtab = .; /* Kernel symbol table */ + __ksymtab : { *(__ksymtab) } + __stop___ksymtab = .; + + __start___kallsyms = .; /* All kernel symbols */ + __kallsyms : { *(__kallsyms) } + __stop___kallsyms = .; + + .data : { /* Data */ + *(.data) + CONSTRUCTORS + } + + _edata = .; /* End of data section */ + + . = ALIGN(8192); /* init_task */ + .data.init_task : { *(.data.init_task) } + + . = ALIGN(4096); /* Init code and data */ + __init_begin = .; + .text.init : { *(.text.init) } + .data.init : { *(.data.init) } + . = ALIGN(16); + __setup_start = .; + .setup.init : { *(.setup.init) } + __setup_end = .; + __initcall_start = .; + .initcall.init : { *(.initcall.init) } + __initcall_end = .; + . = ALIGN(4096); + __init_end = .; + + . = ALIGN(4096); + .data.page_aligned : { *(.data.idt) } + + . = ALIGN(32); + .data.cacheline_aligned : { *(.data.cacheline_aligned) } + + __bss_start = .; /* BSS */ + .bss : { + *(.bss) + } + _end = . ; + + /* Sections to be discarded */ + /DISCARD/ : { + *(.text.exit) + *(.data.exit) + *(.exitcall.exit) + } + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } +} diff --git a/xen/include/asm-x86/config.h b/xen/include/asm-x86/config.h index f61f6aeedd..f8cd450451 100644 --- a/xen/include/asm-x86/config.h +++ b/xen/include/asm-x86/config.h @@ -18,8 +18,10 @@ #define CONFIG_ACPI_BOOT 1 #define CONFIG_PCI 1 -#define CONFIG_PCI_BIOS 1 #define CONFIG_PCI_DIRECT 1 +#if defined(__i386__) +#define CONFIG_PCI_BIOS 1 +#endif #define CONFIG_IDE 1 #define CONFIG_BLK_DEV_IDE 1 diff --git a/xen/include/asm-x86/irq.h b/xen/include/asm-x86/irq.h index 7c5212e50f..1e35752a84 100644 --- a/xen/include/asm-x86/irq.h +++ b/xen/include/asm-x86/irq.h @@ -86,6 +86,8 @@ extern char _stext, _etext; #define __STR(x) #x #define STR(x) __STR(x) +#if defined(__i386__) + #define SAVE_ALL \ "cld\n\t" \ "pushl %gs\n\t" \ @@ -105,8 +107,11 @@ extern char _stext, _etext; "movl %edx,%fs\n\t" \ "movl %edx,%gs\n\t" -#define IRQ_NAME2(nr) nr##_interrupt(void) -#define IRQ_NAME(nr) IRQ_NAME2(IRQ##nr) +#else + +#define SAVE_ALL + +#endif #define BUILD_SMP_INTERRUPT(x,v) XBUILD_SMP_INTERRUPT(x,v) #define XBUILD_SMP_INTERRUPT(x,v)\ @@ -115,7 +120,7 @@ asmlinkage void call_##x(void); \ __asm__( \ "\n"__ALIGN_STR"\n" \ SYMBOL_NAME_STR(x) ":\n\t" \ - "pushl $"#v"\n\t" \ + "push"__OS" $"#v"\n\t" \ SAVE_ALL \ SYMBOL_NAME_STR(call_##x)":\n\t" \ "call "SYMBOL_NAME_STR(smp_##x)"\n\t" \ @@ -128,13 +133,13 @@ asmlinkage void call_##x(void); \ __asm__( \ "\n"__ALIGN_STR"\n" \ SYMBOL_NAME_STR(x) ":\n\t" \ - "pushl $"#v"\n\t" \ + "push"__OS" $"#v"\n\t" \ SAVE_ALL \ - "movl %esp,%eax\n\t" \ - "pushl %eax\n\t" \ + "mov %"__OP"sp,%"__OP"ax\n\t" \ + "push %"__OP"ax\n\t" \ SYMBOL_NAME_STR(call_##x)":\n\t" \ "call "SYMBOL_NAME_STR(smp_##x)"\n\t" \ - "addl $4,%esp\n\t" \ + "add $4,%"__OP"sp\n\t" \ "jmp ret_from_intr\n"); #define BUILD_COMMON_IRQ() \ @@ -147,12 +152,15 @@ __asm__( \ "call " SYMBOL_NAME_STR(do_IRQ) "\n\t" \ "jmp ret_from_intr\n"); +#define IRQ_NAME2(nr) nr##_interrupt(void) +#define IRQ_NAME(nr) IRQ_NAME2(IRQ##nr) + #define BUILD_IRQ(nr) \ asmlinkage void IRQ_NAME(nr); \ __asm__( \ "\n"__ALIGN_STR"\n" \ SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \ - "pushl $"#nr"\n\t" \ + "push"__OS" $"#nr"\n\t" \ "jmp common_interrupt"); extern unsigned long prof_cpu_mask; From 1c894096e7b32c7ad87d36bb2114bcfcd8fe759b Mon Sep 17 00:00:00 2001 From: "mjw@wray-m-3.hpl.hp.com" Date: Mon, 5 Jul 2004 16:19:14 +0000 Subject: [PATCH 21/36] bitkeeper revision 1.1041.5.5 (40e97f82YUOF-rGuIapKOE73WUHZcg) Add control over domain restart on shutdown. --- tools/examples/xmdefaults | 3 +- tools/examples/xmnetbsd | 29 +++-- tools/python/xen/xend/XendClient.py | 5 +- tools/python/xen/xend/XendDomain.py | 141 ++++++++++++++++++++-- tools/python/xen/xend/XendDomainInfo.py | 4 + tools/python/xen/xend/server/SrvDomain.py | 6 +- tools/python/xen/xm/create.py | 6 + tools/python/xen/xm/shutdown.py | 35 +++++- 8 files changed, 193 insertions(+), 36 deletions(-) diff --git a/tools/examples/xmdefaults b/tools/examples/xmdefaults index cf9e9861db..640a7390a0 100644 --- a/tools/examples/xmdefaults +++ b/tools/examples/xmdefaults @@ -2,7 +2,6 @@ #============================================================================ # Python defaults setup for 'xm create'. # Edit this file to reflect the configuration of your system. - #============================================================================ # Define script variables here. @@ -94,6 +93,6 @@ extra = "4 VMID=%d usr=/dev/sda6" % vmid #---------------------------------------------------------------------------- # Set according to whether you want the domain restarted when it exits. # The default is False. -#restart = True +#autorestart = True #============================================================================ diff --git a/tools/examples/xmnetbsd b/tools/examples/xmnetbsd index 0563239464..4f920087b6 100644 --- a/tools/examples/xmnetbsd +++ b/tools/examples/xmnetbsd @@ -2,24 +2,23 @@ #============================================================================ # Python defaults setup for 'xm create'. # Edit this file to reflect the configuration of your system. -# This file expects the variable 'vmid' to be set. #============================================================================ -def config_usage (): - print >>sys.stderr,""" -The config file '%s' requires the following variable to be defined: - vmid -- Numeric identifier for the new domain, used to calculate - the VM's IP address and root partition. E.g. -Dvmid=1 -""" % config_file +# Define script variables here. +# xm_vars is defined automatically, use xm_vars.var() to define a variable. +def vmid_check(var, val): + val = int(val) + if val <= 0: + raise ValueError + return val + +xm_vars.var('vmid', + use="Virtual machine id. Integer greater than 0.", + check=vmid_check) -try: - vmid = int(vmid) # convert to integer -except: - raise ValueError, "Variable 'vmid' must be an integer" - -if vmid <= 0: - raise ValueError, "Variable 'vmid' must be greater than 0" +# This checks the script variables. +xm_vars.check() #---------------------------------------------------------------------------- # Kernel image file. @@ -97,6 +96,6 @@ extra = "4 VMID=%d bootdev=xennet0" % vmid #---------------------------------------------------------------------------- # Set according to whether you want the domain restarted when it exits. # The default is False. -#restart = True +#autorestart = True #============================================================================ diff --git a/tools/python/xen/xend/XendClient.py b/tools/python/xen/xend/XendClient.py index 12a21c2c9c..b5d57b7174 100644 --- a/tools/python/xen/xend/XendClient.py +++ b/tools/python/xen/xend/XendClient.py @@ -225,9 +225,10 @@ class Xend: return xend_call(self.domainurl(id), {'op' : 'pause'}) - def xend_domain_shutdown(self, id): + def xend_domain_shutdown(self, id, reason): return xend_call(self.domainurl(id), - {'op' : 'shutdown'}) + {'op' : 'shutdown', + 'reason' : reason }) def xend_domain_destroy(self, id): return xend_call(self.domainurl(id), diff --git a/tools/python/xen/xend/XendDomain.py b/tools/python/xen/xend/XendDomain.py index 328450a6b5..4bde519b49 100644 --- a/tools/python/xen/xend/XendDomain.py +++ b/tools/python/xen/xend/XendDomain.py @@ -5,8 +5,10 @@ Needs to be persistent for one uptime. """ import sys +import traceback from twisted.internet import defer +from twisted.internet import reactor import xen.lowlevel.xc; xc = xen.lowlevel.xc.new() @@ -28,10 +30,19 @@ __all__ = [ "XendDomain" ] class XendDomain: """Index of all domains. Singleton. """ - + + """Path to domain database.""" dbpath = "domain" + + """Table of domain info indexed by domain id.""" domain = {} + """Table of configs for domain restart, indexed by domain id.""" + restarts = {} + + """Table of delayed calls.""" + schedule = {} + def __init__(self): self.xconsole = XendConsole.instance() # Table of domain info indexed by domain id. @@ -49,6 +60,53 @@ class XendDomain: print 'XendDomain> virq', val self.reap() + def schedule_later(self, _delay, _name, _fn, *args): + """Schedule a function to be called later (if not already scheduled). + + _delay delay in seconds + _name schedule name + _fn function + args arguments + """ + if self.schedule.get(_name): return + self.schedule[_name] = reactor.callLater(_delay, _fn, *args) + + def schedule_cancel(self, name): + """Cancel a scheduled function call. + + name schedule name to cancel + """ + callid = self.schedule.get(name) + if not callid: + return + if callid.active(): + callid.cancel() + del self.schedule[name] + + def reap_schedule(self, delay=0): + """Schedule reap to be called later. + + delay delay in seconds + """ + self.schedule_later(delay, 'reap', self.reap) + + def reap_cancel(self): + """Cancel any scheduled reap. + """ + self.schedule_cancel('reap') + + def refresh_schedule(self, delay=0): + """Schedule refresh to be called later. + + delay delay in seconds + """ + self.schedule_later(delay, 'refresh', self.refresh) + + def refresh_cancel(self): + """Cancel any scheduled refresh. + """ + self.schedule_cancel('refresh') + def rm_all(self): """Remove all domain info. Used after reboot. """ @@ -145,6 +203,7 @@ class XendDomain: """Look for domains that have crashed or stopped. Tidy them up. """ + self.reap_cancel() print 'XendDomain>reap>' domlist = xc.domain_getinfo() casualties = [] @@ -158,12 +217,14 @@ class XendDomain: for d in casualties: id = str(d['dom']) print 'XendDomain>reap> died id=', id, d - self.domain_destroy(id, refresh=0) + self.final_domain_destroy(id) print 'XendDomain>reap<' def refresh(self): """Refresh domain list from Xen. """ + self.refresh_cancel() + print 'XendDomain>refresh>' domlist = xc.domain_getinfo() # Index the domlist by id. # Add entries for any domains we don't know about. @@ -184,7 +245,7 @@ class XendDomain: d.update(dominfo) else: self._delete_domain(d.id) - self.reap() + self.reap_schedule(1) def refresh_domain(self, id): """Refresh information for a single domain. @@ -267,21 +328,70 @@ class XendDomain: """Shutdown domain (nicely). id domain id - reason shutdown type: poweroff, reboot, halt + reason shutdown type: poweroff, reboot, suspend, halt """ dom = int(id) if dom <= 0: return 0 + self.domain_restart_schedule(id, reason) eserver.inject('xend.domain.shutdown', [id, reason]) + if reason == 'halt': + reason = 'poweroff' val = xend.domain_shutdown(dom, reason) - self.refresh() + self.refresh_schedule() return val - - def domain_destroy(self, id, refresh=1): - """Terminate domain immediately. + + def domain_restart_schedule(self, id, reason): + """Schedule a restart for a domain if it needs one. + + id domain id + reason shutdown reason + """ + if id in self.restarts: + # Don't schedule if already there. + return + restart = 0 + if reason in ['poweroff', 'reboot']: + dominfo = self.domain.get(id) + if dominfo and (dominfo.autorestart or reason == 'reboot'): + restart = 1 + # Clear autorestart flag to avoid multiple restarts. + dominfo.autorestart = 0 + + if restart: + self.restarts[id] = dominfo.config + + def domain_restart_cancel(self, id): + """Cancel any restart scheduled for a domain. + + id domain id + """ + dominfo = self.domain.get(id) + if dominfo: + dominfo.autorestart = 0 + if id in self.restarts: + del self.restarts[id] + + def domain_restarts(self): + """Execute any scheduled domain restarts for domains that have gone. + """ + for id in self.restarts.keys(): + if id in self.domain: + # Don't execute restart for domains still running. + continue + config = self.restarts[id] + # Remove it from the restarts. + del self.restarts[id] + try: + self.domain_create(config) + except: + print >>sys.stderr, "XendDomain> Exception restarting domain" + traceback.print_exc(sys.stderr) + + def final_domain_destroy(self, id): + """Final destruction of a domain.. id domain id - refresh send a domain destroy event if true """ dom = int(id) if dom <= 0: @@ -292,15 +402,26 @@ class XendDomain: val = dominfo.destroy() else: val = xc.domain_destroy(dom=dom) - if refresh: self.refresh() return val + def domain_destroy(self, id): + """Terminate domain immediately. + Camcels any restart for the domain. + + id domain id + """ + self.domain_restart_cancel(id) + val = self.final_domain_destroy(id) + self.refresh_schedule() + return val + def domain_migrate(self, id, dst): """Start domain migration. id domain id """ # Need a cancel too? + # Don't forget to cancel restart for it. pass def domain_save(self, id, dst, progress=0): diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index 869fc28e07..f14e6477c2 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -362,6 +362,8 @@ class XendDomainInfo: self.state = self.STATE_OK #todo: set to migrate info if migrating self.migrate = None + #Whether to auto-restart + self.autorestart = 0 def setdom(self, dom): self.dom = int(dom) @@ -418,6 +420,8 @@ class XendDomainInfo: try: self.name = sxp.child_value(config, 'name') self.memory = int(sxp.child_value(config, 'memory', '128')) + if sxp.child(config, 'autorestart', None): + self.autorestart = 1 self.configure_backends() image = sxp.child_value(config, 'image') image_name = sxp.name(image) diff --git a/tools/python/xen/xend/server/SrvDomain.py b/tools/python/xen/xend/server/SrvDomain.py index 156198bd70..085dd2642e 100644 --- a/tools/python/xen/xend/server/SrvDomain.py +++ b/tools/python/xen/xend/server/SrvDomain.py @@ -27,7 +27,11 @@ class SrvDomain(SrvDir): return val def op_shutdown(self, op, req): - val = self.xd.domain_shutdown(self.dom.id) + #val = self.xd.domain_shutdown(self.dom.id) + fn = FormFn(self.xd.domain_shutdown, + [['dom', 'int'], + ['reason', 'str']]) + val = fn(req.args, {'dom': self.dom.id}) req.setResponseCode(202) req.setHeader("Location", "%s/.." % req.prePathURL()) return val diff --git a/tools/python/xen/xm/create.py b/tools/python/xen/xm/create.py index 36bcddef92..3c61db9325 100644 --- a/tools/python/xen/xm/create.py +++ b/tools/python/xen/xm/create.py @@ -101,6 +101,10 @@ gopts.opt('memory', short='m', val='MEMORY', fn=set_value, default=128, use="Domain memory in MB.") +gopts.opt('autorestart', + fn=set_true, default=0, + use="Whether to restart the domain on exit.") + gopts.opt('blkif', fn=set_true, default=0, use="Make the domain a block device backend.") @@ -271,6 +275,8 @@ def make_config(opts): config.append(['backend', ['blkif']]) if opts.netif: config.append(['backend', ['netif']]) + if opts.autorestart: + config.append(['autorestart']) configure_image(config, opts) config_devs = [] diff --git a/tools/python/xen/xm/shutdown.py b/tools/python/xen/xm/shutdown.py index aaa354554a..926aaf27f3 100644 --- a/tools/python/xen/xm/shutdown.py +++ b/tools/python/xen/xm/shutdown.py @@ -1,4 +1,5 @@ # Copyright (C) 2004 Mike Wray + """Domain shutdown. """ import string @@ -10,7 +11,8 @@ from xen.xm.opts import * gopts = Opts(use="""[options] [DOM] -Shutdown one or more domains gracefully.""") +Shutdown one or more domains gracefully. +""") gopts.opt('help', short='h', fn=set_true, default=0, @@ -24,18 +26,22 @@ gopts.opt('wait', short='w', fn=set_true, default=0, use='Wait for shutdown to complete.') -gopts.opt('norestart', short='n', +gopts.opt('halt', short='H', fn=set_true, default=0, - use='Prevent domain restart.') + use='Shutdown without reboot.') -def shutdown(opts, doms, wait): +gopts.opt('reboot', short='R', + fn=set_true, default=0, + use='Shutdown and reboot.') + +def shutdown(opts, doms, mode, wait): def domains(): return [ int(a) for a in server.xend_domains() ] if doms == None: doms = domains() if 0 in doms: doms.remove(0) for d in doms: - server.xend_domain_shutdown(d) + server.xend_domain_shutdown(d, mode) if wait: while doms: alive = domains() @@ -49,6 +55,21 @@ def shutdown(opts, doms, wait): time.sleep(1) opts.info("All domains terminated") +def shutdown_mode(opts): + mode = 'poweroff' + if opts.vals.wait: + mode = 'halt' + if opts.vals.reboot: + opts.err("Can't specify wait and reboot") + else: + if opts.vals.halt and opts.vals.reboot: + opts.err("Can't specify halt and reboot") + if opts.vals.halt: + mode = 'halt' + elif opts.vals.reboot: + mode = 'reboot' + return mode + def main_all(opts, args): shutdown(opts, None, opts.vals.wait) @@ -59,7 +80,9 @@ def main_dom(opts, args): domid = int(dom) except: opts.err('Invalid domain: ' + dom) - shutdown(opts, [ domid ], opts.vals.wait) + + mode = shutdown_mode(opts) + shutdown(opts, [ domid ], mode, opts.vals.wait) def main(argv): opts = gopts From b87f42498ff097e1ae37686e296c05417258d3af Mon Sep 17 00:00:00 2001 From: "mjw@wray-m-3.hpl.hp.com" Date: Mon, 5 Jul 2004 16:20:00 +0000 Subject: [PATCH 22/36] bitkeeper revision 1.1041.5.6 (40e97fb09K8Oxvzk9KeNthtMZL24Tw) Don't call pending deferred if already called. --- tools/python/xen/xend/server/controller.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/python/xen/xend/server/controller.py b/tools/python/xen/xend/server/controller.py index 49d6e26ea8..6804331ac7 100755 --- a/tools/python/xen/xend/server/controller.py +++ b/tools/python/xen/xend/server/controller.py @@ -180,7 +180,8 @@ class ControllerFactory(CtrlMsgRcvr): """ if self.dlist: d = self.dlist.pop(0) - d.callback(*args) + if not d.called: + d.callback(*args) def errDeferred(self, *args): """Signal an error to the top deferred object. @@ -189,7 +190,8 @@ class ControllerFactory(CtrlMsgRcvr): """ if self.dlist: d = self.dlist.pop(0) - d.errback(*args) + if not d.called: + d.errback(*args) class Controller(CtrlMsgRcvr): """Abstract class for a device controller attached to a domain. From 68485ace640a03472b1074cdb6d8369cd82e691d Mon Sep 17 00:00:00 2001 From: "mjw@wray-m-3.hpl.hp.com" Date: Mon, 5 Jul 2004 16:23:43 +0000 Subject: [PATCH 23/36] bitkeeper revision 1.1041.5.7 (40e9808fAoDayBeZwAauQ7CRlcKCog) Start of code to talk to migration daemon to do migrate. Initial checkin of the migration daemon, xfrd. --- .rootkeys | 27 + tools/libxutil/string_stream.c | 47 +- tools/python/xen/xend/XendMigrate.py | 139 +++- tools/python/xen/xend/packing.py | 329 ++++++++ tools/xfrd/Make.xfrd | 34 + tools/xfrd/Makefile | 68 ++ tools/xfrd/connection.c | 163 ++++ tools/xfrd/connection.h | 32 + tools/xfrd/debug.h | 72 ++ tools/xfrd/enum.c | 61 ++ tools/xfrd/enum.h | 30 + tools/xfrd/hash_table.c | 640 +++++++++++++++ tools/xfrd/hash_table.h | 294 +++++++ tools/xfrd/lexis.c | 93 +++ tools/xfrd/lexis.h | 127 +++ tools/xfrd/lzi_stream.c | 533 ++++++++++++ tools/xfrd/lzi_stream.h | 35 + tools/xfrd/marshal.c | 207 +++++ tools/xfrd/marshal.h | 42 + tools/xfrd/select.c | 50 ++ tools/xfrd/select.h | 16 + tools/xfrd/sxpr.c | 950 ++++++++++++++++++++++ tools/xfrd/sxpr.h | 414 ++++++++++ tools/xfrd/xdr.c | 316 ++++++++ tools/xfrd/xdr.h | 30 + tools/xfrd/xen_domain.c | 90 ++ tools/xfrd/xen_domain.h | 15 + tools/xfrd/xfrd.c | 1127 ++++++++++++++++++++++++++ tools/xfrd/xfrd.h | 14 + tools/xfrd/xfrdClient.py | 127 +++ 30 files changed, 6070 insertions(+), 52 deletions(-) create mode 100644 tools/python/xen/xend/packing.py create mode 100644 tools/xfrd/Make.xfrd create mode 100644 tools/xfrd/Makefile create mode 100644 tools/xfrd/connection.c create mode 100644 tools/xfrd/connection.h create mode 100644 tools/xfrd/debug.h create mode 100644 tools/xfrd/enum.c create mode 100644 tools/xfrd/enum.h create mode 100644 tools/xfrd/hash_table.c create mode 100644 tools/xfrd/hash_table.h create mode 100644 tools/xfrd/lexis.c create mode 100644 tools/xfrd/lexis.h create mode 100644 tools/xfrd/lzi_stream.c create mode 100644 tools/xfrd/lzi_stream.h create mode 100644 tools/xfrd/marshal.c create mode 100644 tools/xfrd/marshal.h create mode 100644 tools/xfrd/select.c create mode 100644 tools/xfrd/select.h create mode 100644 tools/xfrd/sxpr.c create mode 100644 tools/xfrd/sxpr.h create mode 100644 tools/xfrd/xdr.c create mode 100644 tools/xfrd/xdr.h create mode 100644 tools/xfrd/xen_domain.c create mode 100644 tools/xfrd/xen_domain.h create mode 100644 tools/xfrd/xfrd.c create mode 100644 tools/xfrd/xfrd.h create mode 100755 tools/xfrd/xfrdClient.py diff --git a/.rootkeys b/.rootkeys index ef35788131..88e79ce75d 100644 --- a/.rootkeys +++ b/.rootkeys @@ -241,6 +241,7 @@ 40c9c468xzANp6o2D_MeCYwNmOIUsQ tools/python/xen/xend/XendVnet.py 40c9c468x191zetrVlMnExfsQWHxIQ tools/python/xen/xend/__init__.py 40c9c468S2YnCEKmk4ey8XQIST7INg tools/python/xen/xend/encode.py +40e9808elkoRulOo1GxRTp5ulJGVNw tools/python/xen/xend/packing.py 40c9c468DCpMe542varOolW1Xc68ew tools/python/xen/xend/server/SrvBase.py 40c9c468IxQabrKJSWs0aEjl-27mRQ tools/python/xen/xend/server/SrvConsole.py 40c9c4689Io5bxfbYIfRiUvsiLX0EQ tools/python/xen/xend/server/SrvConsoleDir.py @@ -276,6 +277,32 @@ 403a3edbVpV2E_wq1zeEkJ_n4Uu2eg tools/xentrace/xentrace.c 403a3edblCUrzSj0mmKhO5HOPrOrSQ tools/xentrace/xentrace_format 4050c413NtuyIq5lsYJV4P7KIjujXw tools/xentrace/xentrace_format.1 +40e9808eHO3QprCFKg9l2JJzgt2voA tools/xfrd/Make.xfrd +40e9808epTR4zWrYjGUnaaynK20Q5A tools/xfrd/Makefile +40e9808eysqT4VNDlJFqsZB2rdg4Qw tools/xfrd/connection.c +40e9808eyXfJUi4E0C3WSgrEXqQ1sQ tools/xfrd/connection.h +40e9808eULGwffNOE4kBrAfZ9YAVMA tools/xfrd/debug.h +40e9808eyjiahG5uF6AMelNVujBzCg tools/xfrd/enum.c +40e9808eZpbdn9q2KSSMGCNvY_ZgpQ tools/xfrd/enum.h +40e9808easXCzzAZQodEfKAhgUXSPA tools/xfrd/hash_table.c +40e9808e94BNXIVVKBFHC3rnkvwtJg tools/xfrd/hash_table.h +40e9808epW9iHcLXuO3QfUfLzB7onw tools/xfrd/lexis.c +40e9808egccMhCizayQRGtpBA3L5MQ tools/xfrd/lexis.h +40e9808ePADCSKL1YgGCt2TbYPnYkw tools/xfrd/lzi_stream.c +40e9808eDNAdpF71o5teYb9DTT-PRw tools/xfrd/lzi_stream.h +40e9808eQxi0EzTcPJtosrzxEIjA-Q tools/xfrd/marshal.c +40e9808etg13xfRm0Lqd8vY-jHOoTg tools/xfrd/marshal.h +40e9808eCsmywryb036TdtRMJHDMmQ tools/xfrd/select.c +40e9808e99OcM547cKMTfmCVSoWVAw tools/xfrd/select.h +40e9808e5_PLdodqVOSx0b4T_f5aeg tools/xfrd/sxpr.c +40e9808e0O4sHZtkDv5hlSqjYcdQAQ tools/xfrd/sxpr.h +40e9808eF3NVldqRNS5IHM8gbFAvpw tools/xfrd/xdr.c +40e9808ezXzoRHm7pybXU69NtnjimA tools/xfrd/xdr.h +40e9808edpUtf4bJ8IbqClPJj_OvbA tools/xfrd/xen_domain.c +40e9808eHviFFIwdUKOA234uIeifjA tools/xfrd/xen_domain.h +40e9808eIFeV-MDCNyVTNt5NfMPKeQ tools/xfrd/xfrd.c +40e9808eGIbOoSNJRiwWK2C3mjGWaA tools/xfrd/xfrd.h +40e9808eHXvs_5eggj9McD_J90mhNw tools/xfrd/xfrdClient.py 3f72f1bdJPsV3JCnBqs9ddL9tr6D2g xen/COPYING 3ddb79bcbOVHh38VJzc97-JEGD4dJQ xen/Makefile 3ddb79bcWnTwYsQRWl_PaneJfa6p0w xen/Rules.mk diff --git a/tools/libxutil/string_stream.c b/tools/libxutil/string_stream.c index c3cf423d84..495238d74a 100644 --- a/tools/libxutil/string_stream.c +++ b/tools/libxutil/string_stream.c @@ -25,8 +25,6 @@ #include "string_stream.h" #include "allocate.h" -static int string_print(IOStream *io, const char *msg, va_list args); -static int string_getc(IOStream *io); static int string_error(IOStream *io); static int string_close(IOStream *io); static void string_free(IOStream *io); @@ -49,45 +47,6 @@ static inline StringData *get_string_data(IOStream *io){ return (StringData*)io->data; } -/** Read a character from a string stream. - * - * @param io string stream - * @return character read, IOSTREAM_EOF if no more input - */ -static int string_getc(IOStream *io){ - StringData *data = get_string_data(io); - int c = IOSTREAM_EOF; - char *s = data->in; - - if(s && s < data->end){ - c = (unsigned)*s; - data->in = s+1; - } - return c; -} - -/** Print to a string stream. - * Formats the data to an internal buffer and prints it. - * The formatted data must fit into the internal buffer. - * - * @param io string stream - * @param format print format - * @param args print arguments - * @return result of the print - */ -static int string_print(IOStream *io, const char *msg, va_list args){ - StringData *data = get_string_data(io); - int k = data->end - data->out; - int n = vsnprintf(data->out, k, (char*)msg, args); - if(n < 0 || n > k ){ - n = k; - IOStream_close(io); - } else { - data->out += n; - } - return n; -} - /** Test if a string stream has an error. * * @param io string stream @@ -118,7 +77,7 @@ static int string_close(IOStream *io){ */ static void string_free(IOStream *io){ StringData *data = get_string_data(io); - zero(data, sizeof(*data)); + memzero(data, sizeof(*data)); deallocate(data); } @@ -139,13 +98,13 @@ IOMethods *string_stream_get_methods(void){ */ void string_stream_init(IOStream *io, StringData *data, char *s, int n){ if(data && io){ - zero(data, sizeof(*data)); + memzero(data, sizeof(*data)); data->string = (char*)s; data->in = data->string; data->out = data->string; data->size = n; data->end = data->string + n; - zero(io, sizeof(*io)); + memzero(io, sizeof(*io)); io->methods = &string_methods; io->data = data; } diff --git a/tools/python/xen/xend/XendMigrate.py b/tools/python/xen/xend/XendMigrate.py index 1580ba83ed..471ea7d1dd 100644 --- a/tools/python/xen/xend/XendMigrate.py +++ b/tools/python/xen/xend/XendMigrate.py @@ -2,22 +2,124 @@ import sys import socket +import time + +from twisted.internet import reactor +from twisted.internet import defer +from twisted.internet.protocol import Protocol +from twisted.internet.protocol import ClientFactory import sxp import XendDB import EventServer; eserver = EventServer.instance() +from xen.xend.packing import SxpPacker, SxpUnpacker +from xen.xend import XendDomain +xd = XendDomain.instance() + + +XFRD_PORT = 8002 + +XFR_PROTO_MAJOR = 1 +XFR_PROTO_MINOR = 0 + +class Migrate(Protocol): + + def __init__(self, minfo): + self.packer = None + self.unpacker = None + self.minfo = minfo + + def connectionMade(self): + self.packer = SxpPacker(self.transport) + self.unpacker = SxpPacker() + # Send hello. + self.packer.pack(['xfr.hello', XFR_PROTO_MAJOR, XFR_PROTO_MINOR]) + # Send migrate. + vmconfig = self.minfo.vmconfig() + if not vmconfig: + self.loseConnection() + return + self.packer.pack(['xfr.migrate', + self.minfo.src_dom, + vmconfig, + self.minfo.dst_host, + self.minfo.dst_port]) + + def connectionLost(self, reason): + self.minfo.closed(reason) + + def dataReceived(self, data): + try: + self.unpacker.reset(data) + val = self.unpacker.unpack() + print 'dataReceived>', 'val=', val + op = val[0] + op.replace('.', '_') + if op.startwith('xfr_'): + fn = getattr(self, op, self.unknown) + else: + fn = self.unknown + fn(val) + except Exception, ex: + print 'dataReceived>', ex + pass + + def unknown(self, val): + print 'unknown>', val + + def xfr_progress(self, val): + print 'xfr_progress>', val + + def xfr_error(self, val): + # If we get an error with non-zero code the migrate failed. + # An error with code zero indicates hello success. + err = int(val[1]) + if not err: return + self.minfo.error(err); + self.loseConnection() + + def xfr_ok(self, val): + # An ok indicates migrate completed successfully, and contains + # the new domain id on the remote system. + dom = int(val[1]) + self.minfo.ok(dom) + self.loseConnection() + +class MigrateClientFactory(ClientFactory): + + def __init__(self, minfo): + ClientFactory.__init__(self) + self.minfo = minfo + + def startedConnecting(self, connector): + print 'Started to connect', 'self=', self, 'connector=', connector + + def buildProtocol(self, addr): + print 'buildProtocol>', addr + return Migrate(self.minfo) + + def clientConnectionLost(self, connector, reason): + print 'clientConnectionLost>', 'connector=', connector, 'reason=', reason + + def clientConnectionFailed(self, connector, reason): + print 'clientConnectionFailed>', 'connector=', connector, 'reason=', reason + + class XendMigrateInfo: # states: begin, active, failed, succeeded? - def __init__(self, id, dom, dst): + def __init__(self, id, dom, host, port): self.id = id self.state = 'begin' self.src_host = socket.gethostname() self.src_dom = dom self.dst_host = dst + self.dst_port = port self.dst_dom = None + self.start = 0 + self.deferred = defer.Deferred() def set_state(self, state): self.state = state @@ -29,12 +131,33 @@ class XendMigrateInfo: sxpr = ['migrate', ['id', self.id], ['state', self.state] ] sxpr_src = ['src', ['host', self.src_host], ['domain', self.src_dom] ] sxpr.append(sxpr_src) - sxpr_dst = ['dst', ['host', self.dst] ] + sxpr_dst = ['dst', ['host', self.dst_host] ] if self.dst_dom: sxpr_dst.append(['domain', self.dst_dom]) sxpr.append(sxpr_dst) return sxpr - + + def vmconfig(self): + dominfo = xd.domain_get(self.dom) + if dominfo: + val = return sxp.to_string(dominfo) + else: + val = None + return None + + def error(self, err): + self.state = 'error' + + def ok(self, dom): + self.state = 'ok' + self.dst_dom = dom + + def close(self): + if self.state =='ok': + eserver.inject('xend.migrate.ok', self.sxpr()) + else: + self.state = 'error' + eserver.inject('xend.migrate.error', self.sxpr()) class XendMigrate: # Represents migration in progress. @@ -84,15 +207,15 @@ class XendMigrate: def migrate_get(self, id): return self.migrate.get(id) - def migrate_begin(self, dom, dst): + def migrate_begin(self, dom, host): # Check dom for existence, not migrating already. - # Create migrate info, tell xend to migrate it? - # - or fork migrate command ourselves? # Subscribe to migrate notifications (for updating). id = self.nextid() - info = XenMigrateInfo(id, dom, dst) + info = XenMigrateInfo(id, dom, host, XFRD_PORT) self._add_migrate(id, info) - return id + mcf = MigrateClientFactory(info) + reactor.connectTCP('localhost', XFRD_PORT, mcf) + return info.deferred def instance(): global inst diff --git a/tools/python/xen/xend/packing.py b/tools/python/xen/xend/packing.py new file mode 100644 index 0000000000..760af7f5a1 --- /dev/null +++ b/tools/python/xen/xend/packing.py @@ -0,0 +1,329 @@ + +# XDR-style packer/unpacker for sxpr. +# +# string -> [STRING] [len:u16] +# atom -> [ATOM] [len:u16] +# int -> [UINT] [value] +# list -> [LIST] {1 elt}* 0 +# null -> [NULL] +# none -> [NONE] +# bool -> [BOOL] { 0:u8 | 1:u8 } +# +# types packed as u16. +# +# So (a b c) -> [LIST] 1 a 1 b 1 c 0 +# () -> [LIST] 0 + +import struct + +try: + from cStringIO import StringIO as _StringIO +except ImportError: + from StringIO import StringIO as _StringIO + +import types + +class Error(Exception): + + def __init__(self, msg): + self.msg = msg + + def __repr__(self): + return repr(self.msg) + + def __str__(self): + return str(self.msg) + + +class ConversionError(Error): + pass + +BOOL_SIZE = 1 +BOOL_FMT = '>B' + +BYTE_SIZE = 1 +BYTE_FMT = '>b' +UBYTE_FMT = '>B' + +SHORT_SIZE = 2 +SHORT_FMT = '>h' +USHORT_FMT = '>H' + +INT_SIZE = 4 +INT_FMT = '>l' +UINT_FMT = '>L' + +NONE_CODE = 0 +NULL_CODE = 1 +INT_CODE = 2 +STRING_CODE = 3 +ATOM_CODE = 4 +BOOL_CODE = 5 +LIST_CODE = 10 + +class Packer: + + def __init__(self, io=None): + self.reset(io=io) + + def reset(self, io=None): + if io is None: + io = _StringIO() + self.io = io + + def get_buffer(self): + return self.io.getvalue() + + def get_io(self): + return self.io + + def struct_pack(self, fmt, x): + try: + self.io.write(struct.pack(fmt, x)) + except struct.error, msg: + raise ConversionError, msg + + def pack_none(self): + pass + + def pack_bool(self, x): + # { '1' | '0' } + print 'bool>', x + if x: + self.io.write('\1') + else: + self.io.write('\0') + + def pack_byte(self, x): + self.struct_pack(BYTE_FMT, x & 0xff) + + def pack_char(self, x): + print 'char>', x + self.io.write(x) + + def pack_ubyte(self, x): + print 'ubyte>', x + self.struct_pack(UBYTE_FMT, x & 0xff) + + def pack_ushort(self, x): + print 'ushort>', x + self.struct_pack(USHORT_FMT, x & 0xffff) + + def pack_short(self, x): + print 'short>', x + self.struct_pack(SHORT_FMT, x & 0xffff) + + def pack_uint(self, x): + print 'uint>', x + self.struct_pack(UINT_FMT, x) + + def pack_int(self, x): + print 'int>', x + self.struct_pack(INT_FMT, x) + + def pack_uhyper(self, x): + print 'uhyper>', x + self.pack_uint(x>>32 & 0xffffffffL) + self.pack_uint(x & 0xffffffffL) + + pack_hyper = pack_uhyper + + def pack_fstring(self, n, x): + print 'fstring>', x + self.io.write(x) + + pack_fopaque = pack_fstring + + def pack_string(self, x): + print 'string>', x + n = len(x) + self.pack_ushort(n) + self.pack_fstring(n, x) + + pack_opaque = pack_string + pack_bytes = pack_string + + def pack_list(self, x, pack_item): + print 'list>', x + # { '1' }* '0' + for item in x: + self.pack_bool(1) + pack_item(item) + self.pack_bool(0) + + def pack_farray(self, x, pack_item): + # * + # Can pass n and check length - but is it worth it? + print 'farray>', list + for item in x: + pack_item(item) + + def pack_array(self, x, pack_item): + # n *n + print 'array>', x + self.pack_uint(len(x)) + self.pack_farray(x, pack_item) + +class Unpacker: + + def __init__(self, data): + self.reset(data) + + def reset(self, data): + if isinstance(data, types.StringType): + data = _StringIO(data) + self.io = data + + def get_bytes(self, n): + if n < 0: + raise ConversionError('negative byte count') + data = self.io.read(n) + return data + + def struct_unpack(self, fmt, n): + data = self.get_bytes(n) + try: + return struct.unpack(fmt, data)[0] + except struct.error, msg: + raise ConversionError, msg + + def unpack_none(self): + return None + + def unpack_bool(self): + return self.struct_unpack(BOOL_FMT, BOOL_SIZE) + + def unpack_char(self): + return self.get_bytes(1)[0] + + def unpack_byte(self): + return self.struct_unpack(BYTE_FMT, BYTE_SIZE) + + def unpack_ubyte(self): + return self.struct_unpack(UBYTE_FMT, BYTE_SIZE) + + def unpack_ushort(self): + return self.struct_unpack(USHORT_FMT, SHORT_SIZE) + + def unpack_short(self): + return self.struct_unpack(SHORT_FMT, SHORT_SIZE) + + def unpack_uint(self): + x = self.struct_unpack(UINT_FMT, UINT_SIZE) + try: + return int(x) + except OverflowError: + return x + + def unpack_int(self): + return self.struct_unpack(INT_FMT, INT_SIZE) + + def unpack_uhyper(self): + hi = self.unpack_uint() + lo = self.unpack_uint() + return long(hi)<<32 | lo + + def unpack_hyper(self): + x = self.unpack_uhyper() + if x >= 0x8000000000000000L: + x = x - 0x10000000000000000L + return x + + def unpack_fstring(self, n): + return self.get_bytes(n) + + unpack_fopaque = unpack_fstring + + def unpack_string(self): + n = self.unpack_ushort() + return self.unpack_fstring(n) + + unpack_opaque = unpack_string + unpack_bytes = unpack_string + + def unpack_list(self, unpack_item): + list = [] + while self.unpack_bool(): + list.append(unpack_item()) + return list + + def unpack_farray(self, n, unpack_item): + list = [] + for i in range(n): + list.append(unpack_item()) + return list + + def unpack_array(self, unpack_item): + n = self.unpack_ushort() + return self.unpack_farray(n, unpack_item) + +class SxpPacker(Packer): + + pack_code = Packer.pack_ushort + + def pack(self, x): + if isinstance(x, types.NoneType): + self.pack_code(NONE_CODE) + self.pack_none() + elif isinstance(x, types.IntType): + self.pack_code(INT_CODE) + self.pack_int(x) + elif isinstance(x, types.StringType): + self.pack_code(STRING_CODE) + self.pack_string(x) + elif isinstance(x, types.ListType): + self.pack_code(LIST_CODE) + self.pack_list(x, self.pack) + else: + raise Error('invalid type ' + str(type(x))) + +class SxpUnpacker(Unpacker): + + unpack_code = Unpacker.unpack_ushort + + def unpack(self): + code = self.unpack_code() + if code == NONE_CODE: + val = self.unpack_none() + elif code == INT_CODE: + val = self.unpack_int() + elif code == BOOL_CODE: + val = self.unpack_bool() + elif code == STRING_CODE: + val = self.unpack_string() + elif code == ATOM_CODE: + val = self.unpack_string() + elif code == LIST_CODE: + val = self.unpack_list(self.unpack) + else: + raise Error('invalid code ' + str(code)) + return val + +def main(): + d = "['vfarm', ['@', ['name', 'vfarm1']], ['memory', 1024], ['image', 'splinux'], ['args', 'root=/dev/nfs ip=dhcp'], [ 1, -1, 1000000]]" + print"> len=", len(d), "d=", d + obj = ['vfarm', ['@', ['name', 'vfarm1']], + ['memory', 1024], + ['image', 'splinux'], + ['args', 'root=/dev/nfs ip=dhcp'], + [ 1, -1, 1000000] ] + print "> obj=", obj + pack = SxpPacker() + pack.pack(obj) + data = pack.get_buffer() + print "> len=", len(data), "data=", data + unpack = SxpUnpacker(data) + obj_unpack = unpack.unpack() + print "> obj=", obj_unpack + #obj = [100,101,102, 999.00234, { 'a': 1, 'b': 2 } ] + #pack.reset() + #pack.pack_item(obj) + #data = pack.get_buffer() + #print "> obj=", obj + #print "> len=", len(data), "data=", data + #unpack.reset(data) + #obj_unpack = unpack.unpack_item() + #print "> obj=", obj_unpack + +if __name__ == "__main__": + main() diff --git a/tools/xfrd/Make.xfrd b/tools/xfrd/Make.xfrd new file mode 100644 index 0000000000..39f3afd3c5 --- /dev/null +++ b/tools/xfrd/Make.xfrd @@ -0,0 +1,34 @@ +# -*- mode: Makefile; -*- +#============================================================================ + +UTIL_LIB = libutil.a + +UTIL_LIB_SRC = +UTIL_LIB_SRC += allocate.c +UTIL_LIB_SRC += enum.c +UTIL_LIB_SRC += file_stream.c +UTIL_LIB_SRC += gzip_stream.c +UTIL_LIB_SRC += hash_table.c +UTIL_LIB_SRC += iostream.c +UTIL_LIB_SRC += lexis.c +UTIL_LIB_SRC += lzi_stream.c +UTIL_LIB_SRC += marshal.c +UTIL_LIB_SRC += string_stream.c +UTIL_LIB_SRC += sxpr.c +#UTIL_LIB_SRC += sxpr_parser.c +UTIL_LIB_SRC += sys_net.c +UTIL_LIB_SRC += sys_string.c +#UTIL_LIB_SRC += util.c +UTIL_LIB_SRC += xdr.c + +#---------------------------------------------------------------------------- +# Xfrd. + +XFRD_PROG_SRC = +XFRD_PROG_SRC += xfrd.c +#XFRD_PROG_SRC += xfr_msg.c +XFRD_PROG_SRC += xen_domain.c +XFRD_PROG_SRC += select.c +XFRD_PROG_SRC += connection.c + +#============================================================================ diff --git a/tools/xfrd/Makefile b/tools/xfrd/Makefile new file mode 100644 index 0000000000..fe84120471 --- /dev/null +++ b/tools/xfrd/Makefile @@ -0,0 +1,68 @@ +# -*- mode: Makefile; -*- +#============================================================================ +# +# Mike Wray +#============================================================================ + +XEN_ROOT = ../.. +include $(XEN_ROOT)/tools/Make.defs + +XFRD_INSTALL_DIR = /usr/sbin + +vpath %.h $(XEN_HYPERVISOR_IFS) +INCLUDES += -I $(XEN_HYPERVISOR_IFS) + +vpath %h $(XEN_LINUX_INCLUDE) +INCLUDES += -I $(XEN_LINUX_INCLUDE) + +vpath %.h $(XEN_XU) +INCLUDES += -I $(XEN_XU) + +vpath %c $(XEN_LIBXUTIL) +INCLUDES += -I $(XEN_LIBXUTIL) + +include Make.xfrd + +UTIL_LIB_OBJ = $(UTIL_LIB_SRC:.c=.o) + +XFRD_PROG_OBJ = $(XFRD_PROG_SRC:.c=.o) +XFRD_PROG_OBJ += $(UTIL_LIB) + +CPPFLAGS += -D _XEN_XFR_STUB_ + +CFLAGS += -g +CFLAGS += -Wall +CFALGS += -Werror +CFLAGS += $(INCLUDES) +# Make gcc generate dependencies. +CFLAGS += -Wp,-MD,.$(@F).d +PROG_DEP = .*.d + +#LDFLAGS += -L $(COMPRESS_DIR) -lz + +$(warning XFRD_PROG_OBJ= $(XFRD_PROG_OBJ)) +$(warning UTIL_LIB= $(UTIL_LIB)) +$(warning UTIL_LIB_OBJ= $(UTIL_LIB_OBJ)) + +all: xfrd + +xfrd: $(XFRD_PROG_OBJ) -lz + +.PHONY: install +install: xfrd + mkdir -p $(prefix)/$(XFRD_INSTALL_DIR) + install -m 0755 xfrd $(prefix)/$(XFRD_INSTALL_DIR) + +.PHONY: libutil +libutil: $(UTIL_LIB) + +$(UTIL_LIB): $(UTIL_LIB_OBJ) + $(AR) rc $@ $^ + +.PHONY: clean +clean: + $(RM) *.o *.a *.so *~ xfrd + $(RM) $(PROG_DEP) + +-include $(PROG_DEP) + diff --git a/tools/xfrd/connection.c b/tools/xfrd/connection.c new file mode 100644 index 0000000000..26dca9968b --- /dev/null +++ b/tools/xfrd/connection.c @@ -0,0 +1,163 @@ +#include +#include +#include +#include +#include +#include + +#include "connection.h" +#include "file_stream.h" +#include "lzi_stream.h" + +#define dprintf(fmt, args...) fprintf(stdout, "[DEBUG] %s" fmt, __FUNCTION__, ##args) +#define wprintf(fmt, args...) fprintf(stderr, "[WARN] %s" fmt, __FUNCTION__, ##args) +#define iprintf(fmt, args...) fprintf(stdout, "[INFO] %s" fmt, __FUNCTION__, ##args) +#define eprintf(fmt, args...) fprintf(stderr, "[ERROR] %s" fmt, __FUNCTION__, ##args) + +/** Compress magic header. */ +char compress_magic[2] = { 0x1f, 0x8b }; + +/** Plain magic header. */ +char plain_magic[2] = { 0x0, 0x0 }; + +int Conn_read_header(int sock, int *flags){ + int err = 0; + char magic[2] = {}; + int k, n = sizeof(magic); + k = read(sock, magic, n); + if(k != n){ + err = -EINVAL; + goto exit; + } + dprintf("> magic={ 0x%x, 0x%x }\n", magic[0], magic[1]); + if(magic[0] == compress_magic[0] && magic[1] == compress_magic[1]){ + *flags |= CONN_READ_COMPRESS; + dprintf("> Using compress read.\n"); + } else { + dprintf("> Using plain read.\n"); + } + exit: + return err; +} + +int Conn_write_header(int sock, int flags){ + int err = 0; + if(flags & CONN_WRITE_COMPRESS){ + dprintf("> Using compress write.\n"); + err = write(sock, compress_magic, 2); + } else { + dprintf("> Using plain write.\n"); + err = write(sock, plain_magic, 2); + } + if(err == 2) err = 0; + return err; +} + +/** Initialize a file stream from a file desciptor. + * + * @param fd file descriptor + * @param mode file mode + * @param flags control compression and buffering + * @param io return parameter for the stream + * @return 0 on success, error code otherwise + */ +int stream_init(int fd, const char *mode, int flags, int compress, IOStream **io){ + int err = 0; + dprintf(">mode=%s flags=%x compress=%d\n", mode, flags, compress); + if(compress){ + *io = lzi_stream_fdopen(fd, mode); + } else { + *io = file_stream_fdopen(fd, mode); + } + if(!*io){ + err = -errno; + perror("fdopen"); + goto exit; + } + if(1 && (flags & CONN_NOBUFFER)){ + // Make unbuffered. + dprintf("> unbuffer...\n"); + err = file_stream_setvbuf((compress ? lzi_stream_io(*io) : *io), NULL, _IONBF, 0); + if(err){ + err = -errno; + perror("setvbuf"); + goto exit; + } + } + exit: + if(err && *io){ + dprintf("> close err=%d\n", err); + IOStream_close(*io); + *io = NULL; + } + dprintf("< err=%d\n", err); + return err; +} + +/** Initialize a connection. + * + * @param conn connection + * @param flags + * @param sock socket + * @param ipaddr ip address + * @return 0 on success, error code otherwise + */ +int Conn_init(Conn *conn, int flags, int sock, struct sockaddr_in addr){ + int err = 0; + dprintf("> flags=%x\n", flags); + conn->addr = addr; + conn->sock = sock; + dprintf("> write stream...\n"); + err = stream_init(sock, "w", flags, (flags & CONN_WRITE_COMPRESS), &conn->out); + if(err) goto exit; + IOStream_flush(conn->out); + dprintf("> read stream...\n"); + err = stream_init(sock, "r", flags, (flags & CONN_READ_COMPRESS) , &conn->in); + if(err) goto exit; + exit: + if(err) eprintf("< err=%d\n", err); + return err; +} + +/** Open a connection. + * + * @param conn connection + * @param flags + * @param ipaddr ip address to connect to + * @param port port + * @return 0 on success, error code otherwise + */ +int Conn_connect(Conn *conn, int flags, struct in_addr ipaddr, uint16_t port){ + int err = 0; + int sock; + struct sockaddr_in addr_in; + struct sockaddr *addr = (struct sockaddr *)&addr_in; + socklen_t addr_n = sizeof(addr_in); + dprintf("> addr=%s:%d\n", inet_ntoa(ipaddr), ntohs(port)); + sock = socket(AF_INET, SOCK_STREAM, 0); + if(sock < 0){ + err = -errno; + goto exit; + } + addr_in.sin_family = AF_INET; + addr_in.sin_addr = ipaddr; + addr_in.sin_port = port; + err = connect(sock, addr, addr_n); + if(err) goto exit; + //err = Conn_write_header(sock, flags); + //if(err < 0) goto exit; + err = Conn_init(conn, flags, sock, addr_in); + exit: + if(err) eprintf("< err=%d\n", err); + return err; +} + +/** Close a connection. + * + * @param conn connection + */ +void Conn_close(Conn *conn){ + if(conn->in) IOStream_close(conn->in); + if(conn->out) IOStream_close(conn->out); + shutdown(conn->sock, 2); +} diff --git a/tools/xfrd/connection.h b/tools/xfrd/connection.h new file mode 100644 index 0000000000..790c01f1e8 --- /dev/null +++ b/tools/xfrd/connection.h @@ -0,0 +1,32 @@ +/* $Id: connection.h,v 1.1 2003/10/17 15:48:43 mjw Exp $ */ +#ifndef _VFC_CONNECTION_H_ +#define _VFC_CONNECTION_H_ + +#include + +#include "iostream.h" + +/** A connection. + * The underlying transport is a socket. + * Contains in and out streams using the socket. + */ +typedef struct Conn { + struct sockaddr_in addr; + int sock; + IOStream *in; + IOStream *out; +} Conn; + +enum { + CONN_NOBUFFER=1, + CONN_READ_COMPRESS=2, + CONN_WRITE_COMPRESS=4, +}; + +extern int Conn_read_header(int sock, int *flags); +extern int Conn_write_header(int sock, int flags); +extern int Conn_init(Conn *conn, int flags, int sock, struct sockaddr_in addr); +extern int Conn_connect(Conn *conn, int flags, struct in_addr ipaddr, uint16_t port); +extern void Conn_close(Conn *conn); + +#endif /* ! _VFC_CONNECTION_H_ */ diff --git a/tools/xfrd/debug.h b/tools/xfrd/debug.h new file mode 100644 index 0000000000..69a6b49937 --- /dev/null +++ b/tools/xfrd/debug.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2004 Mike Wray + * + * 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.1 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 + */ +#ifndef _XUTIL_DEBUG_H_ +#define _XUTIL_DEBUG_H_ + +#ifndef MODULE_NAME +#define MODULE_NAME "" +#endif + +#ifdef __KERNEL__ +#include +#include + +#ifdef DEBUG + +#define dprintf(fmt, args...) printk(KERN_DEBUG "[DBG] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args) +#define wprintf(fmt, args...) printk(KERN_WARNING "[WRN] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args) +#define iprintf(fmt, args...) printk(KERN_INFO "[INF] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args) +#define eprintf(fmt, args...) printk(KERN_ERR "[ERR] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args) + +#else + +#define dprintf(fmt, args...) do {} while(0) +#define wprintf(fmt, args...) printk(KERN_WARNING "[WRN] " MODULE_NAME fmt, ##args) +#define iprintf(fmt, args...) printk(KERN_INFO "[INF] " MODULE_NAME fmt, ##args) +#define eprintf(fmt, args...) printk(KERN_ERR "[ERR] " MODULE_NAME fmt, ##args) + +#endif + +#else + +#include + +#ifdef DEBUG + +#define dprintf(fmt, args...) fprintf(stdout, "[DBG] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args) +#define wprintf(fmt, args...) fprintf(stderr, "[WRN] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args) +#define iprintf(fmt, args...) fprintf(stderr, "[INF] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args) +#define eprintf(fmt, args...) fprintf(stderr, "[ERR] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args) + +#else + +#define dprintf(fmt, args...) do {} while(0) +#define wprintf(fmt, args...) fprintf(stderr, "[WRN] " MODULE_NAME fmt, ##args) +#define iprintf(fmt, args...) fprintf(stderr, "[INF] " MODULE_NAME fmt, ##args) +#define eprintf(fmt, args...) fprintf(stderr, "[ERR] " MODULE_NAME fmt, ##args) + +#endif + +#endif + +/** Print format for an IP address. + * See NIPQUAD(), HIPQUAD() + */ +#define IPFMT "%u.%u.%u.%u" + +#endif /* ! _XUTIL_DEBUG_H_ */ diff --git a/tools/xfrd/enum.c b/tools/xfrd/enum.c new file mode 100644 index 0000000000..95f6e31a87 --- /dev/null +++ b/tools/xfrd/enum.c @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2002, 2004 Mike Wray + * + * 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.1 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 + */ + +#ifdef __KERNEL__ +#include +#else +#include +#endif + +#include "sys_string.h" +#include "enum.h" + +/** Map an enum name to its value using a table. + * + * @param name enum name + * @param defs enum definitions + * @return enum value or -1 if not known + */ +int enum_name_to_val(char *name, EnumDef *defs){ + int val = -1; + for(; defs->name; defs++){ + if(!strcmp(defs->name, name)){ + val = defs->val; + break; + } + } + return val; +} + +/** Map an enum value to its name using a table. + * + * @param val enum value + * @param defs enum definitions + * @param defs_n number of definitions + * @return enum name or NULL if not known + */ +char *enum_val_to_name(int val, EnumDef *defs){ + char *name = NULL; + for(; defs->name; defs++){ + if(val == defs->val){ + name = defs->name; + break; + } + } + return name; +} + diff --git a/tools/xfrd/enum.h b/tools/xfrd/enum.h new file mode 100644 index 0000000000..cdc0f6f1b1 --- /dev/null +++ b/tools/xfrd/enum.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2002, 2004 Mike Wray + * + * 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.1 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 + */ + +#ifndef _XUTIL_ENUM_H_ +#define _XUTIL_ENUM_H_ + +/** Mapping of an enum value to a name. */ +typedef struct EnumDef { + int val; + char *name; +} EnumDef; + +extern int enum_name_to_val(char *name, EnumDef *defs); +extern char *enum_val_to_name(int val, EnumDef *defs); + +#endif /* _XUTIL_ENUM_H_ */ diff --git a/tools/xfrd/hash_table.c b/tools/xfrd/hash_table.c new file mode 100644 index 0000000000..13da946e77 --- /dev/null +++ b/tools/xfrd/hash_table.c @@ -0,0 +1,640 @@ +/* + * Copyright (C) 2001 - 2004 Mike Wray + * + * 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.1 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 + */ + +#ifdef __KERNEL__ +# include +# include +# include +# include +#else +# include +# include +#endif + +//#include + +#include "allocate.h" +#include "hash_table.h" + +/** @file + * Base support for hashtables. + * + * Hash codes are reduced modulo the number of buckets to index tables, + * so there is no need for hash functions to limit the range of hashcodes. + * In fact it is assumed that hashcodes do not change when the number of + * buckets in the table changes. + */ + +/*==========================================================================*/ +/** Number of bits in half a word. */ +//#if __WORDSIZE == 64 +//#define HALF_WORD_BITS 32 +//#else +#define HALF_WORD_BITS 16 +//#endif + +/** Mask for lo half of a word. On 32-bit this is + * (1<<16) - 1 = 65535 = 0xffff + * It's 4294967295 = 0xffffffff on 64-bit. + */ +#define LO_HALF_MASK ((1 << HALF_WORD_BITS) - 1) + +/** Get the lo half of a word. */ +#define LO_HALF(x) ((x) & LO_HALF_MASK) + +/** Get the hi half of a word. */ +#define HI_HALF(x) ((x) >> HALF_WORD_BITS) + +/** Do a full hash on both inputs, using DES-style non-linear scrambling. + * Both inputs are replaced with the results of the hash. + * + * @param pleft input/output word + * @param pright input/output word + */ +void pseudo_des(unsigned long *pleft, unsigned long *pright){ + // Bit-rich mixing constant. + static const unsigned long a_mixer[] = { + 0xbaa96887L, 0x1e17d32cL, 0x03bcdc3cL, 0x0f33d1b2L, }; + + // Bit-rich mixing constant. + static const unsigned long b_mixer[] = { + 0x4b0f3b58L, 0xe874f0c3L, 0x6955c5a6L, 0x55a7ca46L, }; + + // Number of iterations - must be 2 or 4. + static const int ncycle = 4; + //static const int ncycle = 2; + + unsigned long left = *pleft, right = *pright; + unsigned long v, v_hi, v_lo; + int i; + + for(i=0; ibuckets + (hashcode % table->buckets_n); +} + +/** Initialize a hash table. + * Can be safely called more than once. + * + * @param table to initialize + */ +void HashTable_init(HashTable *table){ + int i; + + if(!table->init_done){ + table->init_done = 1; + table->next_id = 0; + for(i=0; ibuckets_n; i++){ + HTBucket *bucket = get_bucket(table, i); + bucket->head = 0; + bucket->count = 0; + } + table->entry_count = 0; + } +} + +/** Allocate a new hashtable. + * If the number of buckets is not positive the default is used. + * The number of buckets should usually be prime. + * + * @param buckets_n number of buckets + * @return new hashtable or null + */ +HashTable *HashTable_new(int buckets_n){ + HashTable *z = ALLOCATE(HashTable); + if(!z) goto exit; + if(buckets_n <= 0){ + buckets_n = HT_BUCKETS_N; + } + z->buckets = (HTBucket*)allocate(buckets_n * sizeof(HTBucket)); + if(!z->buckets){ + deallocate(z); + z = 0; + goto exit; + } + z->buckets_n = buckets_n; + HashTable_init(z); + exit: + return z; +} + +/** Free a hashtable. + * Any entries are removed and freed. + * + * @param h hashtable (ignored if null) + */ +void HashTable_free(HashTable *h){ + if(h){ + HashTable_clear(h); + deallocate(h->buckets); + deallocate(h); + } +} + +/** Push an entry on the list in the bucket for a given hashcode. + * + * @param table to add entry to + * @param hashcode for the entry + * @param entry to add + */ +static inline void push_on_bucket(HashTable *table, Hashcode hashcode, + HTEntry *entry){ + HTBucket *bucket; + HTEntry *old_head; + + bucket = get_bucket(table, hashcode); + old_head = bucket->head; + bucket->count++; + bucket->head = entry; + entry->next = old_head; +} + +/** Change the number of buckets in a hashtable. + * No-op if the number of buckets is not positive. + * Existing entries are reallocated to buckets based on their hashcodes. + * The table is unmodified if the number of buckets cannot be changed. + * + * @param table hashtable + * @param buckets_n new number of buckets + * @return 0 on success, error code otherwise + */ +int HashTable_set_buckets_n(HashTable *table, int buckets_n){ + int err = 0; + HTBucket *old_buckets = table->buckets; + int old_buckets_n = table->buckets_n; + int i; + + if(buckets_n <= 0){ + err = -EINVAL; + goto exit; + } + table->buckets = (HTBucket*)allocate(buckets_n * sizeof(HTBucket)); + if(!table->buckets){ + err = -ENOMEM; + table->buckets = old_buckets; + goto exit; + } + table->buckets_n = buckets_n; + for(i=0; ihead; entry; entry = next){ + next = entry->next; + push_on_bucket(table, entry->hashcode, entry); + } + } + deallocate(old_buckets); + exit: + return err; +} + +/** Adjust the number of buckets so the table is neither too full nor too empty. + * The table is unmodified if adjusting fails. + * + * @param table hash table + * @param buckets_min minimum number of buckets (use default if 0 or negative) + * @return 0 on success, error code otherwise + */ +int HashTable_adjust(HashTable *table, int buckets_min){ + int buckets_n = 0; + int err = 0; + if(buckets_min <= 0) buckets_min = HT_BUCKETS_N; + if(table->entry_count >= table->buckets_n){ + // The table is dense - expand it. + buckets_n = 2 * table->buckets_n; + } else if((table->buckets_n > buckets_min) && + (4 * table->entry_count < table->buckets_n)){ + // The table is more than minimum size and sparse - shrink it. + buckets_n = 2 * table->entry_count; + if(buckets_n < buckets_min) buckets_n = buckets_min; + } + if(buckets_n){ + err = HashTable_set_buckets_n(table, buckets_n); + } + return err; +} + +/** Allocate a new entry for a given value. + * + * @param value to put in the entry + * @return entry, or 0 on failure + */ +HTEntry * HTEntry_new(Hashcode hashcode, void *key, void *value){ + HTEntry *z = ALLOCATE(HTEntry); + if(z){ + z->hashcode = hashcode; + z->key = key; + z->value = value; + } + return z; +} + +/** Free an entry. + * + * @param z entry to free + */ +inline void HTEntry_free(HTEntry *z){ + if(z){ + deallocate(z); + } +} + +/** Free an entry in a hashtable. + * The table's entry_free_fn is used is defined, otherwise + * the HTEntry itself is freed. + * + * @param table hashtable + * @param entry to free + */ +inline void HashTable_free_entry(HashTable *table, HTEntry *entry){ + if(!entry)return; + if(table && table->entry_free_fn){ + table->entry_free_fn(table, entry); + } else { + HTEntry_free(entry); + } +} + +/** Get the first entry satisfying a test from the bucket for the + * given hashcode. + * + * @param table to look in + * @param hashcode indicates the bucket + * @param test_fn test to apply to elements + * @param arg first argument to calls to test_fn + * @return entry found, or 0 + */ +inline HTEntry * HashTable_find_entry(HashTable *table, Hashcode hashcode, + TableTestFn *test_fn, TableArg arg){ + HTBucket *bucket; + HTEntry *entry = 0; + HTEntry *next; + + bucket = get_bucket(table, hashcode); + for(entry = bucket->head; entry; entry = next){ + next = entry->next; + if(test_fn(arg, table, entry)){ + break; + } + } + return entry; +} + +/** Test hashtable keys for equality. + * Uses the table's key_equal_fn if defined, otherwise pointer equality. + * + * @param key1 key to compare + * @param key2 key to compare + * @return 1 if equal, 0 otherwise + */ +inline int HashTable_key_equal(HashTable *table, void *key1, void *key2){ + return (table->key_equal_fn ? table->key_equal_fn(key1, key2) : key1==key2); +} + +/** Compute the hashcode of a hashtable key. + * The table's key_hash_fn is used if defined, otherwise the address of + * the key is hashed. + * + * @param table hashtable + * @param key to hash + * @return hashcode + */ +inline Hashcode HashTable_key_hash(HashTable *table, void *key){ + return (table->key_hash_fn ? table->key_hash_fn(key) : hash_ul((unsigned long)key)); +} + +/** Test if an entry has a given key. + * + * @param arg containing key to test for + * @param table the entry is in + * @param entry to test + * @return 1 if the entry has the key, 0 otherwise + */ +static inline int has_key(TableArg arg, HashTable *table, HTEntry *entry){ + return HashTable_key_equal(table, arg.ptr, entry->key); +} + +/** Get an entry with a given key. + * + * @param table to search + * @param key to look for + * @return entry if found, null otherwise + */ +#if 0 +inline HTEntry * HashTable_get_entry(HashTable *table, void *key){ + TableArg arg = { ptr: key }; + return HashTable_find_entry(table, HashTable_key_hash(table, key), has_key, arg); +} +#else +inline HTEntry * HashTable_get_entry(HashTable *table, void *key){ + Hashcode hashcode; + HTBucket *bucket; + HTEntry *entry = 0; + HTEntry *next; + + hashcode = HashTable_key_hash(table, key); + bucket = get_bucket(table, hashcode); + for(entry = bucket->head; entry; entry = next){ + next = entry->next; + if(HashTable_key_equal(table, key, entry->key)){ + break; + } + } + return entry; +} +#endif + +/** Get the value of an entry with a given key. + * + * @param table to search + * @param key to look for + * @return value if an entry was found, null otherwise + */ +inline void * HashTable_get(HashTable *table, void *key){ + HTEntry *entry = HashTable_get_entry(table, key); + return (entry ? entry->value : 0); +} + +/** Print the buckets in a table. + * + * @param table to print + */ +void show_buckets(HashTable *table, IOStream *io){ + int i,j ; + IOStream_print(io, "entry_count=%d buckets_n=%d\n", table->entry_count, table->buckets_n); + for(i=0; ibuckets_n; i++){ + if(0 || table->buckets[i].count>0){ + IOStream_print(io, "bucket %3d %3d %10p ", i, + table->buckets[i].count, + table->buckets[i].head); + for(j = table->buckets[i].count; j>0; j--){ + IOStream_print(io, "+"); + } + IOStream_print(io, "\n"); + } + } + HashTable_print(table, io); +} + +/** Print an entry in a table. + * + * @param entry to print + * @param arg a pointer to an IOStream to print to + * @return 0 + */ +static int print_entry(TableArg arg, HashTable *table, HTEntry *entry){ + IOStream *io = (IOStream*)arg.ptr; + IOStream_print(io, " b=%4lx h=%08lx i=%08lx |-> e=%8p k=%8p v=%8p\n", + entry->hashcode % table->buckets_n, + entry->hashcode, + entry->index, + entry, entry->key, entry->value); + return 0; +} + +/** Print a hash table. + * + * @param table to print + */ +void HashTable_print(HashTable *table, IOStream *io){ + IOStream_print(io, "{\n"); + HashTable_map(table, print_entry, (TableArg){ ptr: io }); + IOStream_print(io, "}\n"); +} +/*==========================================================================*/ + +/** Get the next entry id to use for a table. + * + * @param table hash table + * @return non-zero entry id + */ +static inline unsigned long get_next_id(HashTable *table){ + unsigned long id; + + if(table->next_id == 0){ + table->next_id = 1; + } + id = table->next_id++; + return id; +} + +/** Add an entry to the bucket for the + * given hashcode. + * + * @param table to insert in + * @param hashcode indicates the bucket + * @param key to add an entry for + * @param value to add an entry for + * @return entry on success, 0 on failure + */ +inline HTEntry * HashTable_add_entry(HashTable *table, Hashcode hashcode, void *key, void *value){ + HTEntry *entry = HTEntry_new(hashcode, key, value); + if(entry){ + entry->index = get_next_id(table); + push_on_bucket(table, hashcode, entry); + table->entry_count++; + } + return entry; +} + +/** Move the front entry for a bucket to the correct point in the bucket order as + * defined by the order function. If this is called every time a new entry is added + * the bucket will be maintained in sorted order. + * + * @param table to modify + * @param hashcode indicates the bucket + * @param order entry comparison function + * @return 0 if an entry was moved, 1 if not + */ +int HashTable_order_bucket(HashTable *table, Hashcode hashcode, TableOrderFn *order){ + HTEntry *new_entry = NULL, *prev = NULL, *entry = NULL; + HTBucket *bucket; + int err = 1; + + bucket = get_bucket(table, hashcode); + new_entry = bucket->head; + if(!new_entry || !new_entry->next) goto exit; + for(entry = new_entry->next; entry; prev = entry, entry = entry->next){ + if(order(new_entry, entry) <= 0) break; + } + if(prev){ + err = 0; + bucket->head = new_entry->next; + new_entry->next = entry; + prev->next = new_entry; + } + exit: + return err; +} + +/** Add an entry to a hashtable. + * The entry is added to the bucket for its key's hashcode. + * + * @param table to insert in + * @param key to add an entry for + * @param value to add an entry for + * @return entry on success, 0 on failure + */ +inline HTEntry * HashTable_add(HashTable *table, void *key, void *value){ + return HashTable_add_entry(table, HashTable_key_hash(table, key), key, value); +} + + +/** Remove entries satisfying a test from the bucket for the + * given hashcode. + * + * @param table to remove from + * @param hashcode indicates the bucket + * @param test_fn test to apply to elements + * @param arg first argument to calls to test_fn + * @return number of entries removed + */ +inline int HashTable_remove_entry(HashTable *table, Hashcode hashcode, + TableTestFn *test_fn, TableArg arg){ + HTBucket *bucket; + HTEntry *entry, *prev = 0, *next; + int removed_count = 0; + + bucket = get_bucket(table, hashcode); + for(entry = bucket->head; entry; entry = next){ + next = entry->next; + if(test_fn(arg, table, entry)){ + if(prev){ + prev->next = next; + } else { + bucket->head = next; + } + bucket->count--; + table->entry_count--; + removed_count++; + HashTable_free_entry(table, entry); + entry = 0; + } + prev = entry; + } + return removed_count; +} + +/** Remove entries with a given key. + * + * @param table to remove from + * @param key of entries to remove + * @return number of entries removed + */ +inline int HashTable_remove(HashTable *table, void *key){ +#if 1 + Hashcode hashcode; + HTBucket *bucket; + HTEntry *entry, *prev = 0, *next; + int removed_count = 0; + + hashcode = HashTable_key_hash(table, key); + bucket = get_bucket(table, hashcode); + for(entry = bucket->head; entry; entry = next){ + next = entry->next; + if(HashTable_key_equal(table, key, entry->key)){ + if(prev){ + prev->next = next; + } else { + bucket->head = next; + } + bucket->count--; + table->entry_count--; + removed_count++; + HashTable_free_entry(table, entry); + entry = 0; + } + prev = entry; + } + return removed_count; +#else + return HashTable_remove_entry(table, HashTable_key_hash(table, key), + has_key, (TableArg){ ptr: key}); +#endif +} + +/** Remove (and free) all the entries in a bucket. + * + * @param bucket to clear + */ +static inline void bucket_clear(HashTable *table, HTBucket *bucket){ + HTEntry *entry, *next; + + for(entry = bucket->head; entry; entry = next){ + next = entry->next; + HashTable_free_entry(table, entry); + } + bucket->head = 0; + table->entry_count -= bucket->count; + bucket->count = 0; +} + +/** Remove (and free) all the entries in a table. + * + * @param table to clear + */ +void HashTable_clear(HashTable *table){ + int i, n = table->buckets_n; + + for(i=0; ibuckets + i); + } +} diff --git a/tools/xfrd/hash_table.h b/tools/xfrd/hash_table.h new file mode 100644 index 0000000000..6608b49cda --- /dev/null +++ b/tools/xfrd/hash_table.h @@ -0,0 +1,294 @@ +/* + * Copyright (C) 2001 - 2004 Mike Wray + * + * 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.1 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 + */ + +#ifndef _XUTIL_HASH_TABLE_H_ +#define _XUTIL_HASH_TABLE_H_ + +#include "iostream.h" + +typedef unsigned long Hashcode; + +/** Type used to pass parameters to table functions. */ +typedef union TableArg { + unsigned long ul; + void *ptr; +} TableArg; + +/** An entry in a bucket list. */ +typedef struct HTEntry { + /** Hashcode of the entry's key. */ + Hashcode hashcode; + /** Identifier for this entry in the table. */ + int index; + /** The key for this entry. */ + void *key; + /** The value in this entry. */ + void *value; + /** The next entry in the list. */ + struct HTEntry *next; +} HTEntry; + +/** A bucket in a rule table. */ +typedef struct HTBucket { + /** Number of entries in the bucket. */ + int count; + /** First entry in the bucket (may be null). */ + HTEntry *head; +} HTBucket; + +/** Default number of buckets in a hash table. + * You want enough buckets so the lists in the buckets will typically be short. + * It's a good idea if this is prime, since that will help to spread hashcodes + * around the table. + */ +//#define HT_BUCKETS_N 1 +//#define HT_BUCKETS_N 3 +//#define HT_BUCKETS_N 7 +//#define HT_BUCKETS_N 17 +//#define HT_BUCKETS_N 97 +//#define HT_BUCKETS_N 211 +//#define HT_BUCKETS_N 401 +#define HT_BUCKETS_N 1021 + +typedef struct HashTable HashTable; + +/** Type for a function used to select table entries. */ +typedef int TableTestFn(TableArg arg, HashTable *table, HTEntry *entry); + +/** Type for a function to map over table entries. */ +typedef int TableMapFn(TableArg arg, HashTable *table, HTEntry *entry); + +/** Type for a function to free table entries. */ +typedef void TableFreeFn(HashTable *table, HTEntry *entry); + +/** Type for a function to hash table keys. */ +typedef Hashcode TableHashFn(void *key); + +/** Type for a function to test table keys for equality. */ +typedef int TableEqualFn(void *key1, void *key2); + +/** Type for a function to order table entries. */ +typedef int TableOrderFn(HTEntry *e1, HTEntry *e2); + +/** General hash table. + * A hash table with a list in each bucket. + * Functions can be supplied for freeing entries, hashing keys, and comparing keys. + * These all default to 0, when default behaviour treating keys as integers is used. + */ +struct HashTable { + /** Flag indicating whether the table has been initialised. */ + int init_done; + /** Next value for the id field in inserted rules. */ + unsigned long next_id; + /** Number of buckets in the bucket array. */ + int buckets_n; + /** Array of buckets, each with its own list. */ + HTBucket *buckets; + /** Number of entries in the table. */ + int entry_count; + /** Function to free keys and values in entries. */ + TableFreeFn *entry_free_fn; + /** Function to hash keys. */ + TableHashFn *key_hash_fn; + /** Function to compare keys for equality. */ + TableEqualFn *key_equal_fn; + /** Place for the user of the table to hang extra data. */ + void *user_data; +}; + +extern HashTable *HashTable_new(int bucket_n); +extern void HashTable_free(HashTable *table); +extern HTEntry * HTEntry_new(Hashcode hashcode, void *key, void *value); +extern void HTEntry_free(HTEntry *entry); +extern int HashTable_set_bucket_n(HashTable *table, int bucket_n); +extern void HashTable_clear(HashTable *table); +extern HTEntry * HashTable_add_entry(HashTable *table, Hashcode hashcode, void *key, void *value); +extern HTEntry * HashTable_get_entry(HashTable *table, void *key); +extern HTEntry * HashTable_add(HashTable *table, void *key, void *value); +extern void * HashTable_get(HashTable *table, void *key); +extern int HashTable_remove(HashTable *table, void *key); +extern HTEntry * HashTable_find_entry(HashTable *table, Hashcode hashcode, + TableTestFn *test_fn, TableArg arg); +extern int HashTable_remove_entry(HashTable *table, Hashcode hashcode, + TableTestFn *test_fn, TableArg arg); +//extern int HashTable_map(HashTable *table, TableMapFn *map_fn, TableArg arg); +extern void HashTable_print(HashTable *table, IOStream *out); +extern int HashTable_set_buckets_n(HashTable *table, int buckets_n); +extern int HashTable_adjust(HashTable *table, int buckets_min); +extern void pseudo_des(unsigned long *pleft, unsigned long *pright); +extern Hashcode hash_string(char *s); + +extern int HashTable_order_bucket(HashTable *table, Hashcode hashcode, TableOrderFn *order); + +/** Control whether to use hashing based on DES or simple + * hashing. DES hashing is `more random' but much more expensive. + */ +#define HASH_PSEUDO_DES 0 + +/** Hash a long using a quick and dirty linear congruential random number generator. + * See `Numerical Recipes in C', Chapter 7, "An Even Quicker Generator". + * + * @param a value to hash + * @return hashed input + */ +static inline unsigned long lcrng_hash(unsigned long a){ + return (1664525L * a + 1013904223L); +} + +/** Hash an unsigned long. + * + * @param a input to hash + * @return hashcode + */ +static inline Hashcode hash_ul(unsigned long a){ +#if HASH_PSEUDO_DES + unsigned long left = a; + unsigned long right = 0L; + pseudo_des(&left, &right); + return right; +#else + a = lcrng_hash(a); + a = lcrng_hash(a); + return a; +#endif +} + +/** Hash two unsigned longs together. + * + * @param a input to hash + * @param b input to hash + * @return hashcode + */ +static inline Hashcode hash_2ul(unsigned long a, unsigned long b){ +#if HASH_PSEUDO_DES + unsigned long left = a; + unsigned long right = b; + pseudo_des(&left, &right); + return right; +#else + a = lcrng_hash(a); + a ^= b; + a = lcrng_hash(a); + return a; +#endif +} + +/** Hash a hashcode and an unsigned long together. + * + * @param a input hashcode + * @param b input to hash + * @return hashcode + */ +static inline Hashcode hash_hul(Hashcode a, unsigned long b){ +#if HASH_PSEUDO_DES + unsigned long left = a; + unsigned long right = b; + pseudo_des(&left, &right); + return right; +#else + a ^= b; + a = lcrng_hash(a); + return a; +#endif +} + +/** Macro to declare variables for HashTable_for_each() to use. + * + * @param entry variable that is set to entries in the table + */ +#define HashTable_for_decl(entry) \ + HashTable *_var_table; \ + HTBucket *_var_bucket; \ + HTBucket *_var_end; \ + HTEntry *_var_next; \ + HTEntry *entry + +/** Macro to iterate over the entries in a hashtable. + * Must be in a scope where HashTable_for_decl() has been used to declare + * variables for it to use. + * The variable 'entry' is iterated over entries in the table. + * The code produced is syntactically a loop, so it must be followed by + * a loop body, typically some statements in braces: + * HashTable_for_each(entry, table){ ...loop body... } + * + * HashTable_for_each() and HashTable_for_decl() cannot be used for nested + * loops as variables will clash. + * + * @note The simplest way to code a direct loop over the entries in a hashtable + * is to use a loop over the buckets, with a nested loop over the entries + * in a bucket. Using this approach in a macro means the macro contains + * an opening brace, and calls to it must be followed by 2 braces! + * To avoid this the code has been restructured so that it is a for loop. + * So that statements could be used in the test expression of the for loop, + * we have used the gcc statement expression extension ({ ... }). + * + * @param entry variable to iterate over the entries + * @param table to iterate over (non-null) + */ +#define HashTable_for_each(entry, table) \ + _var_table = table; \ + _var_bucket = _var_table->buckets; \ + _var_end = _var_bucket + _var_table->buckets_n; \ + for(entry=0, _var_next=0; \ + ({ if(_var_next){ \ + entry = _var_next; \ + _var_next = entry->next; \ + } else { \ + while(_var_bucket < _var_end){ \ + entry = _var_bucket->head; \ + _var_bucket++; \ + if(entry){ \ + _var_next = entry->next; \ + break; \ + } \ + } \ + }; \ + entry; }); \ + entry = _var_next ) + +/** Map a function over the entries in a table. + * Mapping stops when the function returns a non-zero value. + * Uses the gcc statement expression extension ({ ... }). + * + * @param table to map over + * @param fn function to apply to entries + * @param arg first argument to call the function with + * @return 0 if fn always returned 0, first non-zero value otherwise + */ +#define HashTable_map(table, fn, arg) \ + ({ HashTable_for_decl(_var_entry); \ + TableArg _var_arg = arg; \ + int _var_value = 0; \ + HashTable_for_each(_var_entry, table){ \ + if((_var_value = fn(_var_arg, _var_table, _var_entry))) break; \ + } \ + _var_value; }) + +/** Cast x to the type for a key or value in a hash table. + * This avoids compiler warnings when using short integers + * as keys or values (especially on 64-bit platforms). + */ +#define HKEY(x) ((void*)(unsigned long)(x)) + +/** Cast x from the type for a key or value in a hash table. + * to an unsigned long. This avoids compiler warnings when using + * short integers as keys or values (especially on 64-bit platforms). + */ +#define HVAL(x) ((unsigned long)(x)) + +#endif /* !_XUTIL_HASH_TABLE_H_ */ diff --git a/tools/xfrd/lexis.c b/tools/xfrd/lexis.c new file mode 100644 index 0000000000..26d2ec4d5b --- /dev/null +++ b/tools/xfrd/lexis.c @@ -0,0 +1,93 @@ +/* + * + * 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.1 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 + */ + +/** @file + * Lexical analysis. + */ + +#include "sys_string.h" +#include "lexis.h" +#include + +/** Check if a value lies in a (closed) range. + * + * @param x value to test + * @param lo low end of the range + * @param hi high end of the range + * @return 1 if x is in the interval [lo, hi], 0 otherwise + */ +inline static int in_range(int x, int lo, int hi){ + return (lo <= x) && (x <= hi); +} + +/** Determine if a string is an (unsigned) decimal number. + * + * @param s pointer to characters to test + * @param n length of string + * @return 1 if s is a decimal number, 0 otherwise. + */ +int is_decimal_number(const char *s, int n){ + int i; + if(n <= 0)return 0; + for(i = 0; i < n; i++){ + if(!in_decimal_digit_class(s[i])) return 0; + } + return 1; +} + +/** Determine if a string is a hex number. + * Hex numbers are 0, or start with 0x or 0X followed + * by a non-zero number of hex digits (0-9,a-f,A-F). + * + * @param s pointer to characters to test + * @param n length of string + * @return 1 if s is a hex number, 0 otherwise. + */ +int is_hex_number(const char *s, int n){ + int i; + if(n <= 0) return 0; + if(n == 1){ + return s[0]=='0'; + } + if(n <= 3) return 0; + if(s[0] != '0' || (s[1] != 'x' && s[1] != 'X')) return 0; + for(i = 2; i < n; i++){ + if(!in_hex_digit_class(s[i])) return 0; + } + return 1; +} + +/** Test if a string matches a keyword. + * The comparison is case-insensitive. + * The comparison fails if either argument is null. + * + * @param s string + * @param k keyword + * @return 1 if they match, 0 otherwise + */ +int is_keyword(const char *s, const char *k){ + return s && k && !strcasecmp(s, k); +} + +/** Test if a string matches a character. + * + * @param s string + * @param c character (non-null) + * @return 1 if s contains exactly c, 0 otherwise + */ +int is_keychar(const char *s, char c){ + return c && (s[0] == c) && !s[1]; +} diff --git a/tools/xfrd/lexis.h b/tools/xfrd/lexis.h new file mode 100644 index 0000000000..796a8a415a --- /dev/null +++ b/tools/xfrd/lexis.h @@ -0,0 +1,127 @@ +/* + * + * 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.1 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 + */ + +#ifndef _XUTIL_LEXIS_H_ +#define _XUTIL_LEXIS_H_ + +#include "sys_string.h" + +#ifdef __KERNEL__ +# include +#else +# include +#endif + +/** @file + * Lexical analysis. + */ + +/** Class of characters treated as space. */ +#define space_class ((char []){ '\n', '\r', '\t', ' ', '\f' , 0 }) + +/** Class of separator characters. */ +#define sep_class "{}()<>[]@!;" + +#define comment_class "#" + +/** Determine if a character is in a given class. + * + * @param c character to test + * @param s null-terminated string of characters in the class + * @return 1 if c is in the class, 0 otherwise. + */ +static inline int in_class(int c, const char *s){ + return s && (strchr(s, c) != 0); +} + +/** Determine if a character is in the space class. + * + * @param c character to test + * @return 1 if c is in the class, 0 otherwise. + */ +static inline int in_space_class(int c){ + return in_class(c, space_class); +} + +static inline int in_comment_class(int c){ + return in_class(c, comment_class); +} + +/** Determine if a character is in the separator class. + * Separator characters terminate tokens, and do not need space + * to separate them. + * + * @param c character to test + * @return 1 if c is in the class, 0 otherwise. + */ +static inline int in_sep_class(int c){ + return in_class(c, sep_class); +} + +/** Determine if a character is in the alpha class. + * + * @param c character to test + * @return 1 if c is in the class, 0 otherwise. + */ +static inline int in_alpha_class(int c){ + return isalpha(c); +} + +/** Determine if a character is in the octal digit class. + * + * @param c character to test + * @return 1 if c is in the class, 0 otherwise. + */ +static inline int in_octal_digit_class(int c){ + return '0' <= c && c <= '7'; +} + +/** Determine if a character is in the decimal digit class. + * + * @param c character to test + * @return 1 if c is in the class, 0 otherwise. + */ +static inline int in_decimal_digit_class(int c){ + return isdigit(c); +} + +/** Determine if a character is in the hex digit class. + * + * @param c character to test + * @return 1 if c is in the class, 0 otherwise. + */ +static inline int in_hex_digit_class(int c){ + return isdigit(c) || in_class(c, "abcdefABCDEF"); +} + + +static inline int in_string_quote_class(int c){ + return in_class(c, "'\""); +} + +static inline int in_printable_class(int c){ + return ('A' <= c && c <= 'Z') + || ('a' <= c && c <= 'z') + || ('0' <= c && c <= '9') + || in_class(c, "!$%&*+,-./:;<=>?@^_`{|}~"); +} + +extern int is_decimal_number(const char *s, int n); +extern int is_hex_number(const char *s, int n); +extern int is_keyword(const char *s, const char *k); +extern int is_keychar(const char *s, char c); + +#endif /* !_XUTIL_LEXIS_H_ */ diff --git a/tools/xfrd/lzi_stream.c b/tools/xfrd/lzi_stream.c new file mode 100644 index 0000000000..5fbec775c4 --- /dev/null +++ b/tools/xfrd/lzi_stream.c @@ -0,0 +1,533 @@ +/* + * Copyright (C) 2003 Hewlett-Packard Company. + * + * 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.1 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 + */ + +/** @file + * An IOStream implementation using LZI to provide compression and decompression. + * This is designed to provide compression without output latency. + * Flushing an LZI stream flushes all pending data to the underlying stream. + * This is essential for stream-based (e.g. networked) applications. + * + * A compressed data stream is a sequence of blocks. + * Each block is the block size followed by the compressed data. + * The last block has size zero. + * Sizes are 4-byte unsigned in network order. + * + * This format allows compressed data to be read from a stream without reading + * past the logical end of compressed data. + * + * @author Mike Wray + */ +#ifndef __KERNEL__ + +#include +#include +#include +#include + +#include "zlib.h" + +#include "allocate.h" +#include "lzi_stream.h" +#include "file_stream.h" +#include "marshal.h" + +#define dprintf(fmt, args...) fprintf(stdout, "[DEBUG] LZI>%s" fmt, __FUNCTION__, ##args) +#define wprintf(fmt, args...) fprintf(stderr, "[WARN] LZI>%s" fmt, __FUNCTION__, ##args) +#define iprintf(fmt, args...) fprintf(stdout, "[INFO] LZI>%s" fmt, __FUNCTION__, ##args) +#define eprintf(fmt, args...) fprintf(stderr, "[ERROR] LZI>%s" fmt, __FUNCTION__, ##args) + +static int lzi_read(IOStream *s, void *buf, size_t n); +static int lzi_write(IOStream *s, const void *buf, size_t n); +static int lzi_error(IOStream *s); +static int lzi_close(IOStream *s); +static void lzi_free(IOStream *s); +static int lzi_flush(IOStream *s); + +enum { + LZI_WRITE = 1, + LZI_READ = 2, +}; + +/** Methods used by a gzFile* IOStream. */ +static const IOMethods lzi_methods = { + read: lzi_read, + write: lzi_write, + error: lzi_error, + close: lzi_close, + free: lzi_free, + flush: lzi_flush, +}; + +#define BUFFER_SIZE (512 * 1024) + +typedef struct LZIState { + z_stream zstream; + void *inbuf; + uint32_t inbuf_size; + void *outbuf; + uint32_t outbuf_size; + /** Underlying stream for I/O. */ + IOStream *io; + /** Flags. */ + int flags; + /** Error indicator. */ + int error; + int eof; + int plain_bytes; + int comp_bytes; + int zstream_initialized; + int flushed; +} LZIState; + +static inline int LZIState_writeable(LZIState *s){ + return (s->flags & LZI_WRITE) != 0; +} + +static inline int LZIState_readable(LZIState *s){ + return (s->flags & LZI_READ) != 0; +} + +void LZIState_free(LZIState *z){ + if(!z) return; + if(z->zstream_initialized){ + if(LZIState_writeable(z)){ + deflateEnd(&z->zstream); + } else if(LZIState_readable(z)){ + inflateEnd(&z->zstream); + } + } + deallocate(z->inbuf); + deallocate(z->outbuf); + deallocate(z); +} + +static int mode_flags(const char *mode, int *flags){ + int err = 0; + int r=0, w=0; + if(!mode){ + err = -EINVAL; + goto exit; + } + for(; *mode; mode++){ + if(*mode == 'w') w = 1; + if(*mode == 'r') r = 1; + } + if(r + w != 1){ + err = -EINVAL; + goto exit; + } + if(r) *flags |= LZI_READ; + if(w) *flags |= LZI_WRITE; + exit: + return err; +} + +/** Get the stream state. + * + * @param s lzi stream + * @return stream state. + */ +static inline LZIState * lzi_state(IOStream *io){ + return (LZIState*)io->data; +} + +IOStream *lzi_stream_io(IOStream *io){ + LZIState *s = lzi_state(io); + return s->io; +} + +static inline void set_error(LZIState *s, int err){ + if(err < 0 && !s->error){ + s->error = err; + } +} + +static int zerror(LZIState *s, int err){ + if(err){ + //dprintf("> err=%d\n", err); + if(err < 0) set_error(s, -EIO); + } + return s->error; +} + +int lzi_stream_plain_bytes(IOStream *io){ + LZIState *s = lzi_state(io); + return s->plain_bytes; +} + +int lzi_stream_comp_bytes(IOStream *io){ + LZIState *s = lzi_state(io); + return s->comp_bytes; +} + +float lzi_stream_ratio(IOStream *io){ + LZIState *s = lzi_state(io); + float ratio = 0.0; + if(s->comp_bytes){ + ratio = ((float) s->comp_bytes)/((float) s->plain_bytes); + } + return ratio; +} + +static int alloc(void **p, int n){ + *p = allocate(n); + return (p ? 0 : -ENOMEM); +} + +LZIState * LZIState_new(IOStream *io, int flags){ + int err = -ENOMEM; + int zlevel = Z_BEST_SPEED; // Level 1 compression - fastest. + int zstrategy = Z_DEFAULT_STRATEGY; + int zwindow = MAX_WBITS; + int zmemory = 8; + LZIState *z = ALLOCATE(LZIState); + + //dprintf(">\n"); + if(!z) goto exit; + z->io = io; + z->flags = flags; + + if(LZIState_writeable(z)){ + z->outbuf_size = BUFFER_SIZE; + /* windowBits is passed < 0 to suppress zlib header */ + err = deflateInit2(&z->zstream, zlevel, Z_DEFLATED, -zwindow, zmemory, zstrategy); + if (err != Z_OK) goto exit; + z->zstream_initialized = 1; + err = alloc(&z->outbuf, z->outbuf_size); + if(err) goto exit; + z->zstream.next_out = z->outbuf; + z->zstream.avail_out = z->outbuf_size; + } else { + z->inbuf_size = BUFFER_SIZE; + err = alloc(&z->inbuf, z->inbuf_size); + if(err) goto exit; + ///z->zstream.next_in = z->inbuf; + + /* windowBits is passed < 0 to tell that there is no zlib header. + * Note that in this case inflate *requires* an extra "dummy" byte + * after the compressed stream in order to complete decompression and + * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are + * present after the compressed stream. + */ + err = inflateInit2(&z->zstream, -zwindow); + if(err != Z_OK) goto exit; + z->zstream_initialized = 1; + } + + exit: + if(err){ + LZIState_free(z); + z = NULL; + } + //dprintf("< z=%p\n", z); + return z; +} + +int read_block(LZIState *s){ + int err = 0, k = 0; + //dprintf(">\n"); + if(s->eof) goto exit; + err = unmarshal_uint32(s->io, &k); + if(err) goto exit; + if(k > s->inbuf_size){ + err = -EINVAL; + goto exit; + } + if(k){ + err = unmarshal_bytes(s->io, s->inbuf, k); + if(err) goto exit; + } else { + s->eof = 1; + } + s->zstream.avail_in = k; + s->zstream.next_in = s->inbuf; + s->comp_bytes += 4; + s->comp_bytes += k; + exit: + //dprintf("< err=%d\n", err); + return err; +} + +int write_block(LZIState *s){ + int err = 0; + int k = ((char*)s->zstream.next_out) - ((char*)s->outbuf); + //int k2 = s->outbuf_size - s->zstream.avail_out; + //dprintf("> k=%d k2=%d\n", k, k2); + if(!k) goto exit; + err = marshal_uint32(s->io, k); + if(err) goto exit; + err = marshal_bytes(s->io, s->outbuf, k); + if(err) goto exit; + s->zstream.next_out = s->outbuf; + s->zstream.avail_out = s->outbuf_size; + s->comp_bytes += 4; + s->comp_bytes += k; + exit: + //dprintf("< err=%d\n", err); + return err; +} + +int write_terminator(LZIState *s){ + int err = 0; + char c = 0; + err = marshal_uint32(s->io, 1); + if(err) goto exit; + err = marshal_bytes(s->io, &c, 1); + if(err) goto exit; + err = marshal_uint32(s->io, 0); + if(err) goto exit; + s->comp_bytes += 9; + exit: + return err; +} + +/** Write to the underlying stream using fwrite(); + * + * @param io destination + * @param buf data + * @param n number of bytes to write + * @return number of bytes written + */ +static int lzi_write(IOStream *io, const void *buf, size_t n){ + int err = 0; + LZIState *s = lzi_state(io); + + //dprintf("> buf=%p n=%d\n", buf, n); + if(!LZIState_writeable(s)){ + err = -EINVAL; + goto exit; + } + s->flushed = 0; + s->zstream.next_in = (void*)buf; + s->zstream.avail_in = n; + while(s->zstream.avail_in){ + if(s->zstream.avail_out == 0){ + err = write_block(s); + if(err) goto exit; + } + //dprintf("> 1 deflate avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out); + //dprintf("> 1 deflate next_in=%p next_out=%p\n", s->zstream.next_in, s->zstream.next_out); + err = zerror(s, deflate(&s->zstream, Z_NO_FLUSH)); + //dprintf("> 2 deflate avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out); + //dprintf("> 2 deflate next_in=%p next_out=%p\n", s->zstream.next_in, s->zstream.next_out); + if(err) goto exit; + } + err = n; + s->plain_bytes += n; + exit: + //dprintf("< err=%d\n", err); + return err; +} + + +/** Read from the underlying stream. + * + * @param io input + * @param buf where to put input + * @param n number of bytes to read + * @return number of bytes read + */ +static int lzi_read(IOStream *io, void *buf, size_t n){ + int err, zerr; + LZIState *s = lzi_state(io); + + //dprintf("> n=%d\n", n); + if(!LZIState_readable(s)){ + err = -EINVAL; + goto exit; + } + s->zstream.next_out = buf; + s->zstream.avail_out = n; + while(s->zstream.avail_out){ + if(s->zstream.avail_in == 0){ + err = read_block(s); + } + //dprintf("> 1 deflate avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out); + zerr = inflate(&s->zstream, Z_NO_FLUSH); + //dprintf("> 2 deflate avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out); + if(zerr == Z_STREAM_END) break; + //dprintf("> zerr=%d\n", zerr); + err = zerror(s, zerr); + if(err) goto exit; + } + err = n - s->zstream.avail_out; + s->plain_bytes += err; + exit: + set_error(s, err); + //dprintf("< err=%d\n", err); + return err; +} + +static int flush_output(LZIState *s, int mode){ + int err = 0, zerr; + int done = 0; + int avail_out_old; + + //dprintf("> avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out); + if(s->flushed == 1 + mode) goto exit; + //s->zstream.avail_in = 0; /* should be zero already anyway */ + for(;;){ + // Write any available output. + if(done || s->zstream.avail_out == 0){ + err = write_block(s); + if(err) goto exit; + if(done) break; + } + //dprintf("> 1 deflate avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out); + avail_out_old = s->zstream.avail_out; + zerr = deflate(&s->zstream, mode); + err = zerror(s, zerr); + //dprintf("> 2 deflate avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out); + //dprintf("> deflate=%d\n", err); + //done = (s->zstream.avail_out != 0); + //done = (s->zstream.avail_in == 0) && (s->zstream.avail_out == avail_out_old); + if(0 && mode == Z_FINISH){ + done = (zerr == Z_STREAM_END); + } else { + done = (s->zstream.avail_in == 0) + //&& (s->zstream.avail_out == avail_out_old) + && (s->zstream.avail_out != 0); + } + } + s->flushed = 1 + mode; + exit: + //dprintf("< err=%d\n", err); + return err; +} + +/** Flush any pending input to the underlying stream. + * + * @param s lzi stream + * @return 0 on success, error code otherwise + */ +static int lzi_flush(IOStream *io){ + int err = 0; + LZIState *s = lzi_state(io); + //dprintf(">\n"); + if(!LZIState_writeable(s)){ + err = -EINVAL; + goto exit; + } + err = flush_output(s, Z_SYNC_FLUSH); + if(err) goto exit; + err = IOStream_flush(s->io); + exit: + set_error(s, err); + //dprintf("< err=%d\n", err); + return (err < 0 ? err : 0); +} + +/** Check if a stream has an error. + * + * @param s lzi stream + * @return code if has an error, 0 otherwise + */ +static int lzi_error(IOStream *s){ + int err = 0; + LZIState *state = lzi_state(s); + err = state->error; + if(err) goto exit; + err = IOStream_error(state->io); + exit: + return err; +} + +/** Close an lzi stream. + * + * @param s lzi stream to close + * @return result of the close + */ +static int lzi_close(IOStream *io){ + int err = 0; + LZIState *s = lzi_state(io); + if(LZIState_writeable(s)){ + err = flush_output(s, Z_FINISH); + if(err) goto exit; + err = write_terminator(s); + if(err) goto exit; + err = IOStream_flush(s->io); + } + exit: + err = IOStream_close(s->io); + set_error(s, err); + return err; +} + +/** Free an lzi stream. + * + * @param s lzi stream + */ +static void lzi_free(IOStream *s){ + LZIState *state = lzi_state(s); + IOStream_free(state->io); + LZIState_free(state); + s->data = NULL; +} + +/** Create an lzi stream for an IOStream. + * + * @param io stream to wrap + * @return new IOStream using f for i/o + */ +IOStream *lzi_stream_new(IOStream *io, const char *mode){ + int err = -ENOMEM; + int flags = 0; + IOStream *zio = NULL; + LZIState *state = NULL; + + zio = ALLOCATE(IOStream); + if(!zio) goto exit; + err = mode_flags(mode, &flags); + if(err) goto exit; + state = LZIState_new(io, flags); + if(!state) goto exit; + err = 0; + zio->data = state; + zio->methods = &lzi_methods; + exit: + if(err){ + if(state) LZIState_free(state); + if(zio) deallocate(zio); + zio = NULL; + } + return zio; +} + +/** IOStream version of fdopen(). + * + * @param fd file descriptor + * @param flags giving the mode to open in (as for fdopen()) + * @return new stream for the open file, or NULL if failed + */ +IOStream *lzi_stream_fdopen(int fd, const char *mode){ + int err = -ENOMEM; + IOStream *io = NULL, *zio = NULL; + io = file_stream_fdopen(fd, mode); + if(!io) goto exit; + zio = lzi_stream_new(io, mode); + if(!io) goto exit; + err = 0; + exit: + if(err){ + IOStream_free(io); + IOStream_free(zio); + zio = NULL; + } + return zio; +} +#endif diff --git a/tools/xfrd/lzi_stream.h b/tools/xfrd/lzi_stream.h new file mode 100644 index 0000000000..959059eccf --- /dev/null +++ b/tools/xfrd/lzi_stream.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2003 Hewlett-Packard Company. + * + * 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.1 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 + */ + +#ifndef _XUTIL_LZI_STREAM_H_ +#define _XUTIL_LZI_STREAM_H_ + +#ifndef __KERNEL__ +#include "iostream.h" + +extern IOStream *lzi_stream_new(IOStream *io, const char *mode); +extern IOStream *lzi_stream_fopen(const char *file, const char *mode); +extern IOStream *lzi_stream_fdopen(int fd, const char *mode); +extern IOStream *lzi_stream_io(IOStream *zio); + +extern int lzi_stream_plain_bytes(IOStream *io); +extern int lzi_stream_comp_bytes(IOStream *io); +extern float lzi_stream_ratio(IOStream *io); + +#endif +#endif /* !_XUTIL_LZI_STREAM_H_ */ diff --git a/tools/xfrd/marshal.c b/tools/xfrd/marshal.c new file mode 100644 index 0000000000..21691d4412 --- /dev/null +++ b/tools/xfrd/marshal.c @@ -0,0 +1,207 @@ +#include +#include "sys_net.h" +#include "allocate.h" +#include "marshal.h" + +#define dprintf(fmt, args...) IOStream_print(iostdout, "[DEBUG] %s" fmt, __FUNCTION__, ##args) +#define wprintf(fmt, args...) IOStream_print(iostderr, "[WARN] %s" fmt, __FUNCTION__, ##args) +#define iprintf(fmt, args...) IOStream_print(iostdout, "[INFO] %s" fmt, __FUNCTION__, ##args) +#define eprintf(fmt, args...) IOStream_print(iostderr, "[ERROR] %s" fmt, __FUNCTION__, ##args) + + +#define ARRAY_SIZE(ary) (sizeof(ary)/sizeof((ary)[0])) + +/* Messages are coded as msgid followed by message fields. + * Initial message on any channel is hello - so can check version + * compatibility. + * + * char* -> uint16_t:n + * ints/uints go as suitable number of bytes (e.g. uint16_t is 2 bytes). + * optional fields go as '1' or '0' (the 0/1 is 1 byte). + * lists go as ('1' )* '0' + */ + +int marshal_flush(IOStream *io){ + int err = 0; + err = IOStream_flush(io); + return err; +} + +int marshal_bytes(IOStream *io, void *s, uint32_t s_n){ + int err = 0; + int n; + n = IOStream_write(io, s, s_n); + if(n < 0){ + err = n; + } else if (n < s_n){ + wprintf("> Wanted %d, got %d\n", s_n, n); + err = -EIO; + } + return err; +} + +int unmarshal_bytes(IOStream *io, void *s, uint32_t s_n){ + int err = 0; + int n; + //dprintf("> s_n=%d\n", s_n); + n = IOStream_read(io, s, s_n); + //dprintf("> n=%d\n", n); + if(n < 0){ + err = n; + } else if(n < s_n){ + wprintf("> Wanted %d, got %d\n", s_n, n); + err = -EIO; + } + //dprintf("< err=%d\n", err); + return err; +} + +int marshal_uint8(IOStream *io, uint8_t x){ + return marshal_bytes(io, &x, sizeof(x)); +} + +int unmarshal_uint8(IOStream *io, uint8_t *x){ + return unmarshal_bytes(io, x, sizeof(*x)); +} + +int marshal_uint16(IOStream *io, uint16_t x){ + x = htons(x); + return marshal_bytes(io, &x, sizeof(x)); +} + +int unmarshal_uint16(IOStream *io, uint16_t *x){ + int err = 0; + err = unmarshal_bytes(io, x, sizeof(*x)); + *x = ntohs(*x); + return err; +} + +int marshal_int32(IOStream *io, int32_t x){ + int err = 0; + //dprintf("> x=%d\n", x); + x = htonl(x); + err = marshal_bytes(io, &x, sizeof(x)); + //dprintf("< err=%d\n", err); + return err; +} + +int unmarshal_int32(IOStream *io, int32_t *x){ + int err = 0; + //dprintf(">\n"); + err = unmarshal_bytes(io, x, sizeof(*x)); + *x = ntohl(*x); + //dprintf("< err=%d x=%d\n", err, *x); + return err; +} + +int marshal_uint32(IOStream *io, uint32_t x){ + int err = 0; + //dprintf("> x=%u\n", x); + x = htonl(x); + err = marshal_bytes(io, &x, sizeof(x)); + //dprintf("< err=%d\n", err); + return err; +} + +int unmarshal_uint32(IOStream *io, uint32_t *x){ + int err = 0; + //dprintf(">\n"); + err = unmarshal_bytes(io, x, sizeof(*x)); + *x = ntohl(*x); + //dprintf("< err=%d x=%u\n", err, *x); + return err; +} + +int marshal_uint64(IOStream *io, uint64_t x){ + int err; + err = marshal_uint32(io, (uint32_t) ((x >> 32) & 0xffffffff)); + if(err) goto exit; + err = marshal_uint32(io, (uint32_t) ( x & 0xffffffff)); + exit: + return err; +} + +int unmarshal_uint64(IOStream *io, uint64_t *x){ + int err = 0; + uint32_t hi, lo; + err = unmarshal_uint32(io, &hi); + if(err) goto exit; + err = unmarshal_uint32(io, &lo); + *x = (((uint64_t) hi) << 32) | lo; + exit: + return err; +} + +int marshal_net16(IOStream *io, net16_t x){ + return marshal_bytes(io, &x, sizeof(x)); +} + +int unmarshal_net16(IOStream *io, net16_t *x){ + int err = 0; + err = unmarshal_bytes(io, x, sizeof(*x)); + return err; +} + +int marshal_net32(IOStream *io, net32_t x){ + return marshal_bytes(io, &x, sizeof(x)); +} + +int unmarshal_net32(IOStream *io, net32_t *x){ + int err = 0; + err = unmarshal_bytes(io, x, sizeof(*x)); + return err; +} + +int marshal_string(IOStream *io, char *s, uint32_t s_n){ + int err; + //dprintf("> s=%s\n", s); + err = marshal_uint32(io, s_n); + if(err) goto exit; + err = marshal_bytes(io, s, s_n); + exit: + //dprintf("< err=%d\n", err); + return err; +} + +int unmarshal_string(IOStream *io, char *s, uint32_t s_n){ + int err = 0, val_n = 0; + //dprintf(">\n"); + err = unmarshal_uint32(io, &val_n); + if(err) goto exit; + if(val_n >= s_n){ + err = -EINVAL; + goto exit; + } + err = unmarshal_bytes(io, s, val_n); + if(err) goto exit; + s[val_n] = '\0'; + exit: + //dprintf("< err=%d s=%s\n", err, s); + return err; +} + +int unmarshal_new_string(IOStream *io, char **s, uint32_t *s_n){ + int err = 0, val_n = 0; + char *val = NULL; + //dprintf(">\n"); + err = unmarshal_uint32(io, &val_n); + if(err) goto exit; + val = allocate(val_n + 1); + if(!val){ + err = -ENOMEM; + goto exit; + } + err = unmarshal_bytes(io, val, val_n); + if(err) goto exit; + val[val_n] = '\0'; + exit: + if(err){ + if(val) deallocate(val); + val = NULL; + val_n = 0; + } + *s = val; + if(s_n) *s_n = val_n; + //dprintf("< err=%d s=%s\n", err, *s); + return err; +} diff --git a/tools/xfrd/marshal.h b/tools/xfrd/marshal.h new file mode 100644 index 0000000000..65e9682cea --- /dev/null +++ b/tools/xfrd/marshal.h @@ -0,0 +1,42 @@ +#ifndef _XUTIL_MARSHAL_H_ +#define _XUTIL_MARSHAL_H_ + +#include "iostream.h" + +/** A 16-bit uint in network order, e.g. a port number. */ +typedef uint16_t net16_t; + +/** A 32-bit uint in network order, e.g. an IP address. */ +typedef uint32_t net32_t; + +extern int marshal_flush(IOStream *io); + +extern int marshal_bytes(IOStream *io, void *s, uint32_t s_n); +extern int unmarshal_bytes(IOStream *io, void *s, uint32_t s_n); + +extern int marshal_uint8(IOStream *io, uint8_t x); +extern int unmarshal_uint8(IOStream *io, uint8_t *x); + +extern int marshal_uint16(IOStream *io, uint16_t x); +extern int unmarshal_uint16(IOStream *io, uint16_t *x); + +extern int marshal_uint32(IOStream *io, uint32_t x); +extern int unmarshal_uint32(IOStream *io, uint32_t *x); + +extern int marshal_int32(IOStream *io, int32_t x); +extern int unmarshal_int32(IOStream *io, int32_t *x); + +extern int marshal_uint64(IOStream *io, uint64_t x); +extern int unmarshal_uint64(IOStream *io, uint64_t *x); + +extern int marshal_net16(IOStream *io, net16_t x); +extern int unmarshal_net16(IOStream *io, net16_t *x); + +extern int marshal_net32(IOStream *io, net32_t x); +extern int unmarshal_net32(IOStream *io, net32_t *x); + +extern int marshal_string(IOStream *io, char *s, uint32_t s_n); +extern int unmarshal_string(IOStream *io, char *s, uint32_t s_n); +extern int unmarshal_new_string(IOStream *io, char **s, uint32_t *s_n); + +#endif /* ! _XUTIL_MARSHAL_H_ */ diff --git a/tools/xfrd/select.c b/tools/xfrd/select.c new file mode 100644 index 0000000000..bdaccfe000 --- /dev/null +++ b/tools/xfrd/select.c @@ -0,0 +1,50 @@ +#include +#include +#include + +#include "select.h" + +/** Zero all the file descriptor sets. + * + * @param set select set + * @param fd file descriptor + * @return 0 on success, -1 otherwise + */ +void SelectSet_zero(SelectSet *set){ + set->n = 0; + FD_ZERO(&set->rd); + FD_ZERO(&set->wr); + FD_ZERO(&set->er); +} + +/** Add a file descriptor to the write set. + * + * @param set select set + * @param fd file descriptor + * @return 0 on success, -1 otherwise + */ +void SelectSet_add_read(SelectSet *set, int fd){ + FD_SET(fd, &set->rd); + if(fd > set->n) set->n = fd; +} + +/** Add a file descriptor to the write set. + * + * @param set select set + * @param fd file descriptor + * @return 0 on success, -1 otherwise + */ +void SelectSet_add_write(SelectSet *set, int fd){ + FD_SET(fd, &set->wr); + if(fd > set->n) set->n = fd; +} + +/** Select on file descriptors. + * + * @param set select set + * @param timeout timeout (may be NULL for no timeout) + * @return 0 on success, -1 otherwise + */ +int SelectSet_select(SelectSet *set, struct timeval *timeout){ + return select(set->n+1, &set->rd, &set->wr, &set->er, timeout); +} diff --git a/tools/xfrd/select.h b/tools/xfrd/select.h new file mode 100644 index 0000000000..2453f98536 --- /dev/null +++ b/tools/xfrd/select.h @@ -0,0 +1,16 @@ +#ifndef _XFRD_SELECT_H_ +#define _XFRD_SELECT_H_ + +/** Set of file descriptors for select. + */ +typedef struct SelectSet { + int n; + fd_set rd, wr, er; +} SelectSet; + +extern void SelectSet_zero(SelectSet *set); +extern void SelectSet_add_read(SelectSet *set, int fd); +extern void SelectSet_add_write(SelectSet *set, int fd); +extern int SelectSet_select(SelectSet *set, struct timeval *timeout); + +#endif /* ! _XFRD_SELECT_H_ */ diff --git a/tools/xfrd/sxpr.c b/tools/xfrd/sxpr.c new file mode 100644 index 0000000000..81fd14801c --- /dev/null +++ b/tools/xfrd/sxpr.c @@ -0,0 +1,950 @@ +/* + * + * 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.1 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 +#include "sys_string.h" +#include "lexis.h" +#include "sys_net.h" +#include "hash_table.h" +#include "sxpr.h" + +#include +#undef free + +/** @file + * General representation of sxprs. + * Includes print, equal, and free functions for the sxpr types. + * + * Zero memory containing an Sxpr will have the value ONONE - this is intentional. + * When a function returning an sxpr cannot allocate memory we return ONOMEM. + * + */ + +static int atom_print(IOStream *io, Sxpr obj, unsigned flags); +static int atom_equal(Sxpr x, Sxpr y); +static void atom_free(Sxpr obj); + +static int string_print(IOStream *io, Sxpr obj, unsigned flags); +static int string_equal(Sxpr x, Sxpr y); +static void string_free(Sxpr obj); + +static int cons_print(IOStream *io, Sxpr obj, unsigned flags); +static int cons_equal(Sxpr x, Sxpr y); +static void cons_free(Sxpr obj); + +static int null_print(IOStream *io, Sxpr obj, unsigned flags); +static int none_print(IOStream *io, Sxpr obj, unsigned flags); +static int int_print(IOStream *io, Sxpr obj, unsigned flags); +static int bool_print(IOStream *io, Sxpr obj, unsigned flags); + +/** Type definitions. */ +static SxprType types[1024] = { + [T_NONE] { type: T_NONE, name: "none", print: none_print }, + [T_NULL] { type: T_NULL, name: "null", print: null_print }, + [T_UINT] { type: T_UINT, name: "int", print: int_print, }, + [T_BOOL] { type: T_BOOL, name: "bool", print: bool_print, }, + [T_ATOM] { type: T_ATOM, name: "atom", print: atom_print, + pointer: TRUE, + free: atom_free, + equal: atom_equal, + }, + [T_STRING] { type: T_STRING, name: "string", print: string_print, + pointer: TRUE, + free: string_free, + equal: string_equal, + }, + [T_CONS] { type: T_CONS, name: "cons", print: cons_print, + pointer: TRUE, + free: cons_free, + equal: cons_equal, + }, +}; + +/** Number of entries in the types array. */ +static int type_sup = sizeof(types)/sizeof(types[0]); + +/** Get the type definition for a given type code. + * + * @param ty type code + * @return type definition or null + */ +SxprType *get_sxpr_type(int ty){ + if(0 <= ty && ty < type_sup){ + return types+ty; + } + return NULL; +} + +/** The default print function. + * + * @param io stream to print to + * @param x sxpr to print + * @param flags print flags + * @return number of bytes written on success + */ +int default_print(IOStream *io, Sxpr x, unsigned flags){ + return IOStream_print(io, "#<%u %lu>\n", get_type(x), get_ul(x)); +} + +/** The default equal function. + * Uses eq(). + * + * @param x sxpr to compare + * @param y sxpr to compare + * @return 1 if equal, 0 otherwise + */ +int default_equal(Sxpr x, Sxpr y){ + return eq(x, y); +} + +/** General sxpr print function. + * Prints an sxpr on a stream using the print function for the sxpr type. + * Printing is controlled by flags from the PrintFlags enum. + * If PRINT_TYPE is in the flags the sxpr type is printed before the sxpr + * (for debugging). + * + * @param io stream to print to + * @param x sxpr to print + * @param flags print flags + * @return number of bytes written + */ +int objprint(IOStream *io, Sxpr x, unsigned flags){ + SxprType *def = get_sxpr_type(get_type(x)); + ObjPrintFn *print_fn = (def && def->print ? def->print : default_print); + int k = 0; + if(!io) return k; + if(flags & PRINT_TYPE){ + k += IOStream_print(io, "%s:", def->name); + } + k += print_fn(io, x, flags); + return k; +} + +/** General sxpr free function. + * Frees an sxpr using the free function for its type. + * Free functions must recursively free any subsxprs. + * If no function is defined then the default is to + * free sxprs whose type has pointer true. + * Sxprs must not be used after freeing. + * + * @param x sxpr to free + */ +void objfree(Sxpr x){ + SxprType *def = get_sxpr_type(get_type(x)); + + if(def){ + if(def->free){ + def->free(x); + } else if (def->pointer){ + hfree(x); + } + } +} + +/** General sxpr equality function. + * Compares x and y using the equal function for x. + * Uses default_equal() if x has no equal function. + * + * @param x sxpr to compare + * @param y sxpr to compare + * @return 1 if equal, 0 otherwise + */ +int objequal(Sxpr x, Sxpr y){ + SxprType *def = get_sxpr_type(get_type(x)); + ObjEqualFn *equal_fn = (def && def->equal ? def->equal : default_equal); + return equal_fn(x, y); +} + +/** Search for a key in an alist. + * An alist is a list of conses, where the cars + * of the conses are the keys. Compares keys using equality. + * + * @param k key + * @param l alist to search + * @return first element of l with car k, or ONULL + */ +Sxpr assoc(Sxpr k, Sxpr l){ + for( ; CONSP(l) ; l = CDR(l)){ + Sxpr x = CAR(l); + if(CONSP(x) && objequal(k, CAR(x))){ + return x; + } + } + return ONULL; +} + +/** Search for a key in an alist. + * An alist is a list of conses, where the cars + * of the conses are the keys. Compares keys using eq. + * + * @param k key + * @param l alist to search + * @return first element of l with car k, or ONULL + */ +Sxpr assocq(Sxpr k, Sxpr l){ + for( ; CONSP(l); l = CDR(l)){ + Sxpr x = CAR(l); + if(CONSP(x) && eq(k, CAR(x))){ + return x; + } + } + return ONULL; +} + +/** Add a new key and value to an alist. + * + * @param k key + * @param l value + * @param l alist + * @return l with the new cell added to the front + */ +Sxpr acons(Sxpr k, Sxpr v, Sxpr l){ + Sxpr x, y; + x = cons_new(k, v); + if(NOMEMP(x)) return x; + y = cons_new(x, l); + if(NOMEMP(y)) cons_free_cells(x); + return y; +} + +/** Test if a list contains an element. + * Uses sxpr equality. + * + * @param l list + * @param x element to look for + * @return a tail of l with x as car, or ONULL + */ +Sxpr cons_member(Sxpr l, Sxpr x){ + for( ; CONSP(l) && !eq(x, CAR(l)); l = CDR(l)){} + return l; +} + +/** Test if a list contains an element satisfying a test. + * The test function is called with v and an element of the list. + * + * @param l list + * @param test_fn test function to use + * @param v value for first argument to the test + * @return a tail of l with car satisfying the test, or 0 + */ +Sxpr cons_member_if(Sxpr l, ObjEqualFn *test_fn, Sxpr v){ + for( ; CONSP(l) && !test_fn(v, CAR(l)); l = CDR(l)){ } + return l; +} + +/** Test if the elements of list 't' are a subset of the elements + * of list 's'. Element order is not significant. + * + * @param s element list to check subset of + * @param t element list to check if is a subset + * @return 1 if is a subset, 0 otherwise + */ +int cons_subset(Sxpr s, Sxpr t){ + for( ; CONSP(t); t = CDR(t)){ + if(!CONSP(cons_member(s, CAR(t)))){ + return 0; + } + } + return 1; +} + +/** Test if two lists have equal sets of elements. + * Element order is not significant. + * + * @param s list to check + * @param t list to check + * @return 1 if equal, 0 otherwise + */ +int cons_set_equal(Sxpr s, Sxpr t){ + return cons_subset(s, t) && cons_subset(t, s); +} + +#ifdef USE_GC +/*============================================================================*/ +/* The functions inside this ifdef are only safe if GC is used. + * Otherwise they may leak memory. + */ + +/** Remove an element from a list (GC only). + * Uses sxpr equality and removes all instances, even + * if there are more than one. + * + * @param l list to remove elements from + * @param x element to remove + * @return modified input list + */ +Sxpr cons_remove(Sxpr l, Sxpr x){ + return cons_remove_if(l, eq, x); +} + +/** Remove elements satisfying a test (GC only). + * The test function is called with v and an element of the set. + * + * @param l list to remove elements from + * @param test_fn function to use to decide if an element should be removed + * @return modified input list + */ +Sxpr cons_remove_if(Sxpr l, ObjEqualFn *test_fn, Sxpr v){ + Sxpr prev = ONULL, elt, next; + + for(elt = l; CONSP(elt); elt = next){ + next = CDR(elt); + if(test_fn(v, CAR(elt))){ + if(NULLP(prev)){ + l = next; + } else { + CDR(prev) = next; + } + } + } + return l; +} + +/** Set the value for a key in an alist (GC only). + * If the key is present, changes the value, otherwise + * adds a new cell. + * + * @param k key + * @param v value + * @param l alist + * @return modified or extended list + */ +Sxpr setf(Sxpr k, Sxpr v, Sxpr l){ + Sxpr e = assoc(k, l); + if(NULLP(e)){ + l = acons(k, v, l); + } else { + CAR(CDR(e)) = v; + } + return l; +} +/*============================================================================*/ +#endif /* USE_GC */ + +/** Create a new atom with the given name. + * + * @param name the name + * @return new atom + */ +Sxpr atom_new(char *name){ + Sxpr n, obj = ONOMEM; + + n = string_new(name); + if(NOMEMP(n)) goto exit; + obj = HALLOC(ObjAtom, T_ATOM); + if(NOMEMP(obj)) goto exit; + OBJ_ATOM(obj)->name = n; + exit: + return obj; +} + +/** Free an atom. + * + * @param obj to free + */ +void atom_free(Sxpr obj){ + // Interned atoms are shared, so do not free. + if(OBJ_ATOM(obj)->interned) return; + objfree(OBJ_ATOM(obj)->name); + hfree(obj); +} + +/** Print an atom. Prints the atom name. + * + * @param io stream to print to + * @param obj to print + * @param flags print flags + * @return number of bytes printed + */ +int atom_print(IOStream *io, Sxpr obj, unsigned flags){ + //return string_print(io, OBJ_ATOM(obj)->name, (flags | PRINT_RAW)); + return string_print(io, OBJ_ATOM(obj)->name, flags); +} + +/** Atom equality. + * + * @param x to compare + * @param y to compare + * @return 1 if equal, 0 otherwise + */ +int atom_equal(Sxpr x, Sxpr y){ + int ok; + ok = eq(x, y); + if(ok) goto exit; + ok = ATOMP(y) && string_equal(OBJ_ATOM(x)->name, OBJ_ATOM(y)->name); + if(ok) goto exit; + ok = STRINGP(y) && string_equal(OBJ_ATOM(x)->name, y); + exit: + return ok; +} + +/** Get the name of an atom. + * + * @param obj atom + * @return name + */ +char * atom_name(Sxpr obj){ + return string_string(OBJ_ATOM(obj)->name); +} + +/** Get the C string from a string sxpr. + * + * @param obj string sxpr + * @return string + */ +char * string_string(Sxpr obj){ + return OBJ_STRING(obj); +} + +/** Get the length of a string. + * + * @param obj string + * @return length + */ +int string_length(Sxpr obj){ + return strlen(OBJ_STRING(obj)); +} + +/** Create a new string. The input string is copied, + * and must be null-terminated. + * + * @param s characters to put in the string + * @return new sxpr + */ +Sxpr string_new(char *s){ + int n = (s ? strlen(s) : 0); + Sxpr obj; + obj = halloc(n+1, T_STRING); + if(!NOMEMP(obj)){ + char *str = OBJ_STRING(obj); + strncpy(str, s, n); + str[n] = '\0'; + } + return obj; +} + +/** Free a string. + * + * @param obj to free + */ +void string_free(Sxpr obj){ + hfree(obj); +} + +/** Determine if a string needs escapes when printed + * using the given flags. + * + * @param str string to check + * @param flags print flags + * @return 1 if needs escapes, 0 otherwise + */ +int needs_escapes(char *str, unsigned flags){ + char *c; + int val = 0; + + if(str){ + for(c=str; *c; c++){ + if(in_alpha_class(*c)) continue; + if(in_decimal_digit_class(*c)) continue; + if(in_class(*c, "/._+:@~-")) continue; + val = 1; + break; + } + } + //printf("\n> val=%d str=|%s|\n", val, str); + return val; +} + +/** Print a string to a stream, with escapes if necessary. + * + * @param io stream to print to + * @param str string + * @param flags print flags + * @return number of bytes written + */ +int _string_print(IOStream *io, char *str, unsigned flags){ + int k = 0; + if((flags & PRINT_RAW) || !needs_escapes(str, flags)){ + k += IOStream_print(io, str); + } else { + k += IOStream_print(io, "\""); + if(str){ + char *s; + for(s = str; *s; s++){ + if(*s < ' ' || *s >= 127 ){ + switch(*s){ + case '\a': k += IOStream_print(io, "\\a"); break; + case '\b': k += IOStream_print(io, "\\b"); break; + case '\f': k += IOStream_print(io, "\\f"); break; + case '\n': k += IOStream_print(io, "\\n"); break; + case '\r': k += IOStream_print(io, "\\r"); break; + case '\t': k += IOStream_print(io, "\\t"); break; + case '\v': k += IOStream_print(io, "\\v"); break; + default: + // Octal escape; + k += IOStream_print(io, "\\%o", *s); + break; + } + } else if(*s == c_double_quote || + *s == c_single_quote || + *s == c_escape){ + k += IOStream_print(io, "\\%c", *s); + } else { + k+= IOStream_print(io, "%c", *s); + } + } + } + k += IOStream_print(io, "\""); + } + return k; +} + +/** Print a string to a stream, with escapes if necessary. + * + * @param io stream to print to + * @param obj string + * @param flags print flags + * @return number of bytes written + */ +int string_print(IOStream *io, Sxpr obj, unsigned flags){ + return _string_print(io, OBJ_STRING(obj), flags); +} + +/** Compare an sxpr with a string for equality. + * + * @param x string to compare with + * @param y sxpr to compare + * @return 1 if equal, 0 otherwise + */ +int string_equal(Sxpr x, Sxpr y){ + int ok = 0; + ok = eq(x,y); + if(ok) goto exit; + ok = has_type(y, T_STRING) && !strcmp(OBJ_STRING(x), OBJ_STRING(y)); + if(ok) goto exit; + ok = has_type(y, T_ATOM) && !strcmp(OBJ_STRING(x), atom_name(y)); + exit: + return ok; +} + +/** Create a new cons cell. + * The cell is ONOMEM if either argument is. + * + * @param car sxpr for the car + * @param cdr sxpr for the cdr + * @return new cons + */ +Sxpr cons_new(Sxpr car, Sxpr cdr){ + Sxpr obj; + if(NOMEMP(car) || NOMEMP(cdr)){ + obj = ONOMEM; + } else { + obj = HALLOC(ObjCons, T_CONS); + if(!NOMEMP(obj)){ + ObjCons *z = OBJ_CONS(obj); + z->car = car; + z->cdr = cdr; + } + } + return obj; +} + +/** Push a new element onto a list. + * + * @param list list to add to + * @param elt element to add + * @return 0 if successful, error code otherwise + */ +int cons_push(Sxpr *list, Sxpr elt){ + Sxpr l; + l = cons_new(elt, *list); + if(NOMEMP(l)) return -ENOMEM; + *list = l; + return 0; +} + +/** Free a cons. Recursively frees the car and cdr. + * + * @param obj to free + */ +void cons_free(Sxpr obj){ + Sxpr next; + for(; CONSP(obj); obj = next){ + next = CDR(obj); + objfree(CAR(obj)); + hfree(obj); + } + if(!NULLP(obj)){ + objfree(obj); + } +} + +/** Free a cons and its cdr cells, but not the car sxprs. + * Does nothing if called on something that is not a cons. + * + * @param obj to free + */ +void cons_free_cells(Sxpr obj){ + Sxpr next; + for(; CONSP(obj); obj = next){ + next = CDR(obj); + hfree(obj); + } +} + +/** Print a cons. + * Prints the cons in list format if the cdrs are conses. + * uses pair (dot) format if the last cdr is not a cons (or null). + * + * @param io stream to print to + * @param obj to print + * @param flags print flags + * @return number of bytes written + */ +int cons_print(IOStream *io, Sxpr obj, unsigned flags){ + int first = 1; + int k = 0; + k += IOStream_print(io, "("); + for( ; CONSP(obj) ; obj = CDR(obj)){ + if(first){ + first = 0; + } else { + k += IOStream_print(io, " "); + } + k += objprint(io, CAR(obj), flags); + } + if(!NULLP(obj)){ + k += IOStream_print(io, " . "); + k += objprint(io, obj, flags); + } + k += IOStream_print(io, ")"); + return (IOStream_error(io) ? -1 : k); +} + +/** Compare a cons with another sxpr for equality. + * If y is a cons, compares the cars and cdrs recursively. + * + * @param x cons to compare + * @param y sxpr to compare + * @return 1 if equal, 0 otherwise + */ +int cons_equal(Sxpr x, Sxpr y){ + return CONSP(y) && + objequal(CAR(x), CAR(y)) && + objequal(CDR(x), CDR(y)); +} + +/** Return the length of a cons list. + * + * @param obj list + * @return length + */ +int cons_length(Sxpr obj){ + int count = 0; + for( ; CONSP(obj); obj = CDR(obj)){ + count++; + } + return count; +} + +/** Destructively reverse a cons list in-place. + * If the argument is not a cons it is returned unchanged. + * + * @param l to reverse + * @return reversed list + */ +Sxpr nrev(Sxpr l){ + if(CONSP(l)){ + // Iterate down the cells in the list making the cdr of + // each cell point to the previous cell. The last cell + // is the head of the reversed list. + Sxpr prev = ONULL; + Sxpr cell = l; + Sxpr next; + + while(1){ + next = CDR(cell); + CDR(cell) = prev; + if(!CONSP(next)) break; + prev = cell; + cell = next; + } + l = cell; + } + return l; +} + +/** Print the null sxpr. + * + * @param io stream to print to + * @param obj to print + * @param flags print flags + * @return number of bytes written + */ +static int null_print(IOStream *io, Sxpr obj, unsigned flags){ + return IOStream_print(io, "()"); +} + +/** Print the `unspecified' sxpr none. + * + * @param io stream to print to + * @param obj to print + * @param flags print flags + * @return number of bytes written + */ +static int none_print(IOStream *io, Sxpr obj, unsigned flags){ + return IOStream_print(io, ""); +} + +/** Print an integer. + * + * @param io stream to print to + * @param obj to print + * @param flags print flags + * @return number of bytes written + */ +static int int_print(IOStream *io, Sxpr obj, unsigned flags){ + return IOStream_print(io, "%d", OBJ_INT(obj)); +} + +/** Print a boolean. + * + * @param io stream to print to + * @param obj to print + * @param flags print flags + * @return number of bytes written + */ +static int bool_print(IOStream *io, Sxpr obj, unsigned flags){ + return IOStream_print(io, (OBJ_UINT(obj) ? k_true : k_false)); +} + +int sxprp(Sxpr obj, Sxpr name){ + return CONSP(obj) && objequal(CAR(obj), name); +} + +/** Get the name of an element. + * + * @param obj element + * @return name + */ +Sxpr sxpr_name(Sxpr obj){ + Sxpr val = ONONE; + if(CONSP(obj)){ + val = CAR(obj); + } else if(STRINGP(obj) || ATOMP(obj)){ + val = obj; + } + return val; +} + +int sxpr_is(Sxpr obj, char *s){ + if(ATOMP(obj)) return !strcmp(atom_name(obj), s); + if(STRINGP(obj)) return !strcmp(string_string(obj), s); + return 0; +} + +int sxpr_elementp(Sxpr obj, Sxpr name){ + int ok = 0; + ok = CONSP(obj) && objequal(CAR(obj), name); + return ok; +} + +/** Get the attributes of an sxpr. + * + * @param obj sxpr + * @return attributes + */ +Sxpr sxpr_attributes(Sxpr obj){ + Sxpr val = ONULL; + if(CONSP(obj)){ + obj = CDR(obj); + if(CONSP(obj)){ + obj = CAR(obj); + if(sxprp(obj, intern("@"))){ + val = CDR(obj); + } + } + } + return val; +} + +Sxpr sxpr_attribute(Sxpr obj, Sxpr key, Sxpr def){ + Sxpr val = ONONE; + val = assoc(sxpr_attributes(obj), key); + if(CONSP(val) && CONSP(CDR(val))){ + val = CADR(def); + } else { + val = def; + } + return val; +} + +/** Get the children of an sxpr. + * + * @param obj sxpr + * @return children + */ +Sxpr sxpr_children(Sxpr obj){ + Sxpr val = ONULL; + if(CONSP(obj)){ + val = CDR(obj); + if(CONSP(val) && sxprp(CAR(val), intern("@"))){ + val = CDR(val); + } + } + return val; +} + +Sxpr sxpr_child(Sxpr obj, Sxpr name, Sxpr def){ + Sxpr val = ONONE; + Sxpr l; + for(l = sxpr_children(obj); CONSP(l); l = CDR(l)){ + if(sxprp(CAR(l), name)){ + val = CAR(l); + break; + } + } + if(NONEP(val)) val = def; + return val; +} + +Sxpr sxpr_child0(Sxpr obj, Sxpr def){ + Sxpr val = ONONE; + Sxpr l = sxpr_children(obj); + if(CONSP(l)){ + val = CAR(l); + } else { + val = def; + } + return val; +} + +Sxpr sxpr_childN(Sxpr obj, int n, Sxpr def){ + Sxpr val = def; + Sxpr l; + int i; + for (i = 0, l = sxpr_children(obj); CONSP(l); i++, l = CDR(l)){ + if(i == n){ + val = CAR(l); + break; + } + } + return val; +} + +Sxpr sxpr_child_value(Sxpr obj, Sxpr name, Sxpr def){ + Sxpr val = ONONE; + val = sxpr_child(obj, name, ONONE); + if(NONEP(val)){ + val = def; + } else { + val = sxpr_child0(val, def); + } + return val; +} + +/** Table of interned symbols. Indexed by symbol name. */ +static HashTable *symbols = NULL; + +/** Hash function for entries in the symbol table. + * + * @param key to hash + * @return hashcode + */ +static Hashcode sym_hash_fn(void *key){ + return hash_string((char*)key); +} + +/** Key equality function for the symbol table. + * + * @param x to compare + * @param y to compare + * @return 1 if equal, 0 otherwise + */ +static int sym_equal_fn(void *x, void *y){ + return !strcmp((char*)x, (char*)y); +} + +/** Entry free function for the symbol table. + * + * @param table the entry is in + * @param entry being freed + */ +static void sym_free_fn(HashTable *table, HTEntry *entry){ + if(entry){ + objfree(((ObjAtom*)entry->value)->name); + HTEntry_free(entry); + } +} + +/** Initialize the symbol table. + * + * @return 0 on sucess, error code otherwise + */ +static int init_symbols(void){ + symbols = HashTable_new(100); + if(symbols){ + symbols->key_hash_fn = sym_hash_fn; + symbols->key_equal_fn = sym_equal_fn; + symbols->entry_free_fn = sym_free_fn; + return 0; + } + return -1; +} + +/** Cleanup the symbol table. Frees the table and all its symbols. + */ +void cleanup_symbols(void){ + HashTable_free(symbols); + symbols = NULL; +} + +/** Get the interned symbol with the given name. + * No new symbol is created. + * + * @return symbol or null + */ +Sxpr get_symbol(char *sym){ + HTEntry *entry; + if(!symbols){ + if(init_symbols()) return ONOMEM; + return ONULL; + } + entry = HashTable_get_entry(symbols, sym); + if(entry){ + return OBJP(T_ATOM, entry->value); + } else { + return ONULL; + } +} + +/** Get the interned symbol with the given name. + * Creates a new symbol if necessary. + * + * @return symbol + */ +Sxpr intern(char *sym){ + Sxpr symbol = get_symbol(sym); + if(NULLP(symbol)){ + if(!symbols) return ONOMEM; + symbol = atom_new(sym); + if(!NOMEMP(symbol)){ + OBJ_ATOM(symbol)->interned = TRUE; + HashTable_add(symbols, atom_name(symbol), get_ptr(symbol)); + } + } + return symbol; +} diff --git a/tools/xfrd/sxpr.h b/tools/xfrd/sxpr.h new file mode 100644 index 0000000000..a5875c76bd --- /dev/null +++ b/tools/xfrd/sxpr.h @@ -0,0 +1,414 @@ +/* + * + * 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.1 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 + */ +#ifndef _XUTIL_SXPR_H_ +#define _XUTIL_SXPR_H_ + +#include + +#include "hash_table.h" +#include "iostream.h" +#include "allocate.h" + +/** @file + * Definitions for rules and sxprs. + */ + +#ifndef NULL +#define NULL 0 +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +/** Sxpr type. */ +typedef int16_t TypeCode; + +/** A typed sxpr handle.*/ +typedef struct Sxpr { + /** Sxpr type. */ + TypeCode type; + union { + /** Sxpr value. */ + unsigned long ul; + /** Pointer. */ + void *ptr; + } v; +} Sxpr; + +/** Sxpr type to indicate out of memory. */ +#define T_NOMEM ((TypeCode)-1) +/** The 'unspecified' sxpr. */ +#define T_NONE ((TypeCode)0) +/** The empty list. */ +#define T_NULL ((TypeCode)1) +/** Unsigned integer. */ +#define T_UINT ((TypeCode)2) +/** A string. */ +#define T_STRING ((TypeCode)3) +/** An atom. */ +#define T_ATOM ((TypeCode)4) +/** A boolean. */ +#define T_BOOL ((TypeCode)5) + +/** A cons (pair or list). */ +#define T_CONS ((TypeCode)10) + +/** An error. */ +#define T_ERR ((TypeCode)40) + +/** An atom. */ +typedef struct ObjAtom { + Sxpr name; + Hashcode hashcode; + int interned; +} ObjAtom; + +/** A cons (pair). */ +typedef struct ObjCons { + Sxpr car; + Sxpr cdr; +} ObjCons; + +/** A vector. */ +typedef struct ObjVector { + int n; + Sxpr data[0]; +} ObjVector; + +/** Flags for sxpr printing. */ +enum PrintFlags { + PRINT_RAW = 0x001, + PRINT_TYPE = 0x002, + PRINT_PRETTY = 0x004, + PRINT_NUM = 0x008, +}; + +/** An integer sxpr. + * + * @param ty type + * @param val integer value + */ +#define OBJI(ty, val) (Sxpr){ type: (ty), v: { ul: (val) }} + +/** A pointer sxpr. + * If the pointer is non-null, returns an sxpr containing it. + * If the pointer is null, returns ONOMEM. + * + * @param ty type + * @param val pointer + */ +#define OBJP(ty, val) ((val) ? (Sxpr){ type: (ty), v: { ptr: (val) }} : ONOMEM) + +/** Make an integer sxpr containing a pointer. + * + * @param val pointer + */ +#define PTR(val) OBJP(T_UINT, (void*)(val)) + +/** Make an integer sxpr. + * @param x value + */ +#define OINT(x) OBJI(T_UINT, x) + +/** Make an error sxpr. + * + * @param x value + */ +#define OERR(x) OBJI(T_ERR, x) + +/** Out of memory constant. */ +#define ONOMEM OBJI(T_NOMEM, 0) + +/** The `unspecified' constant. */ +#define ONONE OBJI(T_NONE, 0) + +/** Empty list constant. */ +#define ONULL OBJI(T_NULL, 0) + +/** False constant. */ +#define OFALSE OBJI(T_BOOL, 0) + +/** True constant. */ +#define OTRUE OBJI(T_BOOL, 1) + +/* Recognizers for the various sxpr types. */ +#define ATOMP(obj) has_type(obj, T_ATOM) +#define BOOLP(obj) has_type(obj, T_BOOL) +#define CONSP(obj) has_type(obj, T_CONS) +#define ERRP(obj) has_type(obj, T_ERR) +#define INTP(obj) has_type(obj, T_UINT) +#define NOMEMP(obj) has_type(obj, T_NOMEM) +#define NONEP(obj) has_type(obj, T_NONE) +#define NULLP(obj) has_type(obj, T_NULL) +#define STRINGP(obj) has_type(obj, T_STRING) + +#define TRUEP(obj) get_ul(obj) + +/** Convert an sxpr to an unsigned integer. */ +#define OBJ_UINT(x) get_ul(x) +/** Convert an sxpr to an integer. */ +#define OBJ_INT(x) (int)get_ul(x) + +/* Conversions of sxprs to their values. + * No checking is done. + */ +#define OBJ_STRING(x) ((char*)get_ptr(x)) +#define OBJ_CONS(x) ((ObjCons*)get_ptr(x)) +#define OBJ_ATOM(x) ((ObjAtom*)get_ptr(x)) +#define OBJ_SET(x) ((ObjSet*)get_ptr(x)) +#define CAR(x) (OBJ_CONS(x)->car) +#define CDR(x) (OBJ_CONS(x)->cdr) + +#define CAAR(x) (CAR(CAR(x))) +#define CADR(x) (CAR(CDR(x))) +#define CDAR(x) (CDR(CAR(x))) +#define CDDR(x) (CDR(CDR(x))) + +/** Get the integer value from an sxpr. + * + * @param obj sxpr + * @return value + */ +static inline unsigned long get_ul(Sxpr obj){ + return obj.v.ul; +} + +/** Get the pointer value from an sxpr. + * + * @param obj sxpr + * @return value + */ +static inline void * get_ptr(Sxpr obj){ + return obj.v.ptr; +} + +/** Create an sxpr containing a pointer. + * + * @param type typecode + * @param val pointer + * @return sxpr + */ +static inline Sxpr obj_ptr(TypeCode type, void *val){ + return (Sxpr){ type: type, v: { ptr: val } }; +} + +/** Create an sxpr containing an integer. + * + * @param type typecode + * @param val integer + * @return sxpr + */ +static inline Sxpr obj_ul(TypeCode type, unsigned long val){ + return (Sxpr){ type: type, v: { ul: val } }; +} + +/** Get the type of an sxpr. + * + * @param obj sxpr + * @return type + */ +static inline TypeCode get_type(Sxpr obj){ + return obj.type; +} + +/** Check the type of an sxpr. + * + * @param obj sxpr + * @param type to check + * @return 1 if has the type, 0 otherwise + */ +static inline int has_type(Sxpr obj, TypeCode type){ + return get_type(obj) == type; +} + +/** Compare sxprs for literal equality of type and value. + * + * @param x sxpr to compare + * @param y sxpr to compare + * @return 1 if equal, 0 otherwise + */ +static inline int eq(Sxpr x, Sxpr y){ + return ((get_type(x) == get_type(y)) && (get_ul(x) == get_ul(y))); +} + +/** Checked version of CAR + * + * @param x sxpr + * @return CAR if a cons, x otherwise + */ +static inline Sxpr car(Sxpr x){ + return (CONSP(x) ? CAR(x) : x); +} + +/** Checked version of CDR. + * + * @param x sxpr + * @return CDR if a cons, null otherwise + */ +static inline Sxpr cdr(Sxpr x){ + return (CONSP(x) ? CDR(x) : ONULL); +} + +/** Allocate some memory and return an sxpr containing it. + * Returns ONOMEM if allocation failed. + * + * @param n number of bytes to allocate + * @param ty typecode + * @return sxpr + */ +static inline Sxpr halloc(size_t n, TypeCode ty){ + return OBJP(ty, allocate(n)); +} + +/** Allocate an sxpr containing a pointer to the given type. + * + * @param ty type (uses sizeof to determine how many bytes to allocate) + * @param code typecode + * @return sxpr, ONOMEM if allocation failed + */ +#define HALLOC(ty, code) halloc(sizeof(ty), code) + +typedef int ObjPrintFn(IOStream *io, Sxpr obj, unsigned flags); +typedef int ObjEqualFn(Sxpr obj, Sxpr other); +typedef void ObjFreeFn(Sxpr obj); + +/** An sxpr type definition. */ +typedef struct SxprType { + TypeCode type; + char *name; + int pointer; + ObjPrintFn *print; + ObjEqualFn *equal; + ObjFreeFn *free; +} SxprType; + + +extern SxprType *get_sxpr_type(int ty); + +/** Free the pointer in an sxpr. + * + * @param x sxpr containing a pointer + */ +static inline void hfree(Sxpr x){ + deallocate(get_ptr(x)); +} + +extern int objprint(IOStream *io, Sxpr x, unsigned flags); +extern int objequal(Sxpr x, Sxpr y); +extern void objfree(Sxpr x); + +extern void cons_free_cells(Sxpr obj); +extern Sxpr intern(char *s); + +extern Sxpr assoc(Sxpr k, Sxpr l); +extern Sxpr assocq(Sxpr k, Sxpr l); +extern Sxpr acons(Sxpr k, Sxpr v, Sxpr l); +extern Sxpr nrev(Sxpr l); +extern Sxpr cons_member(Sxpr l, Sxpr x); +extern Sxpr cons_member_if(Sxpr l, ObjEqualFn *test_fn, Sxpr v); +extern int cons_subset(Sxpr s, Sxpr t); +extern int cons_set_equal(Sxpr s, Sxpr t); + +#ifdef USE_GC +extern Sxpr cons_remove(Sxpr l, Sxpr x); +extern Sxpr cons_remove_if(Sxpr l, ObjEqualFn *test_fn, Sxpr v); +#endif + +extern Sxpr atom_new(char *name); +extern char * atom_name(Sxpr obj); + +extern Sxpr string_new(char *s); +extern char * string_string(Sxpr obj); +extern int string_length(Sxpr obj); + +extern Sxpr cons_new(Sxpr car, Sxpr cdr); +extern int cons_push(Sxpr *list, Sxpr elt); +extern int cons_length(Sxpr obj); + +Sxpr sxpr_name(Sxpr obj); +int sxpr_is(Sxpr obj, char *s); +int sxpr_elementp(Sxpr obj, Sxpr name); +Sxpr sxpr_attributes(Sxpr obj); +Sxpr sxpr_attribute(Sxpr obj, Sxpr key, Sxpr def); +Sxpr sxpr_children(Sxpr obj); +Sxpr sxpr_child(Sxpr obj, Sxpr name, Sxpr def); +Sxpr sxpr_childN(Sxpr obj, int n, Sxpr def); +Sxpr sxpr_child0(Sxpr obj, Sxpr def); +Sxpr sxpr_child_value(Sxpr obj, Sxpr name, Sxpr def); + +/** Create a new atom. + * + * @param s atom name + * @return new atom + */ +static inline Sxpr mkatom(char *s){ + return atom_new(s); +} + +/** Create a new string sxpr. + * + * @param s string bytes (copied) + * @return new string + */ +static inline Sxpr mkstring(char *s){ + return string_new(s); +} + +/** Create an integer sxpr. + * + * @param i value + * @return sxpr + */ +static inline Sxpr mkint(int i){ + return OBJI(T_UINT, i); +} + +/** Create a boolean sxpr. + * + * @param b value + * @return sxpr + */ +static inline Sxpr mkbool(int b){ + return OBJI(T_BOOL, (b ? 1 : 0)); +} + +/* Constants used in parsing and printing. */ +#define k_list_open "(" +#define c_list_open '(' +#define k_list_close ")" +#define c_list_close ')' +#define k_true "true" +#define k_false "false" + +#define c_var '$' +#define c_escape '\\' +#define c_single_quote '\'' +#define c_double_quote '"' +#define c_string_open c_double_quote +#define c_string_close c_double_quote +#define c_data_open '[' +#define c_data_close ']' +#define c_binary '*' +#define c_eval '!' +#define c_concat_open '{' +#define c_concat_close '}' + +#endif /* ! _XUTIL_SXPR_H_ */ diff --git a/tools/xfrd/xdr.c b/tools/xfrd/xdr.c new file mode 100644 index 0000000000..61dbe44ed6 --- /dev/null +++ b/tools/xfrd/xdr.c @@ -0,0 +1,316 @@ +#include +#include "xdr.h" + +#define MODULE_NAME "XDR" +//#define DEBUG 1 +#undef DEBUG +#include "debug.h" + +/** @file + * XDR packer/unpacker for elements. + * + * string -> [T_STRING] [len:u16] + * atom -> [T_ATOM] [len:u16] + * uint -> [T_UINT] [value] + * cons -> [T_LIST] {1 elt}* 0 + * null -> [T_NULL] + * none -> [T_NONE] + * bool -> [T_BOOL] { 0:u8 | 1:u8 } + * + * types packed as u16. + * + * So (a b c) -> [T_CONS] a [T_CONS] b [T_CONS] c [T_NULL] + * () -> [T_NULL] + */ + +int pack_bool(IOStream *io, int x){ + int err=0; + //dprintf("> x=%d\n", x); + err = IOStream_print(io, "%c", 0xff & x); + if(err > 0) err = 0; + //dprintf("< err=%d\n", err); + return err; +} + +int unpack_bool(IOStream *io, int *x){ + int err = 0; + int c; + //dprintf(">\n"); + c = IOStream_getc(io); + *x = (c < 0 ? 0 : c); + err = IOStream_error(io); + if(c < 0 && !err) err = -EIO; + //dprintf("< err=%d x=%d\n", err, *x); + return err; +} + +int pack_ushort(IOStream *io, unsigned short x){ + int err=0; + //dprintf("> x=%u\n", x); + err = IOStream_print(io, "%c%c", + 0xff & (x >> 8), + 0xff & (x )); + if(err > 0) err = 0; + //dprintf("< err=%d\n", err); + return err; +} + +int unpack_ushort(IOStream *io, unsigned short *x){ + int err = 0; + int i, c = 0; + //dprintf(">\n"); + *x = 0; + for(i = 0; i< 2; i++){ + c = IOStream_getc(io); + if(c < 0) break; + *x <<= 8; + *x |= (0xff & c); + } + err = IOStream_error(io); + + if(c < 0 && !err) err = -EIO; + //dprintf("< err=%d x=%u\n", err, *x); + return err; +} + +int pack_type(IOStream *io, unsigned short x){ + return pack_ushort(io, x); +} + +int unpack_type(IOStream *io, unsigned short *x){ + return unpack_ushort(io, x); +} + +int pack_uint(IOStream *io, unsigned int x){ + int err=0; + //dprintf("> x=%u\n", x); + err = IOStream_print(io, "%c%c%c%c", + 0xff & (x >> 24), + 0xff & (x >> 16), + 0xff & (x >> 8), + 0xff & (x )); + if(err > 0) err = 0; + //dprintf("< err=%d\n", err); + return err; +} + +int unpack_uint(IOStream *io, unsigned int *x){ + int err = 0; + int i, c = 0; + //dprintf(">\n"); + *x = 0; + for(i = 0; i< 4; i++){ + c = IOStream_getc(io); + if(c < 0) break; + *x <<= 8; + *x |= (0xff & c); + } + err = IOStream_error(io); + if(c < 0 && !err) err = -EIO; + //dprintf("< err=%d x=%u\n", err, *x); + return err; +} + +int pack_string(IOStream *io, Sxpr x){ + int err = 0; + unsigned short n = 0xffff & string_length(x); + char *s = string_string(x); + int i; + //dprintf("> n=%d s=%s\n", n, s); + err = pack_ushort(io, n); + if(err) goto exit; + for(i = 0; i < n; i++){ + err = IOStream_print(io, "%c", s[i]); + if(err < 0) break; + } + if(err > 0) err = 0; + exit: + //dprintf("< err=%d\n", err); + return err; +} + +int unpack_string(IOStream *io, Sxpr *x){ + int err; + unsigned short n; + int i, c = 0; + char *s; + Sxpr val = ONONE; + + //dprintf(">\n"); + err = unpack_ushort(io, &n); + if(err) goto exit; + val = halloc(n+1, T_STRING); + if(NOMEMP(val)){ + err = -ENOMEM; + goto exit; + } + s = string_string(val); + for(i=0; i\n"); + for(l = x; CONSP(l); l = CDR(l)){ + err = pack_bool(io, 1); + if(err) goto exit; + err = pack_sxpr(io, CAR(l)); + if(err) goto exit; + } + err = pack_bool(io, 0); + exit: + //dprintf("< err=%d\n", err); + return err; +} + +int unpack_cons(IOStream *io, Sxpr *x){ + int err = 0; + int more = 0; + Sxpr u = ONONE, v = ONONE, val = ONULL; + + dprintf(">\n"); + while(1){ + err = unpack_bool(io, &more); + if(err) goto exit; + if(!more){ + //IOStream_print(iostdout, "unpack_cons 1 val="); + ////objprint(iostdout, val, 0); + IOStream_print(iostdout, "\n"); + + val = nrev(val); + + //IOStream_print(iostdout, "unpack_cons 2 val="); + //objprint(iostdout, val, 0); + //IOStream_print(iostdout, "\n"); + + break; + } + err = unpack_sxpr(io, &u); + if(err) goto exit; + v = cons_new(u, val); + if(NOMEMP(v)){ + err = -ENOMEM; + objfree(u); + goto exit; + } + val = v; + } + exit: + if(err){ + objfree(val); + val = ONONE; + } + *x = val; + dprintf("< err=%d\n", err); + return err; +} + +int pack_sxpr(IOStream *io, Sxpr x){ + int err = 0; + unsigned short type = get_type(x); + //dprintf(">\n"); + //objprint(iostdout, x, 0); + //IOStream_print(iostdout, "\n"); + + err = pack_type(io, type); + if(err) goto exit; + switch(type){ + case T_NULL: + break; + case T_NONE: + break; + case T_BOOL: + err = pack_bool(io, get_ul(x)); + break; + case T_CONS: + err = pack_cons(io, x); + break; + case T_ATOM: + err = pack_string(io, OBJ_ATOM(x)->name); + break; + case T_STRING: + err = pack_string(io, x); + break; + case T_UINT: + err = pack_uint(io, get_ul(x)); + break; + default: + err = -EINVAL; + IOStream_print(iostderr, "%s> invalid type %d\n", __FUNCTION__, type); + break; + } + exit: + //dprintf("< err=%d\n", err); + return err; +} + +int unpack_sxpr(IOStream *io, Sxpr *x){ + int err = 0; + unsigned short type; + unsigned int u; + Sxpr val = ONONE, y; + + //dprintf(">\n"); + err = unpack_type(io, &type); + if(err) goto exit; + switch(type){ + case T_NULL: + val = ONULL; + break; + case T_NONE: + val = ONONE; + break; + case T_CONS: + err = unpack_cons(io, &val); + break; + case T_BOOL: + err = unpack_bool(io, &u); + if(err) goto exit; + val = (u ? OTRUE : OFALSE); + break; + case T_ATOM: + err = unpack_string(io, &y); + if(err) goto exit; + val = intern(string_string(y)); + objfree(y); + break; + case T_STRING: + err = unpack_string(io, &val); + break; + case T_UINT: + err = unpack_uint(io, &u); + if(err) goto exit; + val = OBJI(type, u); + break; + default: + err = -EINVAL; + IOStream_print(iostderr, "%s> invalid type %d\n", __FUNCTION__, type); + break; + } + exit: + *x = (err ? ONONE : val); + //IOStream_print(iostdout, "sxpr="); + //objprint(iostdout, *x, 0); + //IOStream_print(iostdout, "\n"); + //dprintf("< err=%d\n", err); + return err; +} diff --git a/tools/xfrd/xdr.h b/tools/xfrd/xdr.h new file mode 100644 index 0000000000..793cd34a29 --- /dev/null +++ b/tools/xfrd/xdr.h @@ -0,0 +1,30 @@ +#ifndef _XUTIL_XDR_H_ +#define _XUTIL_XDR_H_ +#include "iostream.h" +#include "sxpr.h" + +int pack_type(IOStream *io, unsigned short x); + +int unpack_type(IOStream *io, unsigned short *x); + +int pack_bool(IOStream *io, int x); + +int unpack_bool(IOStream *io, int *x); + +int pack_uint(IOStream *out, unsigned int x); + +int unpack_uint(IOStream *in, unsigned int *x); + +int pack_string(IOStream *out, Sxpr x); + +int unpack_string(IOStream *in, Sxpr *x); + +int pack_cons(IOStream *out, Sxpr x); + +int unpack_cons(IOStream *in, Sxpr *x); + +int pack_sxpr(IOStream *out, Sxpr x); + +int unpack_sxpr(IOStream *in, Sxpr *x); + +#endif /* _XUTIL_XDR_H_ */ diff --git a/tools/xfrd/xen_domain.c b/tools/xfrd/xen_domain.c new file mode 100644 index 0000000000..5c5f7c5bef --- /dev/null +++ b/tools/xfrd/xen_domain.c @@ -0,0 +1,90 @@ +#include +#include +#include + +#ifndef _XEN_XFR_STUB_ +#include "dom0_defs.h" +#include "mem_defs.h" +#endif + +#include "xen_domain.h" +#include "marshal.h" +#include "xdr.h" + +#define MODULE_NAME "XFRD" +#define DEBUG 1 +#include "debug.h" + +/** Write domain state. + * + * At some point during this the domain is suspended, and then there's no way back. + * Even if something later goes wrong we can't restart the domain. + */ +int xen_domain_snd(Conn *xend, IOStream *io, uint32_t dom, char *vmconfig, int vmconfig_n){ + int err = 0; + char buf[1024]; + int n, k, d, buf_n; + dprintf("> dom=%d\n", dom); +#ifdef _XEN_XFR_STUB_ + err = marshal_uint32(io, dom); + if(err) goto exit; + err = marshal_string(io, vmconfig, vmconfig_n); + if(err) goto exit; + n = 32 * 1024 * 1024; + buf_n = sizeof(buf); + err = marshal_uint32(io, n); + for(k = 0; k < n; k += d){ + d = n - k; + if(d > buf_n) d = buf_n; + err = marshal_bytes(io, buf, d); + if(err) goto exit; + //dprintf("> k=%d n=%d\n", k, n); + } + + exit: +#else +#endif + dprintf("< err=%d\n", err); + return err; +} + +/** Receive domain state. + * Create a new domain and store the received state into it. + */ +int xen_domain_rcv(IOStream *io, uint32_t *dom, char **vmconfig, int *vmconfig_n){ + int err = 0; + char buf[1024]; + int n, k, d, buf_n; + dprintf(">\n"); +#ifdef _XEN_XFR_STUB_ + err = unmarshal_uint32(io, dom); + if(err) goto exit; + err = unmarshal_new_string(io, vmconfig, vmconfig_n); + if(err) goto exit; + err = unmarshal_uint32(io, &n); + buf_n = sizeof(buf); + for(k = 0; k < n; k += d){ + d = n - k; + if(d > buf_n) d = buf_n; + err = unmarshal_bytes(io, buf, d); + if(err) goto exit; + //dprintf("> k=%d n=%d\n", k, n); + } + exit: +#else +#endif + dprintf("< err=%d\n", err); + return err; +} + +/** Configure a new domain. Talk to xend. Use libcurl? + */ +int xen_domain_configure(uint32_t dom, char *vmconfig, int vmconfig_n){ + int err = 0; + dprintf(">\n"); +#ifdef _XEN_XFR_STUB_ +#else +#endif + dprintf("< err=%d\n", err); + return err; +} diff --git a/tools/xfrd/xen_domain.h b/tools/xfrd/xen_domain.h new file mode 100644 index 0000000000..4618c642b7 --- /dev/null +++ b/tools/xfrd/xen_domain.h @@ -0,0 +1,15 @@ +#ifndef _XFRD_XEN_DOMAIN_H_ +#define _XFRD_XEN_DOMAIN_H_ +#include +#include +#include "connection.h" + +/** Define to use stubs. Undefine to use Xen ops. */ +//#define _XEN_XFR_STUB_ + +extern int xen_domain_snd(Conn *xend, IOStream *io, uint32_t dom, char *vmconfig, int vmconfig_n); +extern int xen_domain_rcv(IOStream *io, uint32_t *dom, char **vmconfig, int *vmconfig_n); + + +extern int xen_domain_configure(uint32_t dom, char *vmconfig, int vmconfig_n); +#endif diff --git a/tools/xfrd/xfrd.c b/tools/xfrd/xfrd.c new file mode 100644 index 0000000000..1836231075 --- /dev/null +++ b/tools/xfrd/xfrd.c @@ -0,0 +1,1127 @@ +/** @file + * XFRD - Domain Transfer Daemon for Xen. + * + * The xfrd is forked by xend to transfer a vm to a remote system. + * + * The vm is suspended, then its state and memory are transferred to the remote system. + * The remote system attempts to create a vm and copy the transferred state and memory into it, + * finally resuming the vm. If all is OK the vm ends up running on the remote + * system and is removed from the originating system. If the transfer does not complete + * successfully the originating system attempts to resume the vm. + * The children exit when the transfer completes. + * + * @author Mike Wray + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "allocate.h" +#include "file_stream.h" +#include "string_stream.h" +#include "lzi_stream.h" +#include "sys_net.h" +#include "sys_string.h" + +#include "xdr.h" +#include "enum.h" +#include "xfrd.h" + +#include "xen_domain.h" + +#include "connection.h" +#include "select.h" + +#define MODULE_NAME "XFRD" +#define DEBUG 1 +#include "debug.h" + +/* +sender: + xend connects to xfrd and writes migrate message + xend writes domain config to xfrd + + xfrd forks + + xfrd connects to peer + xfrd sends hello, reads response + xfrd sends domain + xfrd reads response + reports progress/status to xend + + xend reads xfrd for progress/status, disconnects + If ok, destroys domain. + If not ok, unpauses domain. + +receiver: + xfrd accepts connection on inbound port + xfrd forks and accepts connection + xfrd receives hello, writes response + xfrd receives domain + xfrd connects to xend, configures new domain + xfrd writes status back to peer, child exits + + + (xfr.hello ) + (xfr.err ) + + xend->xfrd (xfr.migrate ) + (xfr.save ) + xfrd->xend (xfr.suspend ) + xfrd->xend (xfr.progress ) + xfrd->xend (xfr.err ) | (xfr.ok ) + xfrd->xfrd (xfr.xfr ) + xfrd->xfrd (xfr.err ) | (xfr.ok ) + + xfrd->xend (xfr.configure ) + */ + +Sxpr oxfr_configure; // (xfr.configure ) +Sxpr oxfr_err; // (xfr.err ) +Sxpr oxfr_hello; // (xfr.hello ) +Sxpr oxfr_migrate; // (xfr.migrate ) +Sxpr oxfr_ok; // (xfr.ok ) +Sxpr oxfr_progress; // (xfr.progress ) +Sxpr oxfr_save; // (xfr.save ) +Sxpr oxfr_suspend; // (xfr.suspend ) +Sxpr oxfr_xfr; // (xfr.xfr ) + +void xfr_init(void){ + oxfr_configure = intern("xfr.configure"); + oxfr_err = intern("xfr.err"); + oxfr_hello = intern("xfr.hello"); + oxfr_migrate = intern("xfr.migrate"); + oxfr_ok = intern("xfr.ok"); + oxfr_progress = intern("xfr.progress"); + oxfr_save = intern("xfr.save"); + oxfr_suspend = intern("xfr.suspend"); + oxfr_xfr = intern("xfr.xfr"); +} + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#define PROGRAM "xfrd" + +#define OPT_PORT 'P' +#define KEY_PORT "port" +#define DOC_PORT "\n\txfr port (as a number or service name)" + +#define OPT_COMPRESS 'Z' +#define KEY_COMPRESS "compress" +#define DOC_COMPRESS "\n\tuse compression for migration" + +#define OPT_HELP 'h' +#define KEY_HELP "help" +#define DOC_HELP "\n\tprint help" + +#define OPT_VERSION 'v' +#define KEY_VERSION "version" +#define DOC_VERSION "\n\tprint version" + +#define OPT_VERBOSE 'V' +#define KEY_VERBOSE "verbose" +#define DOC_VERBOSE "\n\tverbose flag" + +/** Print a usage message. + * Prints to stdout if err is zero, and exits with 0. + * Prints to stderr if err is non-zero, and exits with 1. + */ +void usage(int err){ + FILE *out = (err ? stderr : stdout); + + fprintf(out, "Usage: %s [options]\n", PROGRAM); + fprintf(out, "-%c, --%s %s\n", OPT_PORT, KEY_PORT, DOC_PORT); + fprintf(out, "-%c, --%s %s\n", OPT_COMPRESS, KEY_COMPRESS, DOC_COMPRESS); + fprintf(out, "-%c, --%s %s\n", OPT_VERBOSE, KEY_VERBOSE, DOC_VERBOSE); + fprintf(out, "-%c, --%s %s\n", OPT_VERSION, KEY_VERSION, DOC_VERSION); + fprintf(out, "-%c, --%s %s\n", OPT_HELP, KEY_HELP, DOC_HELP); + exit(err ? 1 : 0); +} + +/** Short options. Options followed by ':' take an argument. */ +static char *short_opts = (char[]){ + OPT_PORT, ':', + OPT_COMPRESS, + OPT_HELP, + OPT_VERSION, + OPT_VERBOSE, + 0 }; + +/** Long options. */ +static struct option const long_opts[] = { + { KEY_PORT, required_argument, NULL, OPT_PORT }, + { KEY_COMPRESS, no_argument, NULL, OPT_COMPRESS }, + { KEY_HELP, no_argument, NULL, OPT_HELP }, + { KEY_VERSION, no_argument, NULL, OPT_VERSION }, + { KEY_VERBOSE, no_argument, NULL, OPT_VERBOSE }, + { NULL, 0, NULL, 0 } +}; + +typedef struct Args { + int bufsize; + unsigned long port; + int verbose; + int compress; +} Args; + +/** Transfer states. */ +enum { + XFR_INIT, + XFR_HELLO, + XFR_STATE, + XFR_RUN, + XFR_FAIL, + XFR_DONE, + XFR_MAX +}; + +/** Initialize an array element for a constant to its string name. */ +#define VALDEF(val) { val, #val } + +/** Names for the transfer states. */ +static EnumDef xfr_states[] = { + VALDEF(XFR_INIT), + VALDEF(XFR_HELLO), + VALDEF(XFR_STATE), + VALDEF(XFR_RUN), + VALDEF(XFR_FAIL), + VALDEF(XFR_DONE), + { 0, NULL } +}; + + +/** State machine for transfer. */ +typedef struct XfrState { + /** Current state. */ + int state; + /** Error codes for the states. */ + int state_err[XFR_MAX]; + /** First error. */ + int err; + /** State when first error happened. */ + int err_state; + + uint32_t vmid; + char* vmconfig; + int vmconfig_n; + unsigned long xfr_port; + char *xfr_host; + uint32_t vmid_new; +} XfrState; + +/** Get the name of a transfer state. + * + * @param s state + * @return name + */ +char * xfr_state_name(int s){ + return enum_val_to_name(s, xfr_states); +} + +/** Set the state of a transfer. + * + * @param s transfer + * @param state state + * @return state + */ +int XfrState_set_state(XfrState *s, int state){ + s->state = state; + return s->state; +} + +/** Get the state of a transfer. + * + * @param s transfer + * @return state + */ +int XfrState_get_state(XfrState *s){ + return s->state; +} + +/** Set an error in the current state. + * Does nothing if an error is already set. + * + * @param s transfer + * @param err error + * @return error + */ +int XfrState_set_err(XfrState *s, int err){ + if(!s->state_err[s->state]){ + s->state_err[s->state] = err; + } + if(!s->err){ + s->err = err; + s->err_state = s->state; + } + return err; +} + +/** Get the error in the current state. + * + * @param s transfer + * @return error + */ +int XfrState_get_err(XfrState *s){ + return s->state_err[s->state]; +} + +/** Get the first error of a transfer. + * + * @param s transfer + * @return error + */ +int XfrState_first_err(XfrState *s){ + return s->err; +} + +/** Get the state a transfer was in when it had its first error. + * + * @param s transfer + * @return error state + */ +int XfrState_first_err_state(XfrState *s){ + return s->err_state; +} + +/** Xfrd arguments. */ +static Args _args = {}; + +/** Xfrd arguments. */ +static Args *args = &_args; + +/** Set xfrd default arguments. + * + * @param args arguments to set + */ +void set_defaults(Args *args){ + args->compress = FALSE; + args->bufsize = 128 * 1024; + args->port = htons(XFRD_PORT); +} + +int stringof(Sxpr exp, char **s){ + int err = 0; + dprintf(">\n"); + objprint(iostdout, exp, PRINT_TYPE); IOStream_print(iostdout, "\n"); + if(ATOMP(exp)){ + *s = atom_name(exp); + } else if(STRINGP(exp)){ + *s = string_string(exp); + } else { + err = -EINVAL; + *s = NULL; + } + dprintf("< err=%d s=%s\n", err, *s); + return err; +} + +int intof(Sxpr exp, int *v){ + int err = 0; + char *s; + unsigned long l; + dprintf(">\n"); + objprint(iostdout, exp, 0); IOStream_print(iostdout, "\n"); + if(INTP(exp)){ + *v = OBJ_INT(exp); + } else { + err = stringof(exp, &s); + if(err) goto exit; + err = convert_atoul(s, &l); + *v = (int)l; + } + exit: + dprintf("< err=%d v=%d\n", err, *v); + return err; +} + +int addrof(Sxpr exp, uint32_t *v){ + char *h; + unsigned long a; + int err = 0; + dprintf(">\n"); + objprint(iostdout, exp, 0); IOStream_print(iostdout, "\n"); + err = stringof(exp, &h); + if(err) goto exit; + if(get_host_address(h, &a)){ + *v = a; + } else { + err = -EINVAL; + } + exit: + dprintf("< err=%d v=%x\n", err, *v); + return err; +} + +int portof(Sxpr exp, uint16_t *v){ + char *s; + int err = 0; + dprintf(">\n"); + objprint(iostdout, exp, 0); IOStream_print(iostdout, "\n"); + if(INTP(exp)){ + *v = get_ul(exp); + *v = htons(*v); + } else { + unsigned long p; + err = stringof(exp, &s); + if(err) goto exit; + if(get_service_port(s, &p)){ + *v = p; + } else { + err = -EINVAL; + } + } + exit: + dprintf("< err=%d v=%u\n", err, *v); + return err; +} + +static inline struct in_addr inaddr(uint32_t addr){ + return (struct in_addr){ .s_addr = addr }; +} + +time_t stats(time_t t0, uint64_t offset, uint64_t memory, float *percent, float *rate){ + time_t t1 = time(NULL); + *percent = (offset * 100.0f) / memory; + t1 = time(NULL) - t0; + *rate = (t1 ? offset/(t1 * 1024.0f) : 0.0f); + return t1; +} + +/** Notify success or error. + * + * @param conn connection + * @param errcode error code + * @return 0 on success, error code otherwise + */ +int xfr_error(Conn *conn, int errcode){ + int err = 0; + if(!conn->out) return -ENOTCONN; + err = pack_type(conn->out, T_CONS); + if(err) goto exit; + err = pack_bool(conn->out, 1); + if(err) goto exit; + err = pack_sxpr(conn->out, oxfr_err); + if(err) goto exit; + err = pack_bool(conn->out, 1); + if(err) goto exit; + err = pack_sxpr(conn->out, mkint(errcode)); + if(err) goto exit; + err = pack_bool(conn->out, 0); + exit: + return err; +} + +/** Read a response message - error or ok. + * + * @param conn connection + * @return 0 on success, error code otherwise + */ +int xfr_response(Conn *conn){ + int err; + Sxpr sxpr; + + dprintf(">\n"); + if(!conn->out) return -ENOTCONN; + err = unpack_sxpr(conn->in, &sxpr); + if(err) goto exit; + if(sxpr_elementp(sxpr, oxfr_err)){ + int errcode; + err = intof(sxpr_childN(sxpr, 0, ONONE), &errcode); + if(err) goto exit; + err = errcode; + } + exit: + dprintf("< err=%d\n", err); + return err; +} + +/** Get the initial hello message and check the protocol version. + * It is an error to receive anything other than a hello message + * with the correct protocol version. + * + * @param conn connection + * @return 0 on success, error code otherwise + */ +int xfr_hello(Conn *conn){ + int err; + uint32_t major = XFR_PROTO_MAJOR, minor = XFR_PROTO_MINOR; + uint32_t hello_major, hello_minor; + Sxpr sxpr; + if(!conn->in) return -ENOTCONN; + dprintf(">\n"); + err = unpack_sxpr(conn->in, &sxpr); + if(err) goto exit; + if(!sxpr_elementp(sxpr, oxfr_hello)){ + dprintf("> sxpr_elementp test failed\n"); + err = -EINVAL; + goto exit; + } + err = intof(sxpr_childN(sxpr, 0, ONONE), &hello_major); + if(err) goto exit; + err = intof(sxpr_childN(sxpr, 1, ONONE), &hello_minor); + if(err) goto exit; + if(hello_major != major || hello_minor != minor){ + eprintf("> Wanted protocol version %d.%d, got %d.%d", + major, minor, hello_major, hello_minor); + err = -EINVAL; + goto exit; + } + exit: + xfr_error(conn, err); + if(err){ + eprintf("> Hello failed: %d\n", err); + } + dprintf("< err=%d\n", err); + return err; +} + +/** Send the initial hello message. + * + * @param conn connection + * @param msg message + * @return 0 on success, error code otherwise + */ +int xfr_send_hello(Conn *conn){ + int err = 0; + dprintf(">\n"); + err = pack_type(conn->out, T_CONS); + if(err) goto exit; + err = pack_bool(conn->out, 1); + if(err) goto exit; + err = pack_sxpr(conn->out, oxfr_hello); + if(err) goto exit; + err = pack_bool(conn->out, 1); + if(err) goto exit; + err = pack_sxpr(conn->out, mkint(XFR_PROTO_MAJOR)); + if(err) goto exit; + err = pack_bool(conn->out, 1); + if(err) goto exit; + err = pack_sxpr(conn->out, mkint(XFR_PROTO_MINOR)); + if(err) goto exit; + err = pack_bool(conn->out, 0); + IOStream_flush(conn->out); + dprintf("> xfr_response...\n"); + err = xfr_response(conn); + exit: + dprintf("< err=%d\n", err); + return err; +} + +int xfr_send_xfr(Conn *conn, uint32_t vmid){ + int err; + err = pack_type(conn->out, T_CONS); + if(err) goto exit; + err = pack_bool(conn->out, 1); + if(err) goto exit; + err = pack_sxpr(conn->out, oxfr_xfr); + if(err) goto exit; + err = pack_bool(conn->out, 1); + if(err) goto exit; + err = pack_sxpr(conn->out, mkint(vmid)); + if(err) goto exit; + err = pack_bool(conn->out, 0); + if(err) goto exit; + exit: + return err; +} + +int xfr_send_ok(Conn *conn, uint32_t vmid){ + int err = 0; + err = pack_type(conn->out, T_CONS); + if(err) goto exit; + err = pack_bool(conn->out, 1); + if(err) goto exit; + err = pack_sxpr(conn->out, oxfr_ok); + if(err) goto exit; + err = pack_bool(conn->out, 1); + if(err) goto exit; + err = pack_sxpr(conn->out, mkint(vmid)); + if(err) goto exit; + err = pack_bool(conn->out, 0); + exit: + return err; +} + +int xfr_send_suspend(Conn *conn, uint32_t vmid){ + int err = 0; + + err = pack_type(conn->out, T_CONS); + if(err) goto exit; + err = pack_bool(conn->out, 1); + if(err) goto exit; + err = pack_sxpr(conn->out, oxfr_suspend); + if(err) goto exit; + err = pack_bool(conn->out, 1); + if(err) goto exit; + err = pack_sxpr(conn->out, mkint(vmid)); + if(err) goto exit; + err = pack_bool(conn->out, 0); + exit: + return err; +} + +/** Get vm state. Send transfer message. + * + * @param peer connection + * @param msg message + * @return 0 on success, error code otherwise + */ +int xfr_send_state(XfrState *state, Conn *xend, Conn *peer){ + int err = 0; + Sxpr sxpr; + + dprintf(">\n"); + XfrState_set_state(state, XFR_STATE); + // Send xfr message and the domain state. + err = xfr_send_xfr(peer, state->vmid); + if(err) goto exit; + err = xen_domain_snd(xend, peer->out, state->vmid, state->vmconfig, state->vmconfig_n); + if(err) goto exit; + IOStream_flush(peer->out); + // Read the response from the peer. + err = unpack_sxpr(peer->in, &sxpr); + if(err) goto exit; + if(sxpr_elementp(sxpr, oxfr_err)){ + // Error. + int errcode; + err = intof(sxpr_childN(sxpr, 0, ONONE), &errcode); + if(!err) err = errcode; + } else if(sxpr_elementp(sxpr, oxfr_ok)){ + // Ok - get the new domain id. + err = intof(sxpr_childN(sxpr, 0, ONONE), &state->vmid_new); + xfr_error(peer, err); + } else { + // Anything else is invalid. But it may be too late. + err = -EINVAL; + xfr_error(peer, err); + } + exit: + XfrState_set_err(state, err); + dprintf("< err=%d\n", err); + return err; +} + +/** Finish the transfer. + */ +int xfr_send_done(XfrState *state, Conn *xend){ + int err = 0; + int first_err = 0; + + first_err = XfrState_first_err(state); + if(first_err){ + XfrState_set_state(state, XFR_FAIL); + } else { + XfrState_set_state(state, XFR_DONE); + } + if(first_err){ + err = xfr_error(xend, first_err); + } else { + // Report new domain id to xend. + err = xfr_send_ok(xend, state->vmid_new); + } + + XfrState_set_err(state, err); + if(XfrState_first_err(state)){ + int s, serr; + + wprintf("> Transfer errors:\n"); + for(s = 0; s < XFR_MAX; s++){ + serr = state->state_err[s]; + if(!serr) continue; + wprintf("> state=%-12s err=%d\n", xfr_state_name(s), serr); + } + } else { + wprintf("> Transfer OK\n"); + } + dprintf("< err=%d\n", err); + return err; +} + +/** Migrate a vm to another node. + * + * @param xend connection + * @return 0 on success, error code otherwise + */ +int xfr_send(Args *args, XfrState *state, Conn *xend, uint32_t addr, uint32_t port){ + int err = 0; + Conn _peer = {}, *peer = &_peer; + int flags = 0; + struct in_addr xfr_addr; + uint16_t xfr_port; + time_t t0 = time(NULL), t1; + + dprintf(">\n"); + flags |= CONN_NOBUFFER; + if(args->compress){ + flags |= CONN_WRITE_COMPRESS; + } + xfr_addr.s_addr = addr; + xfr_port = port; + if(!xfr_port) xfr_port = htons(XFRD_PORT); + dprintf("> Xfr vmid=%u\n", state->vmid); + dprintf("> Xfr xfr_addr=%s:%d\n", inet_ntoa(xfr_addr), ntohs(xfr_port)); + err = Conn_connect(peer, flags, xfr_addr, xfr_port); + if(err) goto exit; + printf("\n"); + XfrState_set_state(state, XFR_HELLO); + // Send hello message. + err = xfr_send_hello(peer); + if(err) goto exit; + printf("\n"); + // Send vm state. + err = xfr_send_state(state, xend, peer); + if(err) goto exit; + if(args->compress){ + IOStream *zio = peer->out; + int plain_bytes = lzi_stream_plain_bytes(zio); + int comp_bytes = lzi_stream_comp_bytes(zio); + float ratio = lzi_stream_ratio(zio); + dprintf("> Compression: plain %d bytes, compressed %d bytes, ratio %3.2f\n", + plain_bytes, comp_bytes, ratio); + } + printf("\n"); + exit: + dprintf("> err=%d\n", err); + if(err && !XfrState_get_err(state)){ + XfrState_set_err(state, err); + } + Conn_close(peer); + if(!err){ + t1 = time(NULL) - t0; + dprintf("> Transfer complete in %lu seconds\n", t1); + } + dprintf("> done err=%d, notifying xend...\n", err); + xfr_send_done(state, xend); + dprintf("< err=%d\n", err); + return err; +} + +/** Save a vm to file. + */ +int xfr_save(Args *args, XfrState *state, Conn *xend, char *file){ + int err = 0; + IOStream *io = NULL; + + io = file_stream_fopen(file, "wb"); + if(!io){ + err = -EIO; + goto exit; + } + err = xen_domain_snd(xend, io, state->vmid, state->vmconfig, state->vmconfig_n); + exit: + if(io){ + IOStream_close(io); + IOStream_free(io); + } + return err; +} + +/** Accept the transfer of a vm from another node. + * + * @param peer connection + * @param msg message + * @return 0 on success, error code otherwise + */ +int xfr_recv(Args *args, XfrState *state, Conn *peer){ + int err = 0; + time_t t0 = time(NULL), t1; + + dprintf(">\n"); + err = xen_domain_rcv(peer->in, &state->vmid_new, &state->vmconfig, &state->vmconfig_n); + if(err) goto exit; + + err = xen_domain_configure(state->vmid_new, state->vmconfig, state->vmconfig_n); + if(err) goto exit; + + // Report new domain id to peer. + err = xfr_send_ok(peer, state->vmid_new); + if(err) goto exit; + // Get the final ok. + err = xfr_response(peer); + exit: + if(!err){ + t1 = time(NULL) - t0; + dprintf("> Transfer complete in %lu seconds\n", t1); + } + if(err){ + xfr_error(peer, err); + } + dprintf("< err=%d\n", err); + return err; +} + +/** Listen for a hello followed by a service request. + * The request can be from the local xend or from xfrd on another node. + * + * @param peersock socket + * @param peer_in peer address + * @return 0 on success, error code otherwise + */ +int xfrd_service(Args *args, int peersock, struct sockaddr_in peer_in){ + int err = 0; + Sxpr sxpr; + Conn _conn = {}, *conn = &_conn; + int flags = CONN_NOBUFFER; + + dprintf(">\n"); + err = Conn_init(conn, flags, peersock, peer_in); + if(err) goto exit; + err = xfr_hello(conn); + if(err) goto exit; + err = unpack_sxpr(conn->in, &sxpr); + if(err) goto exit; + if(sxpr_elementp(sxpr, oxfr_migrate)){ + // Migrate message from xend. + uint32_t addr; + uint16_t port; + XfrState _state = {}, *state = &_state; + int n = 0; + + dprintf("> xfr.migrate\n"); + err = intof(sxpr_childN(sxpr, n++, ONONE), &state->vmid); + if(err) goto exit; + err = stringof(sxpr_childN(sxpr, n++, ONONE), &state->vmconfig); + if(err) goto exit; + state->vmconfig_n = strlen(state->vmconfig); + err = addrof(sxpr_childN(sxpr, n++, ONONE), &addr); + if(err) goto exit; + err = portof(sxpr_childN(sxpr, n++, ONONE), &port); + if(err) goto exit; + err = xfr_send(args, state, conn, addr, port); + + } else if(sxpr_elementp(sxpr, oxfr_save)){ + // Save message from xend. + char *file; + XfrState _state = {}, *state = &_state; + int n = 0; + + dprintf("> xfr.save\n"); + err = intof(sxpr_childN(sxpr, n++, ONONE), &state->vmid); + if(err) goto exit; + err = stringof(sxpr_childN(sxpr, n++, ONONE), &state->vmconfig); + if(err) goto exit; + state->vmconfig_n = strlen(state->vmconfig); + err = stringof(sxpr_childN(sxpr, n++, ONONE), &file); + if(err) goto exit; + err = xfr_save(args, state, conn, file); + + } else if(sxpr_elementp(sxpr, oxfr_xfr)){ + // Xfr message from peer xfrd. + XfrState _state = {}, *state = &_state; + int n = 0; + + dprintf("> xfr.xfr\n"); + err = intof(sxpr_childN(sxpr, n++, ONONE), &state->vmid); + if(err) goto exit; + err = xfr_recv(args, state, conn); + + } else{ + // Anything else is invalid. + err = -EINVAL; + dprintf("> Invalid message: "); + objprint(iostderr, sxpr, 0); + IOStream_print(iostderr, "\n"); + xfr_error(conn, err); + } + exit: + Conn_close(conn); + dprintf("< err=%d\n", err); + return err; +} + +/** Accept an incoming connection. + * + * @param sock tcp socket + * @return 0 on success, error code otherwise + */ +int xfrd_accept(Args *args, int sock){ + struct sockaddr_in peer_in; + struct sockaddr *peer = (struct sockaddr *)&peer_in; + socklen_t peer_n = sizeof(peer_in); + int peersock; + pid_t pid; + int err = 0; + + dprintf(">\n"); + dprintf("> accept...\n"); + peersock = accept(sock, peer, &peer_n); + dprintf("> accept=%d\n", peersock); + if(peersock < 0){ + perror("accept"); + err = -errno; + goto exit; + } + iprintf("> Accepted connection from %s:%d\n", + inet_ntoa(peer_in.sin_addr), htons(peer_in.sin_port)); + pid = fork(); + if(pid > 0){ + // Parent, fork succeeded. + iprintf("> Forked child pid=%d\n", pid); + close(peersock); + } else if (pid < 0){ + // Parent, fork failed. + perror("fork"); + close(peersock); + } else { + // Child. + iprintf("> Xfr service for %s:%d\n", + inet_ntoa(peer_in.sin_addr), htons(peer_in.sin_port)); + err = xfrd_service(args, peersock, peer_in); + iprintf("> Xfr service err=%d\n", err); + shutdown(peersock, 2); + exit(err ? 1 : 0); + } + exit: + dprintf("< err=%d\n", err); + return err; +} + +/** Socket select loop. + * Accepts connections on the tcp socket. + * + * @param listen_sock tcp listen socket + * @return 0 on success, error code otherwise + */ +int xfrd_select(Args *args, int listen_sock){ + int err = 0; + SelectSet set = {}; + dprintf("> socks: %d\n", listen_sock); + while(1){ + SelectSet_zero(&set); + SelectSet_add_read(&set, listen_sock); + err = SelectSet_select(&set, NULL); + if(err < 0){ + if(errno == EINTR) continue; + perror("select"); + goto exit; + } + if(FD_ISSET(listen_sock, &set.rd)){ + xfrd_accept(args, listen_sock); + } + } + exit: + dprintf("< err=%d\n", err); + return err; +} + +/** Create a socket. + * + * @param args program arguments + * @param socktype socket type + * @param reuse whether to set SO_REUSEADDR + * @param val return value for the socket + * @return 0 on success, error code otherwise + */ +int create_socket(Args *args, int socktype, int reuse, int *val){ + int err = 0; + int sock = 0; + struct sockaddr_in addr_in; + struct sockaddr *addr = (struct sockaddr *)&addr_in; + socklen_t addr_n = sizeof(addr_in); + + dprintf(">\n"); + // Create socket and bind it. + sock = socket(AF_INET, socktype, 0); + if(sock < 0){ + err = -errno; + goto exit; + } + addr_in.sin_family = AF_INET; + addr_in.sin_addr.s_addr = INADDR_ANY; + addr_in.sin_port = args->port; + dprintf("> port=%d\n", ntohs(addr_in.sin_port)); + if(reuse){ + // Set socket option to reuse address. + int val = 1; + err = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)); + if(err < 0){ + err = -errno; + perror("setsockopt"); + goto exit; + } + } + err = bind(sock, addr, addr_n); + if(err < 0){ + err = -errno; + perror("bind"); + goto exit; + } + exit: + *val = (err ? -1 : sock); + dprintf("< err=%d\n", err); + return err; +} + +/** Create the tcp listen socket. + * + * @param args program arguments + * @param val return value for the socket + * @return 0 on success, error code otherwise + */ +int xfrd_listen_socket(Args *args, int *val){ + int err = 0; + int sock; + dprintf(">\n"); + err = create_socket(args, SOCK_STREAM, 1, &sock); + if(err) goto exit; + dprintf("> listen...\n"); + err = listen(sock, 5); + if(err < 0){ + err = -errno; + perror("listen"); + goto exit; + } + exit: + *val = (err ? -1 : sock); + if(err) close(sock); + dprintf("< err=%d\n", err); + return err; +} + +/** Type for signal handling functions. */ +typedef void SignalAction(int code, siginfo_t *info, void *data); + +/** Handle SIGCHLD by getting child exit status. + * This prevents child processes being defunct. + * + * @param code signal code + * @param info signal info + * @param data + */ +void sigaction_SIGCHLD(int code, siginfo_t *info, void *data){ + int status; + pid_t pid; + //dprintf("> child_exit=%d waiting...\n", child_exit); + pid = wait(&status); + dprintf("> child pid=%d status=%d\n", pid, status); +} + +/** Handle SIGPIPE. + * + * @param code signal code + * @param info signal info + * @param data + */ +void sigaction_SIGPIPE(int code, siginfo_t *info, void *data){ + dprintf("> SIGPIPE\n"); + //fflush(stdout); + //fflush(stderr); + //exit(1); +} + +/** Handle SIGALRM. + * + * @param code signal code + * @param info signal info + * @param data + */ +void sigaction_SIGALRM(int code, siginfo_t *info, void *data){ + dprintf("> SIGALRM\n"); +} + +/** Install a handler for a signal. + * + * @param signum signal + * @param action handler + * @return 0 on success, error code otherwise + */ +int catch_signal(int signum, SignalAction *action){ + int err = 0; + struct sigaction sig = {}; + sig.sa_sigaction = action; + sig.sa_flags = SA_SIGINFO; + err = sigaction(signum, &sig, NULL); + if(err){ + perror("sigaction"); + } + return err; +} + +/** Transfer daemon main program. + * + * @param args program arguments + * @return 0 on success, error code otherwise + */ +int xfrd_main(Args *args){ + int err = 0; + int listen_sock; + + dprintf(">\n"); + catch_signal(SIGCHLD,sigaction_SIGCHLD); + catch_signal(SIGPIPE,sigaction_SIGPIPE); + catch_signal(SIGALRM,sigaction_SIGALRM); + err = xfrd_listen_socket(args, &listen_sock); + if(err) goto exit; + err = xfrd_select(args, listen_sock); + exit: + close(listen_sock); + dprintf("< err=%d\n", err); + return err; +} + +/** Parse command-line arguments and call the xfrd main program. + * + * @param arg argument count + * @param argv arguments + * @return 0 on success, 1 otherwise + */ +int main(int argc, char *argv[]){ + int err = 0; + int key = 0; + int long_index = 0; + + set_defaults(args); + while(1){ + key = getopt_long(argc, argv, short_opts, long_opts, &long_index); + if(key == -1) break; + switch(key){ + case OPT_PORT: + err = !convert_service_to_port(optarg, &args->port); + if(err) goto exit; + break; + case OPT_COMPRESS: + args->compress = TRUE; + break; + case OPT_HELP: + usage(0); + break; + case OPT_VERBOSE: + args->verbose = TRUE; + break; + case OPT_VERSION: + printf("> Version %d.%d\n", XFR_PROTO_MAJOR, XFR_PROTO_MINOR); + exit(0); + break; + default: + usage(EINVAL); + break; + } + } + xfr_init(); + err = xfrd_main(args); + exit: + if(err && key > 0){ + fprintf(stderr, "Error in arg %c\n", key); + } + return (err ? 1 : 0); +} + diff --git a/tools/xfrd/xfrd.h b/tools/xfrd/xfrd.h new file mode 100644 index 0000000000..2537fd67ab --- /dev/null +++ b/tools/xfrd/xfrd.h @@ -0,0 +1,14 @@ +#ifndef _XFRD_XFRD_H_ +#define _XFRD_XFRD_H_ + +/** Xend port in host order. */ +#define XEND_PORT 8001 + +/** Xfrd port in host order. */ +#define XFRD_PORT 8002 + +/** Protocol version. */ +#define XFR_PROTO_MAJOR 1 +#define XFR_PROTO_MINOR 0 + +#endif diff --git a/tools/xfrd/xfrdClient.py b/tools/xfrd/xfrdClient.py new file mode 100755 index 0000000000..b8a3554729 --- /dev/null +++ b/tools/xfrd/xfrdClient.py @@ -0,0 +1,127 @@ +#!/bin/env python +""" +Test client for the migration daemon (xfrd). + +Author: Mike Wray + +""" +import getopt +import sys +import os +from socket import * +import StringIO + +sys.path.append("/home/mjw/repos-bk/xeno-unstable.bk/tools/python") + +import xen.xend.sxp as sxp +from xen.xend.packing import SxpPacker, SxpUnpacker + +XFRD_PORT = 8002 + +verbose = 0 + +class TCPClient: + + def __init__(self, host, port): + print ">TCPClient" + self.sock = socket(AF_INET, SOCK_STREAM, 0) + print ">TCPClient sock=", self.sock + print ">TCPClient> connect ", host, port + v = self.sock.connect((host, port)) + print ">TCPClient> connect=", v + # Send plain header (no gzip). + #self.sock.send("\0\0") + + self.sockin = self.sock.makefile("r") + self.sockout = self.sock.makefile("w") + self.packer = SxpPacker(self.sockout) + self.unpacker = SxpUnpacker(self.sockin) + #pass + + def request(self, req): + print "request>", req + self.packer.pack(req) + self.sockout.flush() + print "request<" + + def request_hello(self): + self.request(['xfr.hello', XFR_PROTO_MAJOR, XFR_PROTO_MINOR]) + + def request_migrate(self, vmid, vhost, vport, vmconfig='(vm)'): + self.request(['xfr.migrate', vmid, vmconfig, vhost, vport]) + + def read(self): + while(1): + v = self.unpacker.unpack() + print 'read>', v + if v[0] == 'xfr.err' and v[1]: return + if v[0] == 'xfr.ok': return + +XFR_PROTO_MAJOR = 1 +XFR_PROTO_MINOR = 0 + +host_default = "localhost" +port_default = XFRD_PORT +vhost_default = "localhost" +vport_default = 8003 +vmid_default = 1 + +# Short options. Options followed by ':' need a parameter. +short_opts = 'h' + +# Long options. Options ending in '=' need a parameter. +long_opts = [ 'host=', 'port=', 'vhost=', 'vport=', 'vmid=', 'verbose', 'help'] + +def usage(err=None): + if err: + out = sys.stderr + else: + out = sys.stdout + print >> out, 'Usage: %s [options] [command...]\n' % sys.argv[0] + print >> out, '--host \n\tHost to initiate transfer on. Default %s.' % host_default + print >> out, '--port \n\tPort to initiate transfer on. Default %d.' % port_default + print >> out, '--vhost \n\tHost to transfer VM to. Default %s.' % vhost_default + print >> out, '--vport \n\tPort to transfer VM to. Default %d.' % vport_default + print >> out, '--vmid \n\tVM id. Default %d.' % vmid_default + print >> out, '--help\n\tPrint help.' + +def main(argv): + global verbose + host = host_default + port = port_default + vhost = vhost_default + vport = vport_default + vmid = vmid_default + + try: + opts, args = getopt.getopt(argv[1:], short_opts, long_opts) + except getopt.GetoptError, ex: + print >>sys.stderr, 'Error:', ex + usage(1) + sys.exit(1) + + for key, val in opts: + if key == '--help': + usage() + sys.exit(0) + elif key == '--host': + host = val + elif key == '--port': + port = int(val) + elif key == '--vhost': + vhost = val + elif key == '--vport': + vport = int(val) + elif key == '--vmid': + vmid = int(val) + + print "host=%s port=%d" % (host, port) + print "vhost=%s vport=%d vmid=%d" % (vhost, vport, vmid) + client = TCPClient(gethostbyname(host), port) + client.request_hello() + client.request_migrate(vmid, gethostbyname(vhost), vport) + client.read() + +if __name__ == '__main__': + main(sys.argv) + From 8d3ebbb7a998463ca9c596374c293e40eeef6bed Mon Sep 17 00:00:00 2001 From: "mjw@wray-m-3.hpl.hp.com" Date: Tue, 6 Jul 2004 12:57:26 +0000 Subject: [PATCH 24/36] bitkeeper revision 1.1041.7.1 (40eaa1b63pn-AWBaQWrFszKHGANStQ) Tidy up messaging to device backends. Add message response handlers indexed by message id instead of relying on a queue of deferreds. Tidy up error handling so that deferred errors are caught. --- tools/python/xen/xend/XendDomain.py | 1 + tools/python/xen/xend/XendDomainInfo.py | 17 ++- tools/python/xen/xend/XendMigrate.py | 1 + tools/python/xen/xend/server/SrvBase.py | 1 + tools/python/xen/xend/server/SrvDaemon.py | 1 + tools/python/xen/xend/server/SrvDomainDir.py | 12 +- tools/python/xen/xend/server/blkif.py | 92 +++++++------ tools/python/xen/xend/server/controller.py | 136 +++++++++++++------ tools/python/xen/xend/server/messages.py | 14 +- tools/python/xen/xend/server/netif.py | 46 +++---- 10 files changed, 208 insertions(+), 113 deletions(-) diff --git a/tools/python/xen/xend/XendDomain.py b/tools/python/xen/xend/XendDomain.py index 4bde519b49..8b9db8101c 100644 --- a/tools/python/xen/xend/XendDomain.py +++ b/tools/python/xen/xend/XendDomain.py @@ -8,6 +8,7 @@ import sys import traceback from twisted.internet import defer +defer.Deferred.debug = 1 from twisted.internet import reactor import xen.lowlevel.xc; xc = xen.lowlevel.xc.new() diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index f14e6477c2..619d575466 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -15,6 +15,7 @@ import sys import os from twisted.internet import defer +defer.Deferred.debug = 1 import xen.lowlevel.xc; xc = xen.lowlevel.xc.new() import xen.util.ip @@ -430,14 +431,18 @@ class XendDomainInfo: raise VmError('unknown image type: ' + image_name) image_handler(self, image) deferred = self.configure() + def cbok(x): + print 'vm_create> cbok', x + return x + def cberr(err): + self.destroy() + return err + deferred.addCallback(cbok) + deferred.addErrback(cberr) except StandardError, ex: # Catch errors, cleanup and re-raise. self.destroy() raise - def cbok(x): - print 'vm_create> cbok', x - return x - deferred.addCallback(cbok) print 'vm_create<' return deferred @@ -710,6 +715,10 @@ class XendDomainInfo: self.name = d['name'] self.memory = d['memory']/1024 deferred = self.configure() + def cberr(err): + self.destroy() + return err + deferred.addErrback(cberr) except StandardError, ex: self.destroy() raise diff --git a/tools/python/xen/xend/XendMigrate.py b/tools/python/xen/xend/XendMigrate.py index 471ea7d1dd..a598913792 100644 --- a/tools/python/xen/xend/XendMigrate.py +++ b/tools/python/xen/xend/XendMigrate.py @@ -6,6 +6,7 @@ import time from twisted.internet import reactor from twisted.internet import defer +defer.Deferred.debug = 1 from twisted.internet.protocol import Protocol from twisted.internet.protocol import ClientFactory diff --git a/tools/python/xen/xend/server/SrvBase.py b/tools/python/xen/xend/server/SrvBase.py index bcff1bc3a0..059220c408 100644 --- a/tools/python/xen/xend/server/SrvBase.py +++ b/tools/python/xen/xend/server/SrvBase.py @@ -8,6 +8,7 @@ import types import StringIO from twisted.internet import defer +defer.Deferred.debug = 1 from twisted.internet import reactor from twisted.web import error from twisted.web import resource diff --git a/tools/python/xen/xend/server/SrvDaemon.py b/tools/python/xen/xend/server/SrvDaemon.py index 63c4dd1bee..a514b89108 100644 --- a/tools/python/xen/xend/server/SrvDaemon.py +++ b/tools/python/xen/xend/server/SrvDaemon.py @@ -23,6 +23,7 @@ from twisted.internet import reactor from twisted.internet import protocol from twisted.internet import abstract from twisted.internet import defer +defer.Deferred.debug = 1 from xen.lowlevel import xu diff --git a/tools/python/xen/xend/server/SrvDomainDir.py b/tools/python/xen/xend/server/SrvDomainDir.py index 03c869051e..eb1521e117 100644 --- a/tools/python/xen/xend/server/SrvDomainDir.py +++ b/tools/python/xen/xend/server/SrvDomainDir.py @@ -63,7 +63,8 @@ class SrvDomainDir(SrvDir): "Invalid configuration") try: deferred = self.xd.domain_create(config) - deferred.addCallback(self._cb_op_create, configstring, req) + deferred.addCallback(self._op_create_cb, configstring, req) + deferred.addErrback(self._op_create_err, req) return deferred except Exception, ex: print 'op_create> Exception creating domain:' @@ -75,7 +76,7 @@ class SrvDomainDir(SrvDir): # str(ex)) - def _cb_op_create(self, dominfo, configstring, req): + def _op_create_cb(self, dominfo, configstring, req): """Callback to handle deferred domain creation. """ dom = dominfo.id @@ -95,6 +96,13 @@ class SrvDomainDir(SrvDir): out.close() return val + def _op_create_err(self, err, req): + """Callback to handle errors in deferred domain creation. + """ + print 'op_create> Deferred Exception creating domain:', err + req.setResponseCode(http.BAD_REQUEST, "Error creating domain") + return str(err) + def op_restore(self, op, req): """Restore a domain from file. """ diff --git a/tools/python/xen/xend/server/blkif.py b/tools/python/xen/xend/server/blkif.py index d265ae382e..5596ddb842 100755 --- a/tools/python/xen/xend/server/blkif.py +++ b/tools/python/xen/xend/server/blkif.py @@ -1,6 +1,7 @@ # Copyright (C) 2004 Mike Wray from twisted.internet import defer +defer.Deferred.debug = 1 from xen.xend import sxp from xen.xend import PrettyPrint @@ -20,10 +21,6 @@ class BlkifControllerFactory(controller.ControllerFactory): self.majorTypes = [ CMSG_BLKIF_BE ] self.subTypes = { - CMSG_BLKIF_BE_CREATE : self.recv_be_create, - CMSG_BLKIF_BE_CONNECT : self.recv_be_connect, - CMSG_BLKIF_BE_VBD_CREATE : self.recv_be_vbd_create, - CMSG_BLKIF_BE_VBD_GROW : self.recv_be_vbd_grow, CMSG_BLKIF_BE_DRIVER_STATUS_CHANGED: self.recv_be_driver_status_changed, } self.attached = 1 @@ -35,17 +32,20 @@ class BlkifControllerFactory(controller.ControllerFactory): dom domain recreate if true it's a recreate (after xend restart) """ - d = self.addDeferred() + d = defer.Deferred() blkif = self.getInstanceByDom(dom) if blkif: - self.callDeferred(blkif) + d.callback(blkif) else: blkif = BlkifController(self, dom) self.addInstance(blkif) if recreate: - self.callDeferred(blkif) + d.callback(blkif) else: - blkif.send_be_create() + d1 = defer.Deferred() + d1.addCallback(self.respond_be_create, d) + d1.addErrback(d.errback) + blkif.send_be_create(response=d1) return d def getDomainDevices(self, dom): @@ -117,14 +117,14 @@ class BlkifControllerFactory(controller.ControllerFactory): for blkif in self.getInstances(): blkif.reattached() - def recv_be_create(self, msg, req): - #print 'recv_be_create>' + def respond_be_create(self, msg, d): + print 'respond_be_create>' val = unpackMsg('blkif_be_create_t', msg) blkif = self.getInstanceByDom(val['domid']) - self.callDeferred(blkif) + d.callback(blkif) - def recv_be_connect(self, msg, req): - #print 'recv_be_create>' + def respond_be_connect(self, msg): + print 'respond_be_connect>', self val = unpackMsg('blkif_be_connect_t', msg) blkif = self.getInstanceByDom(val['domid']) if blkif: @@ -132,25 +132,30 @@ class BlkifControllerFactory(controller.ControllerFactory): else: pass - def recv_be_vbd_create(self, msg, req): - #print 'recv_be_vbd_create>' + def respond_be_vbd_create(self, msg, d): + print 'recv_be_vbd_create>', self val = unpackMsg('blkif_be_vbd_create_t', msg) blkif = self.getInstanceByDom(val['domid']) if blkif: - blkif.send_be_vbd_grow(val['vdevice']) + d1 = defer.Deferred() + d1.addCallback(self.respond_be_vbd_grow, d) + if d: d1.addErrback(d.errback) + blkif.send_be_vbd_grow(val['vdevice'], response=d1) else: pass - def recv_be_vbd_grow(self, msg, req): - #print 'recv_be_vbd_grow>' + def respond_be_vbd_grow(self, msg, d): + print 'recv_be_vbd_grow>', self val = unpackMsg('blkif_be_vbd_grow_t', msg) # Check status? if self.attached: - self.callDeferred(0) + if d: + d.callback(0) else: self.reattachDevice(val['domid'], val['vdevice']) def recv_be_driver_status_changed(self, msg, req): + print 'recv_be_driver_status_changed>', self, req val = unpackMsg('blkif_be_driver_status_changed_t', msg) status = val['status'] if status == BLKIF_DRIVER_STATUS_UP and not self.attached: @@ -234,20 +239,22 @@ class BlkifController(controller.Controller): """ dev = self.addDevice(vdev, mode, segment) if not dev: return -1 + d = defer.Deferred() if recreate: - d = defer.Deferred() d.callback(self) else: - self.send_be_vbd_create(vdev) - d = self.factory.addDeferred() + d1 = defer.Deferred() + d1.addCallback(self.factory.respond_be_vbd_create, d) + d1.addErrback(d.errback) + self.send_be_vbd_create(vdev, response=d1) return d def destroy(self): def cb_destroy(val): self.send_be_destroy() - d = self.factory.addDeferred() + d = defer.Deferred() d.addCallback(cb_destroy) - self.send_be_disconnect() + self.send_be_disconnect(response=d) def destroyDevices(self): for dev in self.getDevices(): @@ -259,7 +266,9 @@ class BlkifController(controller.Controller): self.attached = 0 for dev in self.devices.values(): dev.attached = 0 - self.send_be_vbd_create(vdev) + d1 = defer.Deferred() + d1.addCallback(self.factory.respond_be_vbd_create, None) + self.send_be_vbd_create(vdev, response=d1) def reattachDevice(self, vdev): """Reattach a device, when the back-end control domain has changed. @@ -300,46 +309,47 @@ class BlkifController(controller.Controller): 'blkif_handle' : val['handle'], 'evtchn' : self.evtchn['port1'], 'shmem_frame' : val['shmem_frame'] }) - self.factory.writeRequest(msg) - pass + d = defer.Deferred() + d.addCallback(self.factory.respond_be_connect) + self.factory.writeRequest(msg, response=d) - def send_fe_interface_status_changed(self): + def send_fe_interface_status_changed(self, response=None): msg = packMsg('blkif_fe_interface_status_changed_t', { 'handle' : 0, 'status' : BLKIF_INTERFACE_STATUS_CONNECTED, 'evtchn' : self.evtchn['port2'] }) - self.writeRequest(msg) + self.writeRequest(msg, response=response) - def send_be_create(self): + def send_be_create(self, response=None): msg = packMsg('blkif_be_create_t', { 'domid' : self.dom, 'blkif_handle' : 0 }) - self.factory.writeRequest(msg) + self.factory.writeRequest(msg, response=response) - def send_be_disconnect(self): + def send_be_disconnect(self, response=None): print '>BlkifController>send_be_disconnect>', 'dom=', self.dom msg = packMsg('blkif_be_disconnect_t', { 'domid' : self.dom, 'blkif_handle' : 0 }) - self.factory.writeRequest(msg) + self.factory.writeRequest(msg, response=response) - def send_be_destroy(self): + def send_be_destroy(self, response=None): print '>BlkifController>send_be_destroy>', 'dom=', self.dom msg = packMsg('blkif_be_destroy_t', { 'domid' : self.dom, 'blkif_handle' : 0 }) - self.factory.writeRequest(msg) + self.factory.writeRequest(msg, response=response) - def send_be_vbd_create(self, vdev): + def send_be_vbd_create(self, vdev, response=None): dev = self.devices[vdev] msg = packMsg('blkif_be_vbd_create_t', { 'domid' : self.dom, 'blkif_handle' : 0, 'vdevice' : dev.vdev, 'readonly' : dev.readonly() }) - self.factory.writeRequest(msg) + self.factory.writeRequest(msg, response=response) - def send_be_vbd_grow(self, vdev): + def send_be_vbd_grow(self, vdev, response=None): dev = self.devices[vdev] msg = packMsg('blkif_be_vbd_grow_t', { 'domid' : self.dom, @@ -348,9 +358,9 @@ class BlkifController(controller.Controller): 'extent.device' : dev.device, 'extent.sector_start' : dev.start_sector, 'extent.sector_length' : dev.nr_sectors }) - self.factory.writeRequest(msg) + self.factory.writeRequest(msg, response=response) - def send_be_vbd_destroy(self, vdev): + def send_be_vbd_destroy(self, vdev, response=None): print '>BlkifController>send_be_vbd_destroy>', 'dom=', self.dom, 'vdev=', vdev PrettyPrint.prettyprint(self.sxpr()) dev = self.devices[vdev] @@ -359,5 +369,5 @@ class BlkifController(controller.Controller): 'blkif_handle' : 0, 'vdevice' : dev.vdev }) del self.devices[vdev] - self.factory.writeRequest(msg) + self.factory.writeRequest(msg, response=response) diff --git a/tools/python/xen/xend/server/controller.py b/tools/python/xen/xend/server/controller.py index 6804331ac7..6d0bd9295f 100755 --- a/tools/python/xen/xend/server/controller.py +++ b/tools/python/xen/xend/server/controller.py @@ -1,10 +1,39 @@ # Copyright (C) 2004 Mike Wray from twisted.internet import defer +defer.Deferred.debug = 1 import channel from messages import msgTypeName +DEBUG=0 + +class OutOfOrderError(RuntimeError): + """Error reported when a response arrives out of order. + """ + pass + +class Responder: + """Handler for a response to a message. + """ + + def __init__(self, mid, deferred): + """Create a responder. + + mid message id of response to handle + deferred deferred object holding the callbacks + """ + self.mid = mid + self.deferred = deferred + + def responseReceived(self, msg): + if self.deferred.called: return + self.deferred.callback(msg) + + def error(self, err): + if self.deferred.called: return + self.deferred.errback(err) + class CtrlMsgRcvr: """Abstract class for things that deal with a control interface to a domain. @@ -26,6 +55,12 @@ class CtrlMsgRcvr: self.dom = None self.channel = None self.idx = None + self.responders = [] + # Timeout (in seconds) for deferreds. + self.timeout = 10 + + def setTimeout(self, timeout): + self.timeout = timeout def requestReceived(self, msg, type, subtype): """Dispatch a request to handlers. @@ -34,10 +69,13 @@ class CtrlMsgRcvr: type major message type subtype minor message type """ + msgid = msg.get_header()['id'] + if DEBUG: + print 'requestReceived>', self, msgid, msgTypeName(type, subtype) method = self.subTypes.get(subtype) if method: method(msg, 1) - else: + elif DEBUG: print ('requestReceived> No handler: Message type %s %d:%d' % (msgTypeName(type, subtype), type, subtype)), self @@ -48,13 +86,61 @@ class CtrlMsgRcvr: type major message type subtype minor message type """ + msgid = msg.get_header()['id'] + if DEBUG: + print 'responseReceived>', self, msgid, msgTypeName(type, subtype) + if self.callResponders(msg): + return method = self.subTypes.get(subtype) if method: method(msg, 0) - else: + elif DEBUG: print ('responseReceived> No handler: Message type %s %d:%d' % (msgTypeName(type, subtype), type, subtype)), self + def addResponder(self, mid, deferred): + """Add a responder for a message id. + The deferred is called with callback(msg) when a response + with the given message id arrives. Responses are expected + to arrive in order of message id. When a response arrives, + waiting responders for messages with lower id have errback + called with an OutOfOrder error. + + mid message id of response expected + deferred a Deferred to handle the response + + returns Responder + """ + if self.timeout > 0: + deferred.setTimeout(self.timeout) + resp = Responder(mid, deferred) + self.responders.append(resp) + return resp + + def callResponders(self, msg): + """Call any waiting responders for a response message. + + msg response message + + returns 1 if there was a responder for the message, 0 otherwise + """ + hdr = msg.get_header() + mid = hdr['id'] + handled = 0 + while self.responders: + resp = self.responders[0] + if resp.mid > mid: + break + self.responders.pop() + if resp.mid < mid: + print 'handleResponse> Out of order:', resp.mid, mid + resp.error(OutOfOrderError()) + else: + handled = 1 + resp.responseReceived(msg) + break + return handled + def lostChannel(self): """Called when the channel to the domain is lost. """ @@ -64,7 +150,6 @@ class CtrlMsgRcvr: """Register interest in our major message types with the channel to our domain. """ - #print 'CtrlMsgRcvr>registerChannel>', self self.channel = self.channelFactory.domChannel(self.dom) self.idx = self.channel.getIndex() if self.majorTypes: @@ -74,7 +159,6 @@ class CtrlMsgRcvr: """Deregister interest in our major message types with the channel to our domain. """ - #print 'CtrlMsgRcvr>deregisterChannel>', self if self.channel: self.channel.deregisterDevice(self) del self.channel @@ -86,10 +170,16 @@ class CtrlMsgRcvr: """ return 0 - def writeRequest(self, msg): + def writeRequest(self, msg, response=None): """Write a request to the channel. + + msg message + response Deferred to handle the response (optional) """ if self.channel: + if DEBUG: print 'CtrlMsgRcvr>writeRequest>', self, msg + if response: + self.addResponder(msg.get_header()['id'], response) self.channel.writeRequest(msg) else: print 'CtrlMsgRcvr>writeRequest>', 'no channel!', self @@ -98,6 +188,7 @@ class CtrlMsgRcvr: """Write a response to the channel. """ if self.channel: + if DEBUG: print 'CtrlMsgRcvr>writeResponse>', self, msg self.channel.writeResponse(msg) else: print 'CtrlMsgRcvr>writeResponse>', 'no channel!', self @@ -111,7 +202,6 @@ class ControllerFactory(CtrlMsgRcvr): instances : mapping of index to controller instance dlist : list of deferreds dom : domain - timeout : deferred timeout """ def __init__(self): @@ -119,8 +209,6 @@ class ControllerFactory(CtrlMsgRcvr): self.instances = {} self.dlist = [] self.dom = 0 - # Timeout (in seconds) for deferreds. - self.timeout = 10 def addInstance(self, instance): """Add a controller instance (under its index). @@ -161,38 +249,6 @@ class ControllerFactory(CtrlMsgRcvr): """ self.delInstance(instance) - def addDeferred(self): - """Add a deferred object. - - returns deferred - """ - d = defer.Deferred() - if self.timeout > 0: - # The deferred will error if not called before timeout. - d.setTimeout(self.timeout) - self.dlist.append(d) - return d - - def callDeferred(self, *args): - """Call the top deferred object - - args arguments - """ - if self.dlist: - d = self.dlist.pop(0) - if not d.called: - d.callback(*args) - - def errDeferred(self, *args): - """Signal an error to the top deferred object. - - args arguments - """ - if self.dlist: - d = self.dlist.pop(0) - if not d.called: - d.errback(*args) - class Controller(CtrlMsgRcvr): """Abstract class for a device controller attached to a domain. """ diff --git a/tools/python/xen/xend/server/messages.py b/tools/python/xen/xend/server/messages.py index bd2c1eed0e..edda5f2303 100644 --- a/tools/python/xen/xend/server/messages.py +++ b/tools/python/xen/xend/server/messages.py @@ -179,6 +179,12 @@ msg_formats.update(shutdown_formats) class Msg: pass +_next_msgid = 0 + +def nextid(): + global _next_msgid + return ++_next_msgid + def packMsg(ty, params): """Pack a message. Any 'mac' parameter is passed in as an int[6] array and converted. @@ -188,7 +194,8 @@ def packMsg(ty, params): returns xu message """ - if DEBUG: print '>packMsg', ty, params + msgid = nextid() + if DEBUG: print '>packMsg', msgid, ty, params (major, minor) = msg_formats[ty] args = {} for (k, v) in params.items(): @@ -200,7 +207,6 @@ def packMsg(ty, params): if DEBUG: for (k, v) in args.items(): print 'packMsg>', k, v, type(v) - msgid = 0 msg = xu.message(major, minor, msgid, args) return msg @@ -228,7 +234,9 @@ def unpackMsg(ty, msg): args['mac'] = mac for k in macs: del args[k] - if DEBUG: print ' unknown vif=", vif + print "respond_be_connect> unknown vif=", vif pass def recv_be_driver_status_changed(self, msg, req): @@ -168,9 +166,10 @@ class NetDev(controller.Dev): def cb_destroy(val): self.controller.send_be_destroy(self.vif) self.down() - d = self.controller.factory.addDeferred() + #d = self.controller.factory.addDeferred() + d = defer.Deferred() d.addCallback(cb_destroy) - self.controller.send_be_disconnect(self.vif) + self.controller.send_be_disconnect(self.vif, response=d) class NetifController(controller.Controller): @@ -268,20 +267,19 @@ class NetifController(controller.Controller): @param vmac mac address (string) """ self.addDevice(vif, vmac) + d = defer.Deferred() if recreate: - d = defer.Deferred() d.callback(self) else: - d = self.factory.addDeferred() - self.send_be_create(vif) + self.send_be_create(vif, response=d) return d def reattach_devices(self): """Reattach all devices when the back-end control domain has changed. """ - d = self.factory.addDeferred() + #d = self.factory.addDeferred() self.send_be_create(vif) - self.attach_fe_devices(0) + self.attach_fe_devices() def attach_fe_devices(self): for dev in self.devices.values(): @@ -310,37 +308,39 @@ class NetifController(controller.Controller): 'evtchn' : dev.evtchn['port1'], 'tx_shmem_frame' : val['tx_shmem_frame'], 'rx_shmem_frame' : val['rx_shmem_frame'] }) - self.factory.writeRequest(msg) + d = defer.Deferred() + d.addCallback(self.factory.respond_be_connect) + self.factory.writeRequest(msg, response=d) - def send_interface_connected(self, vif): + def send_interface_connected(self, vif, response=None): dev = self.devices[vif] msg = packMsg('netif_fe_interface_status_changed_t', { 'handle' : dev.vif, 'status' : NETIF_INTERFACE_STATUS_CONNECTED, 'evtchn' : dev.evtchn['port2'], 'mac' : dev.mac }) - self.writeRequest(msg) + self.writeRequest(msg, response=response) - def send_be_create(self, vif): + def send_be_create(self, vif, response=None): dev = self.devices[vif] msg = packMsg('netif_be_create_t', { 'domid' : self.dom, 'netif_handle' : dev.vif, 'mac' : dev.mac }) - self.factory.writeRequest(msg) + self.factory.writeRequest(msg, response=response) - def send_be_disconnect(self, vif): + def send_be_disconnect(self, vif, response=None): dev = self.devices[vif] msg = packMsg('netif_be_disconnect_t', { 'domid' : self.dom, 'netif_handle' : dev.vif }) - self.factory.writeRequest(msg) + self.factory.writeRequest(msg, response=response) - def send_be_destroy(self, vif): + def send_be_destroy(self, vif, response=None): PrettyPrint.prettyprint(self.sxpr()) dev = self.devices[vif] del self.devices[vif] msg = packMsg('netif_be_destroy_t', { 'domid' : self.dom, 'netif_handle' : vif }) - self.factory.writeRequest(msg) + self.factory.writeRequest(msg, response=response) From 75bfa50745e070ad3df53ee88016fb8879e3eade Mon Sep 17 00:00:00 2001 From: "kaf24@scramble.cl.cam.ac.uk" Date: Tue, 6 Jul 2004 15:12:42 +0000 Subject: [PATCH 25/36] bitkeeper revision 1.1041.8.1 (40eac16as-X5mJEQ0g8YVoYYxLFmBg) Tidy up and simplify the Python s-expression parser. --- tools/python/xen/xend/XendDomainInfo.py | 27 +- tools/python/xen/xend/XendRoot.py | 2 +- tools/python/xen/xend/sxp.py | 536 ++++-------------------- tools/python/xen/xm/main.py | 16 +- 4 files changed, 97 insertions(+), 484 deletions(-) diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index f14e6477c2..1269c2155c 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -291,6 +291,9 @@ def vm_restore(src, progress=0): if dom < 0: raise VmError('restore failed') vmconfig = sxp.from_string(d['vmconfig']) + if not vmconfig: + raise VmError('bad vmconfig s-expression') + vmconfig = vmconfig[0] vm.config = sxp.child_value(vmconfig, 'config') deferred = vm.dom_configure(dom) def vifs_cb(val, vm): @@ -419,8 +422,8 @@ class XendDomainInfo: self.config = config try: self.name = sxp.child_value(config, 'name') - self.memory = int(sxp.child_value(config, 'memory', '128')) - if sxp.child(config, 'autorestart', None): + self.memory = int(sxp.child_value(config, 'memory') or '128') + if sxp.child(config, 'autorestart'): self.autorestart = 1 self.configure_backends() image = sxp.child_value(config, 'image') @@ -449,7 +452,7 @@ class XendDomainInfo: """ devices = [] for d in sxp.children(self.config, 'device'): - dev = sxp.child0(d) + dev = sxp.child(d) if dev is None: continue if name == sxp.name(dev): devices.append(dev) @@ -580,7 +583,7 @@ class XendDomainInfo: if self.recreate: return memory = self.memory name = self.name - cpu = int(sxp.child_value(self.config, 'cpu', '-1')) + cpu = int(sxp.child_value(self.config, 'cpu') or '-1') print 'init_domain>', memory, name, cpu dom = xc.domain_create(mem_kb= memory * 1024, name= name, cpu= cpu) if dom <= 0: @@ -645,7 +648,7 @@ class XendDomainInfo: devices = sxp.children(self.config, 'device') index = {} for d in devices: - dev = sxp.child0(d) + dev = sxp.child(d) if dev is None: raise VmError('invalid device') dev_name = sxp.name(dev) @@ -664,7 +667,7 @@ class XendDomainInfo: """Set configuration flags if the vm is a backend for netif of blkif. """ for c in sxp.children(self.config, 'backend'): - name = sxp.name(sxp.child0(c)) + name = sxp.name(sxp.child(c)) if name == 'blkif': self.blkif_backend = 1 elif name == 'netif': @@ -742,7 +745,7 @@ def vm_image_linux(vm, image): """ kernel = sxp.child_value(image, "kernel") cmdline = "" - ip = sxp.child_value(image, "ip", "dhcp") + ip = sxp.child_value(image, "ip") or "dhcp" if ip: cmdline += " ip=" + ip root = sxp.child_value(image, "root") @@ -751,7 +754,7 @@ def vm_image_linux(vm, image): args = sxp.child_value(image, "args") if args: cmdline += " " + args - ramdisk = sxp.child_value(image, "ramdisk", '') + ramdisk = sxp.child_value(image, "ramdisk") or '' vifs = vm.config_devices("vif") vm.create_domain("linux", kernel, ramdisk, cmdline, len(vifs)) return vm @@ -768,7 +771,7 @@ def vm_image_netbsd(vm, image): #todo: Same as for linux. Is that right? If so can unify them. kernel = sxp.child_value(image, "kernel") cmdline = "" - ip = sxp.child_value(image, "ip", "dhcp") + ip = sxp.child_value(image, "ip") or "dhcp" if ip: cmdline += "ip=" + ip root = sxp.child_value(image, "root") @@ -797,7 +800,7 @@ def vm_dev_vif(vm, val, index): defer = make_vif(vm.dom, vif, vmac, vm.recreate) def fn(id): dev = xend.netif_dev(vm.dom, vif) - devid = sxp.attribute(val, 'id') + devid = sxp.child_value(val, 'id') if devid: dev.setprop('id', devid) bridge = sxp.child_value(val, "bridge") @@ -824,7 +827,7 @@ def vm_dev_vbd(vm, val, index): dev = sxp.child_value(val, 'dev') if not dev: raise VmError('vbd: Missing dev') - mode = sxp.child_value(val, 'mode', 'r') + mode = sxp.child_value(val, 'mode') or 'r' defer = make_disk(vm.dom, uname, dev, mode, vm.recreate) def fn(vbd): dev = xend.blkif_dev(vm.dom, vdev) @@ -926,7 +929,7 @@ def vm_field_vnet(vm, config, val, index): if id is None: raise VmError('vnet: missing vif id') dev = vm.get_device_by_id('vif', id) - #vnet = sxp.child_value(v, 'vnet', 1) + #vnet = sxp.child_value(v, 'vnet') or '1' #mac = sxp.child_value(dev, 'mac') #vif = sxp.child_value(dev, 'vif') #vnet_bridge(vnet, mac, vm.dom, 0) diff --git a/tools/python/xen/xend/XendRoot.py b/tools/python/xen/xend/XendRoot.py index 665f5df29e..3687f57f4a 100644 --- a/tools/python/xen/xend/XendRoot.py +++ b/tools/python/xen/xend/XendRoot.py @@ -145,7 +145,7 @@ class XendRoot: val default value (optional, defaults to None) returns value """ - return sxp.child_value(self.config, name, val=val) + return sxp.child_value(self.config, name) or val def instance(): global inst diff --git a/tools/python/xen/xend/sxp.py b/tools/python/xen/xend/sxp.py index 143ba81ab4..352f7f2933 100644 --- a/tools/python/xen/xend/sxp.py +++ b/tools/python/xen/xend/sxp.py @@ -21,56 +21,19 @@ from StringIO import StringIO __all__ = [ "mime_type", "ParseError", - "Parser", - "atomp", - "show", - "show_xml", - "elementp", + "Parser", + "show", "name", - "attributes", - "attribute", "children", "child", - "child_at", - "child0", - "child1", - "child2", - "child3", - "child4", "child_value", - "has_id", - "with_id", - "child_with_id", - "elements", "to_string", "from_string", - "all_from_string", "parse", ] mime_type = "application/sxp" -escapes = { - 'a': '\a', - 'b': '\b', - 't': '\t', - 'n': '\n', - 'v': '\v', - 'f': '\f', - 'r': '\r', - '\\': '\\', - '\'': '\'', - '\"': '\"'} - -k_list_open = "(" -k_list_close = ")" -k_attr_open = "@" -k_eval = "!" - -escapes_rev = {} -for k in escapes: - escapes_rev[escapes[k]] = k - class ParseError(StandardError): def __init__(self, parser, value): @@ -86,7 +49,6 @@ class ParserState: self.parent = parent self.buf = '' self.val = [] - self.delim = None self.fn = fn def push(self, fn): @@ -95,28 +57,19 @@ class ParserState: class Parser: def __init__(self): - self.error = sys.stderr self.reset() def reset(self): - self.val = [] self.eof = 0 - self.err = 0 self.line_no = 0 self.char_no = 0 - self.state = None + self.state = self.start_state = ParserState(self.state_start) def push_state(self, fn): self.state = self.state.push(fn) def pop_state(self): - val = self.state self.state = self.state.parent - if self.state and self.state.fn == self.state_start: - # Return to start state - produce the value. - self.val += self.state.val - self.state.val = [] - return val def in_class(self, c, s): return s.find(c) >= 0 @@ -136,12 +89,6 @@ class Parser: def in_printable_class(self, c): return self.in_class(c, string.printable) - def set_error_stream(self, error): - self.error = error - - def has_error(self): - return self.err > 0 - def at_eof(self): return self.eof @@ -166,439 +113,131 @@ class Parser: self.char_no += 1 if self.state is None: - self.begin_start(None) + self.state = ParserState(self.state_start) + self.state.fn(c) def ready(self): - return len(self.val) > 0 + return len(self.start_state.val) > 0 def get_val(self): - v = self.val[0] - self.val = self.val[1:] + v = self.start_state.val[0] + self.start_state.val = self.start_state.val[1:] return v def get_all(self): - return self.val + return self.start_state.val - def begin_start(self, c): - self.state = ParserState(self.state_start) - - def end_start(self): - self.val += self.state.val - self.pop_state() - def state_start(self, c): - if self.at_eof(): - self.end_start() - elif self.in_space_class(c): + if self.at_eof() or self.in_space_class(c): pass elif self.in_comment_class(c): - self.begin_comment(c) - elif c == k_list_open: - self.begin_list(c) - elif c == k_list_close: + self.push_state(self.state_comment) + elif c == '(': + self.push_state(self.state_list) + elif c == ')': raise ParseError(self, "syntax error: "+c) elif self.in_string_quote_class(c): - self.begin_string(c) + self.push_state(self.state_string) + self.state.buf = c elif self.in_printable_class(c): - self.begin_atom(c) + self.push_state(self.state_atom) + self.state.buf = c elif c == chr(4): # ctrl-D, EOT: end-of-text. self.input_eof() else: raise ParseError(self, "invalid character: code %d" % ord(c)) - def begin_comment(self, c): - self.push_state(self.state_comment) - self.state.buf += c - - def end_comment(self): - self.pop_state() - def state_comment(self, c): if c == '\n' or self.at_eof(): - self.end_comment() - else: - self.state.buf += c + self.pop_state() - def begin_string(self, c): - self.push_state(self.state_string) - self.state.delim = c - - def end_string(self): - val = self.state.buf - self.state.parent.val.append(val) - self.pop_state() - def state_string(self, c): if self.at_eof(): raise ParseError(self, "unexpected EOF") - elif c == self.state.delim: - self.end_string() - elif c == '\\': - self.push_state(self.state_escape) - else: - self.state.buf += c - - def state_escape(self, c): - if self.at_eof(): - raise ParseError(self, "unexpected EOF") - d = escapes.get(c) - if d: - self.state.parent.buf += d + self.state.buf += c + # Look out for non-escaped end delimiter + if self.state.buf[0] == c and self.state.buf[-2] != '\\': + try: # parse escape sequences but fall back to something simple + val = eval(compile(self.state.buf,'','eval')) + except: + val = self.state.buf[1:-1] # just strip the delimiters + self.state.parent.val.append(val) self.pop_state() - elif c == 'x': - self.state.fn = self.state_hex - self.state.val = 0 - else: - self.state.fn = self.state_octal - self.state.val = 0 - self.input_char(c) - - def state_octal(self, c): - def octaldigit(c): - self.state.val *= 8 - self.state.val += ord(c) - ord('0') - self.state.buf += c - if self.state.val < 0 or self.state.val > 0xff: - raise ParseError(self, "invalid octal escape: out of range " + self.state.buf) - if len(self.state.buf) == 3: - octaldone() - - def octaldone(): - d = chr(self.state.val) - self.state.parent.buf += d - self.pop_state() - - if self.at_eof(): - raise ParseError(self, "unexpected EOF") - elif '0' <= c <= '7': - octaldigit(c) - elif len(self.buf): - octaldone() - self.input_char(c) - - def state_hex(self, c): - def hexdone(): - d = chr(self.state.val) - self.state.parent.buf += d - self.pop_state() - - def hexdigit(c, d): - self.state.val *= 16 - self.state.val += ord(c) - ord(d) - self.state.buf += c - if self.state.val < 0 or self.state.val > 0xff: - raise ParseError(self, "invalid hex escape: out of range " + self.state.buf) - if len(self.state.buf) == 2: - hexdone() - - if self.at_eof(): - raise ParseError(self, "unexpected EOF") - elif '0' <= c <= '9': - hexdigit(c, '0') - elif 'A' <= c <= 'F': - hexdigit(c, 'A') - elif 'a' <= c <= 'f': - hexdigit(c, 'a') - elif len(buf): - hexdone() - self.input_char(c) - - def begin_atom(self, c): - self.push_state(self.state_atom) - self.state.buf = c - - def end_atom(self): - val = self.state.buf - self.state.parent.val.append(val) - self.pop_state() def state_atom(self, c): - if self.at_eof(): - self.end_atom() - elif (self.is_separator(c) or - self.in_space_class(c) or - self.in_comment_class(c)): - self.end_atom() - self.input_char(c) + if (self.at_eof() or + self.is_separator(c) or + self.in_space_class(c) or + self.in_comment_class(c)): + val = self.state.buf + self.state.parent.val.append(val) + self.pop_state() + if not self.at_eof(): + self.input_char(c) else: self.state.buf += c - def begin_list(self, c): - self.push_state(self.state_list) - - def end_list(self): - val = self.state.val - self.state.parent.val.append(val) - self.pop_state() - def state_list(self, c): if self.at_eof(): raise ParseError(self, "unexpected EOF") - elif c == k_list_close: - self.end_list() + elif c == ')': + val = self.state.val + self.state.parent.val.append(val) + self.pop_state() else: self.state_start(c) -def atomp(sxpr): - """Check if an sxpr is an atom. - """ - if sxpr.isalnum() or sxpr == '@': - return 1 - for c in sxpr: - if c in string.whitespace: return 0 - if c in '"\'\\(){}[]<>$#&%^': return 0 - if c in string.ascii_letters: continue - if c in string.digits: continue - if c in '.-_:/~': continue - return 0 - return 1 - def show(sxpr, out=sys.stdout): """Print an sxpr in bracketed (lisp-style) syntax. """ if isinstance(sxpr, types.ListType): - out.write(k_list_open) - i = 0 + out.write('(') for x in sxpr: - if i: out.write(' ') show(x, out) - i += 1 - out.write(k_list_close) - elif isinstance(sxpr, types.StringType) and atomp(sxpr): - out.write(sxpr) + out.write(' ') + out.write(')') else: - #out.write("'" + str(sxpr) + "'") out.write(repr(str(sxpr))) -def show_xml(sxpr, out=sys.stdout): - """Print an sxpr in XML syntax. - """ - if isinstance(sxpr, types.ListType): - element = name(sxpr) - out.write('<%s' % element) - for attr in attributes(sxpr): - out.write(' %s=%s' % (attr[0], attr[1])) - out.write('>') - i = 0 - for x in children(sxpr): - if i: out.write(' ') - show_xml(x, out) - i += 1 - out.write('' % element) - elif isinstance(sxpr, types.StringType) and atomp(sxpr): - out.write(sxpr) - else: - out.write(str(sxpr)) - -def elementp(sxpr, elt=None): - """Check if an sxpr is an element of the given type. - - sxpr sxpr - elt element type - """ - return (isinstance(sxpr, types.ListType) - and len(sxpr) - and (None == elt or sxpr[0] == elt)) - def name(sxpr): - """Get the element name of an sxpr. - If the sxpr is not an element (i.e. it's an atomic value) its name - is None. - - sxpr - - returns name (None if not an element). + """Get the element name of an sxpr, or None if a bad sxpr. """ - val = None if isinstance(sxpr, types.StringType): - val = sxpr - elif isinstance(sxpr, types.ListType) and len(sxpr): - val = sxpr[0] - return val - -def attributes(sxpr): - """Get the attribute list of an sxpr. - - sxpr - - returns attribute list - """ - val = [] - if isinstance(sxpr, types.ListType) and len(sxpr) > 1: - attr = sxpr[1] - if elementp(attr, k_attr_open): - val = attr[1:] - return val - -def attribute(sxpr, key, val=None): - """Get an attribute of an sxpr. - - sxpr sxpr - key attribute key - val default value (default None) - - returns attribute value - """ - for x in attributes(sxpr): - if x[0] == key: - val = x[1] - break - return val + return sxpr + if isinstance(sxpr, types.ListType) and len(sxpr): + return sxpr[0] + return None def children(sxpr, elt=None): - """Get children of an sxpr. - - sxpr sxpr - elt optional element type to filter by - - returns children (filtered by elt if specified) + """Get children of an s-expression @sxpr, optionally filtered by + element type @elt. """ - val = [] - if isinstance(sxpr, types.ListType) and len(sxpr) > 1: - i = 1 - x = sxpr[i] - if elementp(x, k_attr_open): - i += 1 - val = sxpr[i : ] + if not isinstance(sxpr, types.ListType): return [] + val = filter(lambda x: isinstance(x, types.ListType) and len(x) > 0, sxpr) if elt: - def iselt(x): - return elementp(x, elt) - val = filter(iselt, val) + val = filter(lambda x,y=elt: x[0] == y, val) return val -def child(sxpr, elt, val=None): - """Get the first child of the given element type. - - sxpr sxpr - elt element type - val default value +def child(sxpr, elt=None, idx=0): + """Get the @idx'th child of the optional filtering type @elt in @sxpr. """ - for x in children(sxpr): - if elementp(x, elt): - val = x - break - return val + x = children(sxpr, elt) + if len(x) > idx: + return x[idx] + return None -def child_at(sxpr, index, val=None): - """Get the child at the given index (zero-based). - - sxpr sxpr - index index - val default value +def child_value(sxpr, elt=None): + """Get the value of the first child of @sxpr with the optional type @elt. """ - kids = children(sxpr) - if len(kids) > index: - val = kids[index] - return val - -def child0(sxpr, val=None): - """Get the zeroth child. - """ - return child_at(sxpr, 0, val) - -def child1(sxpr, val=None): - """Get the first child. - """ - return child_at(sxpr, 1, val) - -def child2(sxpr, val=None): - """Get the second child. - """ - return child_at(sxpr, 2, val) - -def child3(sxpr, val=None): - """Get the third child. - """ - return child_at(sxpr, 3, val) - -def child4(sxpr, val=None): - """Get the fourth child. - """ - return child_at(sxpr, 4, val) - -def child_value(sxpr, elt, val=None): - """Get the value of the first child of the given element type. - Assumes the child has an atomic value. - - sxpr sxpr - elt element type - val default value - """ - kid = child(sxpr, elt) - if kid: - val = child_at(kid, 0, val) - return val - -def has_id(sxpr, id): - """Test if an s-expression has a given id. - """ - return attribute(sxpr, 'id') == id - -def with_id(sxpr, id, val=None): - """Find the first s-expression with a given id, at any depth. - - sxpr s-exp or list - id id - val value if not found (default None) - - return s-exp or val - """ - if isinstance(sxpr, types.ListType): - for n in sxpr: - if has_id(n, id): - val = n - break - v = with_id(n, id) - if v is None: continue - val = v - break - return val - -def child_with_id(sxpr, id, val=None): - """Find the first child with a given id. - - sxpr s-exp or list - id id - val value if not found (default None) - - return s-exp or val - """ - if isinstance(sxpr, types.ListType): - for n in sxpr: - if has_id(n, id): - val = n - break - return val - -def elements(sxpr, ctxt=None): - """Generate elements (at any depth). - Visit elements in pre-order. - Values generated are (node, context) - The context is None if there is no parent, otherwise - (index, parent, context) where index is the node's index w.r.t its parent, - and context is the parent's context. - - sxpr s-exp - - returns generator - """ - yield (sxpr, ctxt) - i = 0 - for n in children(sxpr): - if isinstance(n, types.ListType): - # Calling elements() recursively does not generate recursively, - # it just returns a generator object. So we must iterate over it. - for v in elements(n, (i, sxpr, ctxt)): - yield v - i += 1 + x = child(sxpr, elt) + if not isinstance(x, types.ListType) or len(x) < 2: + return None + return x[1] def to_string(sxpr): - """Convert an sxpr to a string. - - sxpr sxpr - returns string + """Convert an s-expression @sxpr to a string. """ io = StringIO() show(sxpr, io) @@ -608,35 +247,14 @@ def to_string(sxpr): return val def from_string(str): - """Create an sxpr by parsing a string. - - str string - returns sxpr - """ - io = StringIO(str) - vals = parse(io) - if vals is []: - return None - else: - return vals[0] - - -def all_from_string(str): - """Create an sxpr list by parsing a string. - - str string - returns sxpr list + """Create an sxpr list from a given input string @str. """ io = StringIO(str) vals = parse(io) return vals def parse(io): - """Completely parse all input from 'io'. - - io input file object - returns list of values, None if incomplete - raises ParseError on parse error + """Completely parse all input from file @io. """ pin = Parser() while 1: @@ -649,19 +267,11 @@ def parse(io): else: val = None return val + - if __name__ == '__main__': - print ">main" pin = Parser() - while 1: - buf = sys.stdin.read(1024) - #buf = sys.stdin.readline() - pin.input(buf) - while pin.ready(): - val = pin.get_val() - print - print '****** val=', val - if len(buf) == 0: - break - + buf = sys.stdin.read(1024) + pin.input(buf) + while pin.ready(): + print '\n****** val=', pin.get_val() diff --git a/tools/python/xen/xm/main.py b/tools/python/xen/xm/main.py index 97a36f6711..9ae1fb67b8 100644 --- a/tools/python/xen/xm/main.py +++ b/tools/python/xen/xm/main.py @@ -246,11 +246,11 @@ class ProgList(Prog): info = server.xend_domain(dom) d = {} d['dom'] = int(dom) - d['name'] = sxp.child_value(info, 'name', '??') - d['mem'] = int(sxp.child_value(info, 'memory', '0')) - d['cpu'] = int(sxp.child_value(info, 'cpu', '0')) - d['state'] = sxp.child_value(info, 'state', '??') - d['cpu_time'] = float(sxp.child_value(info, 'cpu_time', '0')) + d['name'] = sxp.child_value(info, 'name') or '??' + d['mem'] = int(sxp.child_value(info, 'memory') or '-1') + d['cpu'] = int(sxp.child_value(info, 'cpu') or '-1') + d['state'] = sxp.child_value(info, 'state') or '??' + d['cpu_time'] = float(sxp.child_value(info, 'cpu_time') or '-1') print ("%(dom)-4d %(name)-16s %(mem)7d %(cpu)3d %(state)5s %(cpu_time)7.1f" % d) def long_list(self, doms): @@ -424,9 +424,9 @@ class ProgConsoles(Prog): for x in l: info = server.xend_console(x) d = {} - d['dom'] = sxp.child(info, 'dst', ['dst', '?', '?'])[1] - d['port'] = sxp.child_value(info, 'port', '?') - d['id'] = sxp.child_value(info, 'id', '?') + d['dom'] = (sxp.child(info, 'dst') or ['dst', '?', '?'])[1] + d['port'] = sxp.child_value(info, 'port') or '?' + d['id'] = sxp.child_value(info, 'id') or '?' print "%(dom)3s %(port)4s %(id)3s" % d xm.prog(ProgConsoles) From 8533ad9cf6d2c173059d90582469cb6c693524e6 Mon Sep 17 00:00:00 2001 From: "mjw@wray-m-3.hpl.hp.com" Date: Tue, 6 Jul 2004 15:21:43 +0000 Subject: [PATCH 26/36] bitkeeper revision 1.1041.9.1 (40eac387W39rUFRFKTwvCfPBOF7Aow) Convert most 'xm create' command-line switches to variables. --- tools/python/xen/util/ip.py | 53 +++++++++++++++----- tools/python/xen/xm/create.py | 69 ++++++++++++-------------- tools/python/xen/xm/opts.py | 93 ++++++++++++++++++++++++++++++----- 3 files changed, 155 insertions(+), 60 deletions(-) diff --git a/tools/python/xen/util/ip.py b/tools/python/xen/util/ip.py index 8396e0d014..39eb01f944 100644 --- a/tools/python/xen/util/ip.py +++ b/tools/python/xen/util/ip.py @@ -3,7 +3,7 @@ import re import socket import struct -def readlines(fd): +def _readlines(fd): """Version of readlines safe against EINTR. """ import errno @@ -21,7 +21,7 @@ def readlines(fd): lines.append(line) return lines -def readline(fd): +def _readline(fd): """Version of readline safe against EINTR. """ while 1: @@ -42,11 +42,14 @@ as it may have been moved onto the bridge. NBE_BRIDGE = 'nbe-br' def get_current_ipaddr(dev='eth0'): - """Return a string containing the primary IP address for the given - network interface (default 'eth0'). + """Get the primary IP address for the given network interface. + + dev network interface (default eth0) + + returns interface address as a string """ fd = os.popen( '/sbin/ifconfig ' + dev + ' 2>/dev/null' ) - lines = readlines(fd) + lines = _readlines(fd) for line in lines: m = re.search( '^\s+inet addr:([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+).*', line ) @@ -57,11 +60,14 @@ def get_current_ipaddr(dev='eth0'): return None def get_current_ipmask(dev='eth0'): - """Return a string containing the primary IP netmask for the given - network interface (default 'eth0'). + """Get the primary IP netmask for a network interface. + + dev network interface (default eth0) + + returns interface netmask as a string """ fd = os.popen( '/sbin/ifconfig ' + dev + ' 2>/dev/null' ) - lines = readlines(fd) + lines = _readlines(fd) for line in lines: m = re.search( '^.+Mask:([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+).*', line ) @@ -72,11 +78,14 @@ def get_current_ipmask(dev='eth0'): return None def get_current_ipgw(dev='eth0'): - """Return a string containing the IP gateway for the given - network interface (default 'eth0'). + """Get the IP gateway for a network interface. + + dev network interface (default eth0) + + returns gateway address as a string """ fd = os.popen( '/sbin/route -n' ) - lines = readlines(fd) + lines = _readlines(fd) for line in lines: m = re.search( '^\S+\s+([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)' + '\s+\S+\s+\S*G.*' + dev + '.*', line ) @@ -88,24 +97,46 @@ def get_current_ipgw(dev='eth0'): def inet_aton(addr): """Convert an IP addr in IPv4 dot notation into an int. + + addr IP address as a string + + returns integer """ b = socket.inet_aton(addr) return struct.unpack('!I', b)[0] def inet_ntoa(n): """Convert an int into an IP addr in IPv4 dot notation. + + n IP address + + returns string """ b = struct.pack('!I', n) return socket.inet_ntoa(b) def add_offset_to_ip(addr, offset): """Add a numerical offset to an IP addr in IPv4 dot notation. + + addr IP address + offset offset to add + + returns new address """ n = inet_aton(addr) n += offset return inet_ntoa(n) def check_subnet( ip, network, netmask ): + """Check if an IP address is in the subnet defined by + a network address and mask'. + + ip IP adress + network network address + netmask network mask + + returns 1 if it is in the subnet, 0 if not + """ n_ip = inet_aton(ip) n_net = inet_aton(network) n_mask = inet_aton(netmask) diff --git a/tools/python/xen/xm/create.py b/tools/python/xen/xm/create.py index 3c61db9325..cf82d075f9 100644 --- a/tools/python/xen/xm/create.py +++ b/tools/python/xen/xm/create.py @@ -13,7 +13,7 @@ from xen.util import console_client from xen.xm.opts import * -gopts = Opts(use="""[options] +gopts = Opts(use="""[options] [vars] Create a domain. @@ -66,54 +66,49 @@ gopts.opt('load', short='L', val='FILE', fn=set_value, default=None, use='Domain saved state to load.') -#gopts.opt('define', short='D', val='VAR=VAL', -# fn=set_var, default=None, -# use="""Set a variable before loading defaults, e.g. '-D vmid=3' -# to set vmid. May be repeated to set more than one variable.""") - gopts.opt('dryrun', short='n', fn=set_true, default=0, use="""Dry run - print the config but don't create the domain. The defaults file is loaded and the SXP configuration is created and printed. """) -gopts.opt('name', short='N', val='NAME', - fn=set_value, default=None, - use="Domain name.") - gopts.opt('console_autoconnect', short='c', fn=set_true, default=0, use="Connect to console after domain is created.") -gopts.opt('kernel', short='k', val='FILE', +gopts.var('name', val='NAME', + fn=set_value, default=None, + use="Domain name.") + +gopts.var('kernel', val='FILE', fn=set_value, default=None, use="Path to kernel image.") -gopts.opt('ramdisk', short='r', val='FILE', +gopts.var('ramdisk', val='FILE', fn=set_value, default='', use="Path to ramdisk.") -gopts.opt('builder', short='b', val='FUNCTION', +gopts.var('builder', val='FUNCTION', fn=set_value, default='linux', use="Function to use to build the domain.") -gopts.opt('memory', short='m', val='MEMORY', +gopts.var('memory', val='MEMORY', fn=set_value, default=128, use="Domain memory in MB.") -gopts.opt('autorestart', - fn=set_true, default=0, +gopts.var('autorestart', val='no|yes', + fn=set_bool, default=0, use="Whether to restart the domain on exit.") -gopts.opt('blkif', - fn=set_true, default=0, +gopts.var('blkif', val='no|yes', + fn=set_bool, default=0, use="Make the domain a block device backend.") -gopts.opt('netif', - fn=set_true, default=0, +gopts.var('netif', val='no|yes', + fn=set_bool, default=0, use="Make the domain a network interface backend.") -gopts.opt('disk', short='d', val='phy:DEV,VDEV,MODE', +gopts.var('disk', val='phy:DEV,VDEV,MODE', fn=append_value, default=[], use="""Add a disk device to a domain. The physical device is DEV, which is exported to the domain as VDEV. The disk is read-only if MODE @@ -121,18 +116,18 @@ gopts.opt('disk', short='d', val='phy:DEV,VDEV,MODE', The option may be repeated to add more than one disk. """) -gopts.opt('pci', val='BUS,DEV,FUNC', +gopts.var('pci', val='BUS,DEV,FUNC', fn=append_value, default=[], use="""Add a PCI device to a domain, using given params (in hex). For example '-pci c0,02,1a'. The option may be repeated to add more than one pci device. """) -gopts.opt('ipaddr', short='i', val="IPADDR", +gopts.var('ipaddr', val="IPADDR", fn=append_value, default=[], use="Add an IP address to the domain.") -gopts.opt('vif', val="mac=MAC,bridge=BRIDGE", +gopts.var('vif', val="mac=MAC,bridge=BRIDGE", fn=append_value, default=[], use="""Add a network interface with the given MAC address and bridge. If mac is not specified a random MAC address is used. @@ -141,7 +136,7 @@ gopts.opt('vif', val="mac=MAC,bridge=BRIDGE", Specifying vifs will increase the number of interfaces as needed. """) -gopts.opt('nics', val="NUM", +gopts.var('nics', val="NUM", fn=set_int, default=1, use="""Set the number of network interfaces. Use the vif option to define interface parameters, otherwise @@ -149,44 +144,44 @@ gopts.opt('nics', val="NUM", number of interfaces as needed. """) -gopts.opt('root', short='R', val='DEVICE', +gopts.var('root', val='DEVICE', fn=set_value, default='', use="""Set the root= parameter on the kernel command line. Use a device, e.g. /dev/sda1, or /dev/nfs for NFS root.""") -gopts.opt('extra', short='E', val="ARGS", +gopts.var('extra', val="ARGS", fn=set_value, default='', use="Set extra arguments to append to the kernel command line.") -gopts.opt('ip', short='I', val='IPADDR', +gopts.var('ip', val='IPADDR', fn=set_value, default='', use="Set the kernel IP interface address.") -gopts.opt('gateway', val="IPADDR", +gopts.var('gateway', val="IPADDR", fn=set_value, default='', use="Set the kernel IP gateway.") -gopts.opt('netmask', val="MASK", +gopts.var('netmask', val="MASK", fn=set_value, default = '', use="Set the kernel IP netmask.") -gopts.opt('hostname', val="NAME", +gopts.var('hostname', val="NAME", fn=set_value, default='', use="Set the kernel IP hostname.") -gopts.opt('interface', val="INTF", +gopts.var('interface', val="INTF", fn=set_value, default="eth0", use="Set the kernel IP interface name.") -gopts.opt('dhcp', val="off|dhcp", +gopts.var('dhcp', val="off|dhcp", fn=set_value, default='off', use="Set the kernel dhcp option.") -gopts.opt('nfs_server', val="IPADDR", +gopts.var('nfs_server', val="IPADDR", fn=set_value, default=None, use="Set the address of the NFS server for NFS root.") -gopts.opt('nfs_root', val="PATH", +gopts.var('nfs_root', val="PATH", fn=set_value, default=None, use="Set the path of the root NFS directory.") @@ -315,7 +310,7 @@ def preprocess_vifs(opts): d = {} a = vif.split(',') for b in a: - (k, v) = b.strip().split('=') + (k, v) = b.strip().split('=', 1) k = k.strip() v = v.strip() if k not in ['mac', 'bridge']: @@ -392,7 +387,7 @@ def main(argv): # Process remaining args as config variables. for arg in args: if '=' in arg: - (var, val) = arg.strip().split('=') + (var, val) = arg.strip().split('=', 1) gopts.setvar(var.strip(), val.strip()) if opts.vals.config: pass diff --git a/tools/python/xen/xm/opts.py b/tools/python/xen/xm/opts.py index 25f11abad2..4f963b5146 100644 --- a/tools/python/xen/xm/opts.py +++ b/tools/python/xen/xm/opts.py @@ -126,6 +126,42 @@ class Opt: """ return self.specified_opt +class OptVar(Opt): + """An individual option variable. + """ + def __init__(self, opts, name, + val=None, fn=None, use=None, default=None): + """Create an option. + + opts parent options object + name name of the field it controls + val string used to print option args in help. + If val is not specified the option has no arg. + fn function to call when the option is specified. + use usage (help) string + default default value if not specified on command-line + """ + if val is None: + val = name.upper() + Opt.__init__(self, opts, name, val=val, fn=fn, use=use, default=default) + self.optkeys = [] + self.optkeys.append(self.long) + + def short_opt(self): + return None + + def long_opt(self): + return None + + def show(self): + print '%s=%s' %(self.optkeys[0], self.val) + print + if self.use: + print '\t', + print self.use + if self.val: + print '\tDefault', self.default or 'None' + class OptVals: """Class to hold option values. """ @@ -134,6 +170,13 @@ class OptVals: class Opts: """Container for options. """ + + imports = ["import sys", + "import os", + "import os.path", + "from xen.util.ip import *", + ] + def __init__(self, use=None): """Options constructor. @@ -168,6 +211,12 @@ class Opts: self.options_map[name] = x return x + def var(self, name, **args): + x = OptVar(self, name, **args) + self.options.append(x) + self.options_map[name] = x + return x + def setvar(self, var, val): """Set a default script variable. """ @@ -232,7 +281,14 @@ class Opts: else: print >>sys.stderr, "Error: Unknown option:", k self.usage() - return args + xargs = [] + for arg in args: + (k, v) = arg.split('=', 1) + for opt in self.options: + if opt.specify(k, v): break + else: + xargs.append(arg) + return xargs def short_opts(self): """Get short options specifier for getopt. @@ -257,6 +313,7 @@ class Opts: def usage(self): print 'Usage: ', self.argv[0], self.use or 'OPTIONS' for opt in self.options: + print opt.show() def load_defaults(self, help=0): @@ -287,21 +344,22 @@ class Opts: globals = {} locals = {} locals.update(self.vars) - cmd = '\n'.join(["import sys", - "import os", - "import os.path", - "from xen.xm.help import Vars", - "from xen.util import ip", - "xm_file = '%s'" % defaults, - "xm_help = %d" % help, - "xm_vars = Vars(xm_file, xm_help, locals())", - ]) + cmd = '\n'.join(self.imports + + [ "from xen.xm.help import Vars", + "xm_file = '%s'" % defaults, + "xm_help = %d" % help, + "xm_vars = Vars(xm_file, xm_help, locals())" + ]) exec cmd in globals, locals try: execfile(defaults, globals, locals) except: if not help: raise - if help: return + if help: + print 'The following imports are done automatically:' + for x in self.imports: + print x + return # Extract the values set by the script and set the corresponding # options, if not set on the command line. vtypes = [ types.StringType, @@ -322,6 +380,17 @@ def set_false(opt, k, v): """Set an option false.""" opt.set(0) +def set_bool(opt, k, v): + """Set a boolean option. + """ + if v in ['yes']: + opt.set(1) + elif v in ['no']: + opt.set(0) + else: + opt.opts.err('Invalid value:' +v) + + def set_value(opt, k, v): """Set an option to a valoue.""" opt.set(v) @@ -341,6 +410,6 @@ def append_value(opt, k, v): def set_var(opt, k, v): """Set a default script variable. """ - (var, val) = v.strip().split('=') + (var, val) = v.strip().split('=', 1) opt.opts.setvar(var.strip(), val.strip()) From 6cff3d537c107f4b1acfd3b3f033aeb8e45947b5 Mon Sep 17 00:00:00 2001 From: "mjw@wray-m-3.hpl.hp.com" Date: Tue, 6 Jul 2004 15:31:35 +0000 Subject: [PATCH 27/36] bitkeeper revision 1.1041.9.2 (40eac5d7QK5-_Ap_TCZ0_9b3ykFACA) Fix for args that aren't variable assigns. --- tools/python/xen/xm/opts.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/tools/python/xen/xm/opts.py b/tools/python/xen/xm/opts.py index 4f963b5146..325698875d 100644 --- a/tools/python/xen/xm/opts.py +++ b/tools/python/xen/xm/opts.py @@ -283,10 +283,14 @@ class Opts: self.usage() xargs = [] for arg in args: - (k, v) = arg.split('=', 1) - for opt in self.options: - if opt.specify(k, v): break - else: + isvar = 0 + if '=' in arg: + (k, v) = arg.split('=', 1) + for opt in self.options: + if opt.specify(k, v): + isvar = 1 + break + if not isvar: xargs.append(arg) return xargs From 6680e51038f158001cdf189d8c1900a21afac86f Mon Sep 17 00:00:00 2001 From: "kaf24@scramble.cl.cam.ac.uk" Date: Tue, 6 Jul 2004 16:04:47 +0000 Subject: [PATCH 28/36] bitkeeper revision 1.1041.5.11 (40eacd9fZF8vOabxL_0gJXpgUypPQw) Fix free_irq() calls to pass the correct dev_id. --- .../arch/xen/drivers/blkif/backend/common.h | 4 ++-- .../arch/xen/drivers/blkif/backend/interface.c | 2 +- .../arch/xen/drivers/blkif/frontend/main.c | 2 +- .../arch/xen/drivers/netif/backend/interface.c | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/linux-2.4.26-xen-sparse/arch/xen/drivers/blkif/backend/common.h b/linux-2.4.26-xen-sparse/arch/xen/drivers/blkif/backend/common.h index daf09a76f9..98986cffb8 100644 --- a/linux-2.4.26-xen-sparse/arch/xen/drivers/blkif/backend/common.h +++ b/linux-2.4.26-xen-sparse/arch/xen/drivers/blkif/backend/common.h @@ -15,11 +15,11 @@ #include #include "../blkif.h" -#if 0 +#if 1 #define ASSERT(_p) \ if ( !(_p) ) { printk("Assertion '%s' failed, line %d, file %s", #_p , \ __LINE__, __FILE__); *(int*)0=0; } -#define DPRINTK(_f, _a...) printk("(file=%s, line=%d) " _f, \ +#define DPRINTK(_f, _a...) printk(KERN_ALERT "(file=%s, line=%d) " _f, \ __FILE__ , __LINE__ , ## _a ) #else #define ASSERT(_p) ((void)0) diff --git a/linux-2.4.26-xen-sparse/arch/xen/drivers/blkif/backend/interface.c b/linux-2.4.26-xen-sparse/arch/xen/drivers/blkif/backend/interface.c index 780d793c6c..16b37164ab 100644 --- a/linux-2.4.26-xen-sparse/arch/xen/drivers/blkif/backend/interface.c +++ b/linux-2.4.26-xen-sparse/arch/xen/drivers/blkif/backend/interface.c @@ -217,7 +217,7 @@ int blkif_disconnect(blkif_be_disconnect_t *disconnect, u8 rsp_id) blkif->status = DISCONNECTING; blkif->disconnect_rspid = rsp_id; wmb(); /* Let other CPUs see the status change. */ - free_irq(blkif->irq, NULL); + free_irq(blkif->irq, blkif); blkif_deschedule(blkif); blkif_put(blkif); } diff --git a/linux-2.4.26-xen-sparse/arch/xen/drivers/blkif/frontend/main.c b/linux-2.4.26-xen-sparse/arch/xen/drivers/blkif/frontend/main.c index fa662496ec..1216600eff 100644 --- a/linux-2.4.26-xen-sparse/arch/xen/drivers/blkif/frontend/main.c +++ b/linux-2.4.26-xen-sparse/arch/xen/drivers/blkif/frontend/main.c @@ -616,7 +616,7 @@ static void blkif_status_change(blkif_fe_interface_status_changed_t *status) printk(KERN_INFO "VBD driver recovery in progress\n"); - /* Prevent new requests being issued until we've fixed things up. */ + /* Prevent new requests being issued until we fix things up. */ spin_lock_irq(&io_request_lock); recovery = 1; blkif_state = BLKIF_STATE_DISCONNECTED; diff --git a/linux-2.4.26-xen-sparse/arch/xen/drivers/netif/backend/interface.c b/linux-2.4.26-xen-sparse/arch/xen/drivers/netif/backend/interface.c index 2c4b74e1ea..ff3bc7bbf7 100644 --- a/linux-2.4.26-xen-sparse/arch/xen/drivers/netif/backend/interface.c +++ b/linux-2.4.26-xen-sparse/arch/xen/drivers/netif/backend/interface.c @@ -266,7 +266,7 @@ int netif_disconnect(netif_be_disconnect_t *disconnect, u8 rsp_id) netif->disconnect_rspid = rsp_id; wmb(); /* Let other CPUs see the status change. */ netif_stop_queue(netif->dev); - free_irq(netif->irq, NULL); + free_irq(netif->irq, netif); netif_deschedule(netif); netif_put(netif); } From 00df0da60e3bac697115278971c2e12d66646c3f Mon Sep 17 00:00:00 2001 From: "kaf24@scramble.cl.cam.ac.uk" Date: Tue, 6 Jul 2004 16:05:41 +0000 Subject: [PATCH 29/36] bitkeeper revision 1.1041.5.12 (40eacdd5K6HHt1PnK9g1obh8UFDx7w) Quieten debugging. --- linux-2.4.26-xen-sparse/arch/xen/drivers/blkif/backend/common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-2.4.26-xen-sparse/arch/xen/drivers/blkif/backend/common.h b/linux-2.4.26-xen-sparse/arch/xen/drivers/blkif/backend/common.h index 98986cffb8..a9f2b87844 100644 --- a/linux-2.4.26-xen-sparse/arch/xen/drivers/blkif/backend/common.h +++ b/linux-2.4.26-xen-sparse/arch/xen/drivers/blkif/backend/common.h @@ -15,7 +15,7 @@ #include #include "../blkif.h" -#if 1 +#if 0 #define ASSERT(_p) \ if ( !(_p) ) { printk("Assertion '%s' failed, line %d, file %s", #_p , \ __LINE__, __FILE__); *(int*)0=0; } From ac302eda479394e1731e572427d2e409f0d0cb29 Mon Sep 17 00:00:00 2001 From: "djm@kirby.fc.hp.com" Date: Tue, 6 Jul 2004 17:25:40 +0000 Subject: [PATCH 30/36] bitkeeper revision 1.1041.1.12 (40eae094p4Hi_HGiXIC_gBESK2nm0g) Move most of DOM0_GETDOMAININFO back to common, leaving just getting the context in machdep code. --- xen/arch/x86/dom0_ops.c | 173 ++++++++++++---------------------------- xen/common/dom0_ops.c | 76 ++++++++++++++++++ 2 files changed, 128 insertions(+), 121 deletions(-) diff --git a/xen/arch/x86/dom0_ops.c b/xen/arch/x86/dom0_ops.c index 1ec26d583d..4ee83fb6ad 100644 --- a/xen/arch/x86/dom0_ops.c +++ b/xen/arch/x86/dom0_ops.c @@ -79,127 +79,6 @@ long arch_do_dom0_op(dom0_op_t *op, dom0_op_t *u_dom0_op) } break; - case DOM0_GETDOMAININFO: - { - full_execution_context_t *c; - struct domain *d; - unsigned long flags; - int i; - - read_lock_irqsave(&tasklist_lock, flags); - - for_each_domain ( d ) - { - if ( d->domain >= op->u.getdomaininfo.domain ) - break; - } - - if ( (d == NULL) || !get_domain(d) ) - { - read_unlock_irqrestore(&tasklist_lock, flags); - ret = -ESRCH; - break; - } - - read_unlock_irqrestore(&tasklist_lock, flags); - - op->u.getdomaininfo.domain = d->domain; - strcpy(op->u.getdomaininfo.name, d->name); - - op->u.getdomaininfo.flags = - (test_bit(DF_DYING, &d->flags) ? DOMFLAGS_DYING : 0) | - (test_bit(DF_CRASHED, &d->flags) ? DOMFLAGS_CRASHED : 0) | - (test_bit(DF_SHUTDOWN, &d->flags) ? DOMFLAGS_SHUTDOWN : 0) | - (test_bit(DF_CTRLPAUSE, &d->flags) ? DOMFLAGS_PAUSED : 0) | - (test_bit(DF_BLOCKED, &d->flags) ? DOMFLAGS_BLOCKED : 0) | - (test_bit(DF_RUNNING, &d->flags) ? DOMFLAGS_RUNNING : 0); - - op->u.getdomaininfo.flags |= d->processor << DOMFLAGS_CPUSHIFT; - op->u.getdomaininfo.flags |= - d->shutdown_code << DOMFLAGS_SHUTDOWNSHIFT; - - op->u.getdomaininfo.tot_pages = d->tot_pages; - op->u.getdomaininfo.max_pages = d->max_pages; - op->u.getdomaininfo.cpu_time = d->cpu_time; - op->u.getdomaininfo.shared_info_frame = - __pa(d->shared_info) >> PAGE_SHIFT; - - if ( op->u.getdomaininfo.ctxt != NULL ) - { - if ( (c = kmalloc(sizeof(*c))) == NULL ) - { - ret = -ENOMEM; - put_domain(d); - break; - } - - if ( d != current ) - domain_pause(d); - - c->flags = 0; - memcpy(&c->cpu_ctxt, - &d->shared_info->execution_context, - sizeof(d->shared_info->execution_context)); - if ( test_bit(DF_DONEFPUINIT, &d->flags) ) - c->flags |= ECF_I387_VALID; - memcpy(&c->fpu_ctxt, - &d->thread.i387, - sizeof(d->thread.i387)); - memcpy(&c->trap_ctxt, - d->thread.traps, - sizeof(d->thread.traps)); -#ifdef ARCH_HAS_FAST_TRAP - if ( (d->thread.fast_trap_desc.a == 0) && - (d->thread.fast_trap_desc.b == 0) ) - c->fast_trap_idx = 0; - else - c->fast_trap_idx = - d->thread.fast_trap_idx; -#endif - c->ldt_base = d->mm.ldt_base; - c->ldt_ents = d->mm.ldt_ents; - c->gdt_ents = 0; - if ( GET_GDT_ADDRESS(d) == GDT_VIRT_START ) - { - for ( i = 0; i < 16; i++ ) - c->gdt_frames[i] = - l1_pgentry_to_pagenr(d->mm.perdomain_pt[i]); - c->gdt_ents = - (GET_GDT_ENTRIES(d) + 1) >> 3; - } - c->guestos_ss = d->thread.guestos_ss; - c->guestos_esp = d->thread.guestos_sp; - c->pt_base = - pagetable_val(d->mm.pagetable); - memcpy(c->debugreg, - d->thread.debugreg, - sizeof(d->thread.debugreg)); - c->event_callback_cs = - d->event_selector; - c->event_callback_eip = - d->event_address; - c->failsafe_callback_cs = - d->failsafe_selector; - c->failsafe_callback_eip = - d->failsafe_address; - - if ( d != current ) - domain_unpause(d); - - if ( copy_to_user(op->u.getdomaininfo.ctxt, c, sizeof(*c)) ) - ret = -EINVAL; - - if ( c != NULL ) - kfree(c); - } - - if ( copy_to_user(u_dom0_op, op, sizeof(*op)) ) - ret = -EINVAL; - - put_domain(d); - } - break; - case DOM0_SHADOW_CONTROL: { struct domain *d; @@ -221,3 +100,55 @@ long arch_do_dom0_op(dom0_op_t *op, dom0_op_t *u_dom0_op) return ret; } + +void arch_getdomaininfo_ctxt(struct domain *d, full_execution_context_t *c) +{ + int i; + + c->flags = 0; + memcpy(&c->cpu_ctxt, + &d->shared_info->execution_context, + sizeof(d->shared_info->execution_context)); + if ( test_bit(DF_DONEFPUINIT, &d->flags) ) + c->flags |= ECF_I387_VALID; + memcpy(&c->fpu_ctxt, + &d->thread.i387, + sizeof(d->thread.i387)); + memcpy(&c->trap_ctxt, + d->thread.traps, + sizeof(d->thread.traps)); +#ifdef ARCH_HAS_FAST_TRAP + if ( (d->thread.fast_trap_desc.a == 0) && + (d->thread.fast_trap_desc.b == 0) ) + c->fast_trap_idx = 0; + else + c->fast_trap_idx = + d->thread.fast_trap_idx; +#endif + c->ldt_base = d->mm.ldt_base; + c->ldt_ents = d->mm.ldt_ents; + c->gdt_ents = 0; + if ( GET_GDT_ADDRESS(d) == GDT_VIRT_START ) + { + for ( i = 0; i < 16; i++ ) + c->gdt_frames[i] = + l1_pgentry_to_pagenr(d->mm.perdomain_pt[i]); + c->gdt_ents = + (GET_GDT_ENTRIES(d) + 1) >> 3; + } + c->guestos_ss = d->thread.guestos_ss; + c->guestos_esp = d->thread.guestos_sp; + c->pt_base = + pagetable_val(d->mm.pagetable); + memcpy(c->debugreg, + d->thread.debugreg, + sizeof(d->thread.debugreg)); + c->event_callback_cs = + d->event_selector; + c->event_callback_eip = + d->event_address; + c->failsafe_callback_cs = + d->failsafe_selector; + c->failsafe_callback_eip = + d->failsafe_address; +} diff --git a/xen/common/dom0_ops.c b/xen/common/dom0_ops.c index 28b2671e5f..fcec8991b2 100644 --- a/xen/common/dom0_ops.c +++ b/xen/common/dom0_ops.c @@ -25,6 +25,7 @@ extern unsigned int alloc_new_dom_mem(struct domain *, unsigned int); extern long arch_do_dom0_op(dom0_op_t *op, dom0_op_t *u_dom0_op); +extern void arch_getdomaininfo_ctxt(struct domain *, full_execution_context_t *); long do_dom0_op(dom0_op_t *u_dom0_op) { @@ -254,6 +255,81 @@ long do_dom0_op(dom0_op_t *u_dom0_op) } break; + case DOM0_GETDOMAININFO: + { + full_execution_context_t *c; + struct domain *d; + unsigned long flags; + + read_lock_irqsave(&tasklist_lock, flags); + + for_each_domain ( d ) + { + if ( d->domain >= op->u.getdomaininfo.domain ) + break; + } + + if ( (d == NULL) || !get_domain(d) ) + { + read_unlock_irqrestore(&tasklist_lock, flags); + ret = -ESRCH; + break; + } + + read_unlock_irqrestore(&tasklist_lock, flags); + + op->u.getdomaininfo.domain = d->domain; + strcpy(op->u.getdomaininfo.name, d->name); + + op->u.getdomaininfo.flags = + (test_bit(DF_DYING, &d->flags) ? DOMFLAGS_DYING : 0) | + (test_bit(DF_CRASHED, &d->flags) ? DOMFLAGS_CRASHED : 0) | + (test_bit(DF_SHUTDOWN, &d->flags) ? DOMFLAGS_SHUTDOWN : 0) | + (test_bit(DF_CTRLPAUSE, &d->flags) ? DOMFLAGS_PAUSED : 0) | + (test_bit(DF_BLOCKED, &d->flags) ? DOMFLAGS_BLOCKED : 0) | + (test_bit(DF_RUNNING, &d->flags) ? DOMFLAGS_RUNNING : 0); + + op->u.getdomaininfo.flags |= d->processor << DOMFLAGS_CPUSHIFT; + op->u.getdomaininfo.flags |= + d->shutdown_code << DOMFLAGS_SHUTDOWNSHIFT; + + op->u.getdomaininfo.tot_pages = d->tot_pages; + op->u.getdomaininfo.max_pages = d->max_pages; + op->u.getdomaininfo.cpu_time = d->cpu_time; + op->u.getdomaininfo.shared_info_frame = + __pa(d->shared_info) >> PAGE_SHIFT; + + if ( op->u.getdomaininfo.ctxt != NULL ) + { + if ( (c = kmalloc(sizeof(*c))) == NULL ) + { + ret = -ENOMEM; + put_domain(d); + break; + } + + if ( d != current ) + domain_pause(d); + + arch_getdomaininfo_ctxt(d,c); + + if ( d != current ) + domain_unpause(d); + + if ( copy_to_user(op->u.getdomaininfo.ctxt, c, sizeof(*c)) ) + ret = -EINVAL; + + if ( c != NULL ) + kfree(c); + } + + if ( copy_to_user(u_dom0_op, op, sizeof(*op)) ) + ret = -EINVAL; + + put_domain(d); + } + break; + case DOM0_GETPAGEFRAMEINFO: { struct pfn_info *page; From 3d00a30898614995a3bf68af8efef538a98fe335 Mon Sep 17 00:00:00 2001 From: "kaf24@scramble.cl.cam.ac.uk" Date: Tue, 6 Jul 2004 18:02:59 +0000 Subject: [PATCH 31/36] bitkeeper revision 1.1041.5.13 (40eae953qXVB0VAXac-t2uDXq-tS9Q) Tidy up remote shutdown handling in xenolinux. --- .../arch/xen/kernel/setup.c | 88 +++++++++++++++---- 1 file changed, 72 insertions(+), 16 deletions(-) diff --git a/linux-2.4.26-xen-sparse/arch/xen/kernel/setup.c b/linux-2.4.26-xen-sparse/arch/xen/kernel/setup.c index b329632b78..42ef543546 100644 --- a/linux-2.4.26-xen-sparse/arch/xen/kernel/setup.c +++ b/linux-2.4.26-xen-sparse/arch/xen/kernel/setup.c @@ -8,6 +8,8 @@ * This file handles the architecture-dependent parts of initialization */ +#define __KERNEL_SYSCALLS__ +static int errno; #include #include #include @@ -30,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -1148,10 +1151,10 @@ void __init cpu_init (void) #include -/* Treat multiple suspend requests as a single one. */ -static int suspending; +/* Ignore multiple shutdown requests. */ +static int shutting_down = -1; -static void suspend_task(void *unused) +static void __do_suspend(void) { /* Hmmm... a cleaner interface to suspend/resume blkdevs would be nice. */ extern void blkdev_suspend(void); @@ -1220,7 +1223,7 @@ static void suspend_task(void *unused) HYPERVISOR_suspend(virt_to_machine(suspend_record) >> PAGE_SHIFT); - suspending = 0; + shutting_down = -1; memcpy(&start_info, &suspend_record->resume_info, sizeof(start_info)); @@ -1272,25 +1275,78 @@ static void suspend_task(void *unused) free_page((unsigned long)suspend_record); } -static struct tq_struct suspend_tq; - -static void shutdown_handler(ctrl_msg_t *msg, unsigned long id) +static int shutdown_process(void *__unused) { - if ( msg->subtype != CMSG_SHUTDOWN_SUSPEND ) + static char *envp[] = { "HOME=/", "TERM=linux", + "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL }; + static char *restart_argv[] = { "/sbin/shutdown", "-r", "now", NULL }; + static char *poweroff_argv[] = { "/sbin/halt", "-p", NULL }; + + extern asmlinkage long sys_reboot(int magic1, int magic2, + unsigned int cmd, void *arg); + + daemonize(); + + switch ( shutting_down ) { - extern void ctrl_alt_del(void); - ctrl_if_send_response(msg); - ctrl_alt_del(); + case CMSG_SHUTDOWN_POWEROFF: + if ( execve("/sbin/halt", poweroff_argv, envp) < 0 ) + { + sys_reboot(LINUX_REBOOT_MAGIC1, + LINUX_REBOOT_MAGIC2, + LINUX_REBOOT_CMD_POWER_OFF, + NULL); + } + break; + + case CMSG_SHUTDOWN_REBOOT: + if ( execve("/sbin/shutdown", restart_argv, envp) < 0 ) + { + sys_reboot(LINUX_REBOOT_MAGIC1, + LINUX_REBOOT_MAGIC2, + LINUX_REBOOT_CMD_RESTART, + NULL); + } + break; } - else if ( !suspending ) + + return 0; +} + +static void __shutdown_handler(void *unused) +{ + int err; + + if ( shutting_down != CMSG_SHUTDOWN_SUSPEND ) { - suspending = 1; - suspend_tq.routine = suspend_task; - schedule_task(&suspend_tq); + err = kernel_thread(shutdown_process, NULL, CLONE_FS | CLONE_FILES); + if ( err < 0 ) + printk(KERN_ALERT "Error creating shutdown process!\n"); + else + shutting_down = -1; /* could try again */ } else { - printk(KERN_ALERT"Ignore queued suspend request\n"); + __do_suspend(); + } +} + +static void shutdown_handler(ctrl_msg_t *msg, unsigned long id) +{ + static struct tq_struct shutdown_tq; + + if ( (shutting_down == -1) && + ((msg->subtype == CMSG_SHUTDOWN_POWEROFF) || + (msg->subtype == CMSG_SHUTDOWN_REBOOT) || + (msg->subtype == CMSG_SHUTDOWN_SUSPEND)) ) + { + shutting_down = msg->subtype; + shutdown_tq.routine = __shutdown_handler; + schedule_task(&shutdown_tq); + } + else + { + printk("Ignore spurious shutdown request\n"); } ctrl_if_send_response(msg); From 61e74858f89e89012d97acb590cfe8e5859fb58b Mon Sep 17 00:00:00 2001 From: "djm@kirby.fc.hp.com" Date: Tue, 6 Jul 2004 18:49:28 +0000 Subject: [PATCH 32/36] bitkeeper revision 1.1041.1.14 (40eaf438sciOdZWe5QAqcjLLtbzF2Q) Minor PCI tweaks to move ever so slightly toward 2.6 and make ia64 (based on 2.6) easier. --- xen/drivers/pci/pci.c | 4 ++-- xen/include/asm-x86/pci.h | 2 +- xen/include/xen/pci.h | 4 ++++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/xen/drivers/pci/pci.c b/xen/drivers/pci/pci.c index 258d9d8c8a..f8697d1337 100644 --- a/xen/drivers/pci/pci.c +++ b/xen/drivers/pci/pci.c @@ -890,7 +890,7 @@ pci_set_mwi(struct pci_dev *dev) u16 cmd; #ifdef HAVE_ARCH_PCI_MWI - rc = pcibios_set_mwi(dev); + rc = pcibios_prep_mwi(dev); #else rc = pci_generic_prep_mwi(dev); #endif @@ -1384,7 +1384,7 @@ struct pci_dev * __devinit pci_scan_slot(struct pci_dev *temp) temp->hdr_type = hdr_type & 0x7f; dev = pci_scan_device(temp); - if (!pcibios_scan_all_fns() && func == 0) { + if (!pcibios_scan_all_fns(0,0) && func == 0) { if (!dev) break; } else { diff --git a/xen/include/asm-x86/pci.h b/xen/include/asm-x86/pci.h index 1a217315a4..c5f72c0fae 100644 --- a/xen/include/asm-x86/pci.h +++ b/xen/include/asm-x86/pci.h @@ -12,7 +12,7 @@ extern unsigned int pcibios_assign_all_busses(void); #else #define pcibios_assign_all_busses() 0 #endif -#define pcibios_scan_all_fns() 0 +#define pcibios_scan_all_fns(a,b) 0 extern unsigned long pci_mem_start; #define PCIBIOS_MIN_IO 0x1000 diff --git a/xen/include/xen/pci.h b/xen/include/xen/pci.h index f4d9d72f9c..90fce051b1 100644 --- a/xen/include/xen/pci.h +++ b/xen/include/xen/pci.h @@ -393,6 +393,10 @@ struct pci_dev { this is D0-D3, D0 being fully functional, and D3 being off. */ +#ifdef LINUX_2_6 + struct device dev; /* Generic device interface */ +#endif + /* device is compatible with these IDs */ unsigned short vendor_compatible[DEVICE_COUNT_COMPATIBLE]; unsigned short device_compatible[DEVICE_COUNT_COMPATIBLE]; From 26bee389365f359b5f2fca829db57f9ec829f467 Mon Sep 17 00:00:00 2001 From: "djm@kirby.fc.hp.com" Date: Tue, 6 Jul 2004 19:33:41 +0000 Subject: [PATCH 33/36] bitkeeper revision 1.1041.1.16 (40eafe95g-dX5S31rejiqR_01dEwUQ) Minor ACPI tweaks to move ever so slightly toward 2.6 and make ia64 (based on 2.6) easier. --- xen/include/acpi/acpi_bus.h | 2 -- xen/include/asm-x86/acpi.h | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/xen/include/acpi/acpi_bus.h b/xen/include/acpi/acpi_bus.h index 50eaf61c0a..4326bc934b 100644 --- a/xen/include/acpi/acpi_bus.h +++ b/xen/include/acpi/acpi_bus.h @@ -36,8 +36,6 @@ #include -extern int acpi_disabled; - /* TBD: Make dynamic */ #define ACPI_MAX_HANDLES 10 struct acpi_handle_list { diff --git a/xen/include/asm-x86/acpi.h b/xen/include/asm-x86/acpi.h index 35d45f4151..be7d6dfda7 100644 --- a/xen/include/asm-x86/acpi.h +++ b/xen/include/asm-x86/acpi.h @@ -108,6 +108,7 @@ extern int acpi_lapic; extern int acpi_ioapic; extern int acpi_noirq; +extern int acpi_disabled; /* Fixmap pages to reserve for ACPI boot-time tables (see fixmap.h) */ #define FIX_ACPI_PAGES 4 From b3b277c5661447ae1fc94ec5b8169674c645191e Mon Sep 17 00:00:00 2001 From: "djm@kirby.fc.hp.com" Date: Tue, 6 Jul 2004 20:28:23 +0000 Subject: [PATCH 34/36] bitkeeper revision 1.1041.1.17 (40eb0b673jnCW3n1yVuLT8OFnMJm-Q) Minor slab tweaks to move ever so slightly toward 2.6 and make ia64 (based on 2.6) easier. (NOTE! kmem_bufctl_t is now a short per 2.6!) --- xen/common/slab.c | 6 +++--- xen/include/asm-x86/types.h | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/xen/common/slab.c b/xen/common/slab.c index 2266baa9af..ab97bc5c33 100644 --- a/xen/common/slab.c +++ b/xen/common/slab.c @@ -117,9 +117,9 @@ * is less than 512 (PAGE_SIZE<<3), but greater than 256. */ -#define BUFCTL_END 0xffffFFFF -#define SLAB_LIMIT 0xffffFFFE -typedef unsigned int kmem_bufctl_t; +#define BUFCTL_END (((kmem_bufctl_t)(~0U))-0) +#define BUFCTL_FREE (((kmem_bufctl_t)(~0U))-1) +#define SLAB_LIMIT (((kmem_bufctl_t)(~0U))-2) /* Max number of objs-per-slab for caches which use off-slab slabs. * Needed to avoid a possible looping condition in kmem_cache_grow(). diff --git a/xen/include/asm-x86/types.h b/xen/include/asm-x86/types.h index e2b229edcf..3f1f0a6c6a 100644 --- a/xen/include/asm-x86/types.h +++ b/xen/include/asm-x86/types.h @@ -56,4 +56,6 @@ typedef unsigned long size_t; typedef unsigned long dma_addr_t; typedef u64 dma64_addr_t; +typedef unsigned short kmem_bufctl_t; + #endif From 6f545013b5146fb8e1a90289d771ecfca9509113 Mon Sep 17 00:00:00 2001 From: "kaf24@scramble.cl.cam.ac.uk" Date: Wed, 7 Jul 2004 09:58:27 +0000 Subject: [PATCH 35/36] bitkeeper revision 1.1041.15.1 (40ebc943G6NlOlbW-3EGaR3sQs14kQ) Revert 1.1051.4.1 (s-expression parser changes). --- tools/python/xen/xend/XendDomainInfo.py | 27 +- tools/python/xen/xend/XendRoot.py | 2 +- tools/python/xen/xend/sxp.py | 552 ++++++++++++++++++++---- tools/python/xen/xm/main.py | 16 +- 4 files changed, 492 insertions(+), 105 deletions(-) diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index 377e7bb61b..619d575466 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -292,9 +292,6 @@ def vm_restore(src, progress=0): if dom < 0: raise VmError('restore failed') vmconfig = sxp.from_string(d['vmconfig']) - if not vmconfig: - raise VmError('bad vmconfig s-expression') - vmconfig = vmconfig[0] vm.config = sxp.child_value(vmconfig, 'config') deferred = vm.dom_configure(dom) def vifs_cb(val, vm): @@ -423,8 +420,8 @@ class XendDomainInfo: self.config = config try: self.name = sxp.child_value(config, 'name') - self.memory = int(sxp.child_value(config, 'memory') or '128') - if sxp.child(config, 'autorestart'): + self.memory = int(sxp.child_value(config, 'memory', '128')) + if sxp.child(config, 'autorestart', None): self.autorestart = 1 self.configure_backends() image = sxp.child_value(config, 'image') @@ -457,7 +454,7 @@ class XendDomainInfo: """ devices = [] for d in sxp.children(self.config, 'device'): - dev = sxp.child(d) + dev = sxp.child0(d) if dev is None: continue if name == sxp.name(dev): devices.append(dev) @@ -588,7 +585,7 @@ class XendDomainInfo: if self.recreate: return memory = self.memory name = self.name - cpu = int(sxp.child_value(self.config, 'cpu') or '-1') + cpu = int(sxp.child_value(self.config, 'cpu', '-1')) print 'init_domain>', memory, name, cpu dom = xc.domain_create(mem_kb= memory * 1024, name= name, cpu= cpu) if dom <= 0: @@ -653,7 +650,7 @@ class XendDomainInfo: devices = sxp.children(self.config, 'device') index = {} for d in devices: - dev = sxp.child(d) + dev = sxp.child0(d) if dev is None: raise VmError('invalid device') dev_name = sxp.name(dev) @@ -672,7 +669,7 @@ class XendDomainInfo: """Set configuration flags if the vm is a backend for netif of blkif. """ for c in sxp.children(self.config, 'backend'): - name = sxp.name(sxp.child(c)) + name = sxp.name(sxp.child0(c)) if name == 'blkif': self.blkif_backend = 1 elif name == 'netif': @@ -754,7 +751,7 @@ def vm_image_linux(vm, image): """ kernel = sxp.child_value(image, "kernel") cmdline = "" - ip = sxp.child_value(image, "ip") or "dhcp" + ip = sxp.child_value(image, "ip", "dhcp") if ip: cmdline += " ip=" + ip root = sxp.child_value(image, "root") @@ -763,7 +760,7 @@ def vm_image_linux(vm, image): args = sxp.child_value(image, "args") if args: cmdline += " " + args - ramdisk = sxp.child_value(image, "ramdisk") or '' + ramdisk = sxp.child_value(image, "ramdisk", '') vifs = vm.config_devices("vif") vm.create_domain("linux", kernel, ramdisk, cmdline, len(vifs)) return vm @@ -780,7 +777,7 @@ def vm_image_netbsd(vm, image): #todo: Same as for linux. Is that right? If so can unify them. kernel = sxp.child_value(image, "kernel") cmdline = "" - ip = sxp.child_value(image, "ip") or "dhcp" + ip = sxp.child_value(image, "ip", "dhcp") if ip: cmdline += "ip=" + ip root = sxp.child_value(image, "root") @@ -809,7 +806,7 @@ def vm_dev_vif(vm, val, index): defer = make_vif(vm.dom, vif, vmac, vm.recreate) def fn(id): dev = xend.netif_dev(vm.dom, vif) - devid = sxp.child_value(val, 'id') + devid = sxp.attribute(val, 'id') if devid: dev.setprop('id', devid) bridge = sxp.child_value(val, "bridge") @@ -836,7 +833,7 @@ def vm_dev_vbd(vm, val, index): dev = sxp.child_value(val, 'dev') if not dev: raise VmError('vbd: Missing dev') - mode = sxp.child_value(val, 'mode') or 'r' + mode = sxp.child_value(val, 'mode', 'r') defer = make_disk(vm.dom, uname, dev, mode, vm.recreate) def fn(vbd): dev = xend.blkif_dev(vm.dom, vdev) @@ -938,7 +935,7 @@ def vm_field_vnet(vm, config, val, index): if id is None: raise VmError('vnet: missing vif id') dev = vm.get_device_by_id('vif', id) - #vnet = sxp.child_value(v, 'vnet') or '1' + #vnet = sxp.child_value(v, 'vnet', 1) #mac = sxp.child_value(dev, 'mac') #vif = sxp.child_value(dev, 'vif') #vnet_bridge(vnet, mac, vm.dom, 0) diff --git a/tools/python/xen/xend/XendRoot.py b/tools/python/xen/xend/XendRoot.py index 3687f57f4a..665f5df29e 100644 --- a/tools/python/xen/xend/XendRoot.py +++ b/tools/python/xen/xend/XendRoot.py @@ -145,7 +145,7 @@ class XendRoot: val default value (optional, defaults to None) returns value """ - return sxp.child_value(self.config, name) or val + return sxp.child_value(self.config, name, val=val) def instance(): global inst diff --git a/tools/python/xen/xend/sxp.py b/tools/python/xen/xend/sxp.py index 352f7f2933..143ba81ab4 100644 --- a/tools/python/xen/xend/sxp.py +++ b/tools/python/xen/xend/sxp.py @@ -21,19 +21,56 @@ from StringIO import StringIO __all__ = [ "mime_type", "ParseError", - "Parser", - "show", + "Parser", + "atomp", + "show", + "show_xml", + "elementp", "name", + "attributes", + "attribute", "children", "child", + "child_at", + "child0", + "child1", + "child2", + "child3", + "child4", "child_value", + "has_id", + "with_id", + "child_with_id", + "elements", "to_string", "from_string", + "all_from_string", "parse", ] mime_type = "application/sxp" +escapes = { + 'a': '\a', + 'b': '\b', + 't': '\t', + 'n': '\n', + 'v': '\v', + 'f': '\f', + 'r': '\r', + '\\': '\\', + '\'': '\'', + '\"': '\"'} + +k_list_open = "(" +k_list_close = ")" +k_attr_open = "@" +k_eval = "!" + +escapes_rev = {} +for k in escapes: + escapes_rev[escapes[k]] = k + class ParseError(StandardError): def __init__(self, parser, value): @@ -49,6 +86,7 @@ class ParserState: self.parent = parent self.buf = '' self.val = [] + self.delim = None self.fn = fn def push(self, fn): @@ -57,19 +95,28 @@ class ParserState: class Parser: def __init__(self): + self.error = sys.stderr self.reset() def reset(self): + self.val = [] self.eof = 0 + self.err = 0 self.line_no = 0 self.char_no = 0 - self.state = self.start_state = ParserState(self.state_start) + self.state = None def push_state(self, fn): self.state = self.state.push(fn) def pop_state(self): + val = self.state self.state = self.state.parent + if self.state and self.state.fn == self.state_start: + # Return to start state - produce the value. + self.val += self.state.val + self.state.val = [] + return val def in_class(self, c, s): return s.find(c) >= 0 @@ -89,6 +136,12 @@ class Parser: def in_printable_class(self, c): return self.in_class(c, string.printable) + def set_error_stream(self, error): + self.error = error + + def has_error(self): + return self.err > 0 + def at_eof(self): return self.eof @@ -113,131 +166,439 @@ class Parser: self.char_no += 1 if self.state is None: - self.state = ParserState(self.state_start) - + self.begin_start(None) self.state.fn(c) def ready(self): - return len(self.start_state.val) > 0 + return len(self.val) > 0 def get_val(self): - v = self.start_state.val[0] - self.start_state.val = self.start_state.val[1:] + v = self.val[0] + self.val = self.val[1:] return v def get_all(self): - return self.start_state.val + return self.val + def begin_start(self, c): + self.state = ParserState(self.state_start) + + def end_start(self): + self.val += self.state.val + self.pop_state() + def state_start(self, c): - if self.at_eof() or self.in_space_class(c): + if self.at_eof(): + self.end_start() + elif self.in_space_class(c): pass elif self.in_comment_class(c): - self.push_state(self.state_comment) - elif c == '(': - self.push_state(self.state_list) - elif c == ')': + self.begin_comment(c) + elif c == k_list_open: + self.begin_list(c) + elif c == k_list_close: raise ParseError(self, "syntax error: "+c) elif self.in_string_quote_class(c): - self.push_state(self.state_string) - self.state.buf = c + self.begin_string(c) elif self.in_printable_class(c): - self.push_state(self.state_atom) - self.state.buf = c + self.begin_atom(c) elif c == chr(4): # ctrl-D, EOT: end-of-text. self.input_eof() else: raise ParseError(self, "invalid character: code %d" % ord(c)) + def begin_comment(self, c): + self.push_state(self.state_comment) + self.state.buf += c + + def end_comment(self): + self.pop_state() + def state_comment(self, c): if c == '\n' or self.at_eof(): - self.pop_state() + self.end_comment() + else: + self.state.buf += c + def begin_string(self, c): + self.push_state(self.state_string) + self.state.delim = c + + def end_string(self): + val = self.state.buf + self.state.parent.val.append(val) + self.pop_state() + def state_string(self, c): if self.at_eof(): raise ParseError(self, "unexpected EOF") - self.state.buf += c - # Look out for non-escaped end delimiter - if self.state.buf[0] == c and self.state.buf[-2] != '\\': - try: # parse escape sequences but fall back to something simple - val = eval(compile(self.state.buf,'','eval')) - except: - val = self.state.buf[1:-1] # just strip the delimiters - self.state.parent.val.append(val) - self.pop_state() - - def state_atom(self, c): - if (self.at_eof() or - self.is_separator(c) or - self.in_space_class(c) or - self.in_comment_class(c)): - val = self.state.buf - self.state.parent.val.append(val) - self.pop_state() - if not self.at_eof(): - self.input_char(c) + elif c == self.state.delim: + self.end_string() + elif c == '\\': + self.push_state(self.state_escape) else: self.state.buf += c + def state_escape(self, c): + if self.at_eof(): + raise ParseError(self, "unexpected EOF") + d = escapes.get(c) + if d: + self.state.parent.buf += d + self.pop_state() + elif c == 'x': + self.state.fn = self.state_hex + self.state.val = 0 + else: + self.state.fn = self.state_octal + self.state.val = 0 + self.input_char(c) + + def state_octal(self, c): + def octaldigit(c): + self.state.val *= 8 + self.state.val += ord(c) - ord('0') + self.state.buf += c + if self.state.val < 0 or self.state.val > 0xff: + raise ParseError(self, "invalid octal escape: out of range " + self.state.buf) + if len(self.state.buf) == 3: + octaldone() + + def octaldone(): + d = chr(self.state.val) + self.state.parent.buf += d + self.pop_state() + + if self.at_eof(): + raise ParseError(self, "unexpected EOF") + elif '0' <= c <= '7': + octaldigit(c) + elif len(self.buf): + octaldone() + self.input_char(c) + + def state_hex(self, c): + def hexdone(): + d = chr(self.state.val) + self.state.parent.buf += d + self.pop_state() + + def hexdigit(c, d): + self.state.val *= 16 + self.state.val += ord(c) - ord(d) + self.state.buf += c + if self.state.val < 0 or self.state.val > 0xff: + raise ParseError(self, "invalid hex escape: out of range " + self.state.buf) + if len(self.state.buf) == 2: + hexdone() + + if self.at_eof(): + raise ParseError(self, "unexpected EOF") + elif '0' <= c <= '9': + hexdigit(c, '0') + elif 'A' <= c <= 'F': + hexdigit(c, 'A') + elif 'a' <= c <= 'f': + hexdigit(c, 'a') + elif len(buf): + hexdone() + self.input_char(c) + + def begin_atom(self, c): + self.push_state(self.state_atom) + self.state.buf = c + + def end_atom(self): + val = self.state.buf + self.state.parent.val.append(val) + self.pop_state() + + def state_atom(self, c): + if self.at_eof(): + self.end_atom() + elif (self.is_separator(c) or + self.in_space_class(c) or + self.in_comment_class(c)): + self.end_atom() + self.input_char(c) + else: + self.state.buf += c + + def begin_list(self, c): + self.push_state(self.state_list) + + def end_list(self): + val = self.state.val + self.state.parent.val.append(val) + self.pop_state() + def state_list(self, c): if self.at_eof(): raise ParseError(self, "unexpected EOF") - elif c == ')': - val = self.state.val - self.state.parent.val.append(val) - self.pop_state() + elif c == k_list_close: + self.end_list() else: self.state_start(c) +def atomp(sxpr): + """Check if an sxpr is an atom. + """ + if sxpr.isalnum() or sxpr == '@': + return 1 + for c in sxpr: + if c in string.whitespace: return 0 + if c in '"\'\\(){}[]<>$#&%^': return 0 + if c in string.ascii_letters: continue + if c in string.digits: continue + if c in '.-_:/~': continue + return 0 + return 1 + def show(sxpr, out=sys.stdout): """Print an sxpr in bracketed (lisp-style) syntax. """ if isinstance(sxpr, types.ListType): - out.write('(') + out.write(k_list_open) + i = 0 for x in sxpr: + if i: out.write(' ') show(x, out) - out.write(' ') - out.write(')') + i += 1 + out.write(k_list_close) + elif isinstance(sxpr, types.StringType) and atomp(sxpr): + out.write(sxpr) else: + #out.write("'" + str(sxpr) + "'") out.write(repr(str(sxpr))) -def name(sxpr): - """Get the element name of an sxpr, or None if a bad sxpr. +def show_xml(sxpr, out=sys.stdout): + """Print an sxpr in XML syntax. """ - if isinstance(sxpr, types.StringType): - return sxpr - if isinstance(sxpr, types.ListType) and len(sxpr): - return sxpr[0] - return None + if isinstance(sxpr, types.ListType): + element = name(sxpr) + out.write('<%s' % element) + for attr in attributes(sxpr): + out.write(' %s=%s' % (attr[0], attr[1])) + out.write('>') + i = 0 + for x in children(sxpr): + if i: out.write(' ') + show_xml(x, out) + i += 1 + out.write('' % element) + elif isinstance(sxpr, types.StringType) and atomp(sxpr): + out.write(sxpr) + else: + out.write(str(sxpr)) -def children(sxpr, elt=None): - """Get children of an s-expression @sxpr, optionally filtered by - element type @elt. +def elementp(sxpr, elt=None): + """Check if an sxpr is an element of the given type. + + sxpr sxpr + elt element type """ - if not isinstance(sxpr, types.ListType): return [] - val = filter(lambda x: isinstance(x, types.ListType) and len(x) > 0, sxpr) - if elt: - val = filter(lambda x,y=elt: x[0] == y, val) + return (isinstance(sxpr, types.ListType) + and len(sxpr) + and (None == elt or sxpr[0] == elt)) + +def name(sxpr): + """Get the element name of an sxpr. + If the sxpr is not an element (i.e. it's an atomic value) its name + is None. + + sxpr + + returns name (None if not an element). + """ + val = None + if isinstance(sxpr, types.StringType): + val = sxpr + elif isinstance(sxpr, types.ListType) and len(sxpr): + val = sxpr[0] return val -def child(sxpr, elt=None, idx=0): - """Get the @idx'th child of the optional filtering type @elt in @sxpr. - """ - x = children(sxpr, elt) - if len(x) > idx: - return x[idx] - return None +def attributes(sxpr): + """Get the attribute list of an sxpr. -def child_value(sxpr, elt=None): - """Get the value of the first child of @sxpr with the optional type @elt. + sxpr + + returns attribute list """ - x = child(sxpr, elt) - if not isinstance(x, types.ListType) or len(x) < 2: - return None - return x[1] + val = [] + if isinstance(sxpr, types.ListType) and len(sxpr) > 1: + attr = sxpr[1] + if elementp(attr, k_attr_open): + val = attr[1:] + return val + +def attribute(sxpr, key, val=None): + """Get an attribute of an sxpr. + + sxpr sxpr + key attribute key + val default value (default None) + + returns attribute value + """ + for x in attributes(sxpr): + if x[0] == key: + val = x[1] + break + return val + +def children(sxpr, elt=None): + """Get children of an sxpr. + + sxpr sxpr + elt optional element type to filter by + + returns children (filtered by elt if specified) + """ + val = [] + if isinstance(sxpr, types.ListType) and len(sxpr) > 1: + i = 1 + x = sxpr[i] + if elementp(x, k_attr_open): + i += 1 + val = sxpr[i : ] + if elt: + def iselt(x): + return elementp(x, elt) + val = filter(iselt, val) + return val + +def child(sxpr, elt, val=None): + """Get the first child of the given element type. + + sxpr sxpr + elt element type + val default value + """ + for x in children(sxpr): + if elementp(x, elt): + val = x + break + return val + +def child_at(sxpr, index, val=None): + """Get the child at the given index (zero-based). + + sxpr sxpr + index index + val default value + """ + kids = children(sxpr) + if len(kids) > index: + val = kids[index] + return val + +def child0(sxpr, val=None): + """Get the zeroth child. + """ + return child_at(sxpr, 0, val) + +def child1(sxpr, val=None): + """Get the first child. + """ + return child_at(sxpr, 1, val) + +def child2(sxpr, val=None): + """Get the second child. + """ + return child_at(sxpr, 2, val) + +def child3(sxpr, val=None): + """Get the third child. + """ + return child_at(sxpr, 3, val) + +def child4(sxpr, val=None): + """Get the fourth child. + """ + return child_at(sxpr, 4, val) + +def child_value(sxpr, elt, val=None): + """Get the value of the first child of the given element type. + Assumes the child has an atomic value. + + sxpr sxpr + elt element type + val default value + """ + kid = child(sxpr, elt) + if kid: + val = child_at(kid, 0, val) + return val + +def has_id(sxpr, id): + """Test if an s-expression has a given id. + """ + return attribute(sxpr, 'id') == id + +def with_id(sxpr, id, val=None): + """Find the first s-expression with a given id, at any depth. + + sxpr s-exp or list + id id + val value if not found (default None) + + return s-exp or val + """ + if isinstance(sxpr, types.ListType): + for n in sxpr: + if has_id(n, id): + val = n + break + v = with_id(n, id) + if v is None: continue + val = v + break + return val + +def child_with_id(sxpr, id, val=None): + """Find the first child with a given id. + + sxpr s-exp or list + id id + val value if not found (default None) + + return s-exp or val + """ + if isinstance(sxpr, types.ListType): + for n in sxpr: + if has_id(n, id): + val = n + break + return val + +def elements(sxpr, ctxt=None): + """Generate elements (at any depth). + Visit elements in pre-order. + Values generated are (node, context) + The context is None if there is no parent, otherwise + (index, parent, context) where index is the node's index w.r.t its parent, + and context is the parent's context. + + sxpr s-exp + + returns generator + """ + yield (sxpr, ctxt) + i = 0 + for n in children(sxpr): + if isinstance(n, types.ListType): + # Calling elements() recursively does not generate recursively, + # it just returns a generator object. So we must iterate over it. + for v in elements(n, (i, sxpr, ctxt)): + yield v + i += 1 def to_string(sxpr): - """Convert an s-expression @sxpr to a string. + """Convert an sxpr to a string. + + sxpr sxpr + returns string """ io = StringIO() show(sxpr, io) @@ -247,14 +608,35 @@ def to_string(sxpr): return val def from_string(str): - """Create an sxpr list from a given input string @str. + """Create an sxpr by parsing a string. + + str string + returns sxpr + """ + io = StringIO(str) + vals = parse(io) + if vals is []: + return None + else: + return vals[0] + + +def all_from_string(str): + """Create an sxpr list by parsing a string. + + str string + returns sxpr list """ io = StringIO(str) vals = parse(io) return vals def parse(io): - """Completely parse all input from file @io. + """Completely parse all input from 'io'. + + io input file object + returns list of values, None if incomplete + raises ParseError on parse error """ pin = Parser() while 1: @@ -267,11 +649,19 @@ def parse(io): else: val = None return val - + if __name__ == '__main__': + print ">main" pin = Parser() - buf = sys.stdin.read(1024) - pin.input(buf) - while pin.ready(): - print '\n****** val=', pin.get_val() + while 1: + buf = sys.stdin.read(1024) + #buf = sys.stdin.readline() + pin.input(buf) + while pin.ready(): + val = pin.get_val() + print + print '****** val=', val + if len(buf) == 0: + break + diff --git a/tools/python/xen/xm/main.py b/tools/python/xen/xm/main.py index 9ae1fb67b8..97a36f6711 100644 --- a/tools/python/xen/xm/main.py +++ b/tools/python/xen/xm/main.py @@ -246,11 +246,11 @@ class ProgList(Prog): info = server.xend_domain(dom) d = {} d['dom'] = int(dom) - d['name'] = sxp.child_value(info, 'name') or '??' - d['mem'] = int(sxp.child_value(info, 'memory') or '-1') - d['cpu'] = int(sxp.child_value(info, 'cpu') or '-1') - d['state'] = sxp.child_value(info, 'state') or '??' - d['cpu_time'] = float(sxp.child_value(info, 'cpu_time') or '-1') + d['name'] = sxp.child_value(info, 'name', '??') + d['mem'] = int(sxp.child_value(info, 'memory', '0')) + d['cpu'] = int(sxp.child_value(info, 'cpu', '0')) + d['state'] = sxp.child_value(info, 'state', '??') + d['cpu_time'] = float(sxp.child_value(info, 'cpu_time', '0')) print ("%(dom)-4d %(name)-16s %(mem)7d %(cpu)3d %(state)5s %(cpu_time)7.1f" % d) def long_list(self, doms): @@ -424,9 +424,9 @@ class ProgConsoles(Prog): for x in l: info = server.xend_console(x) d = {} - d['dom'] = (sxp.child(info, 'dst') or ['dst', '?', '?'])[1] - d['port'] = sxp.child_value(info, 'port') or '?' - d['id'] = sxp.child_value(info, 'id') or '?' + d['dom'] = sxp.child(info, 'dst', ['dst', '?', '?'])[1] + d['port'] = sxp.child_value(info, 'port', '?') + d['id'] = sxp.child_value(info, 'id', '?') print "%(dom)3s %(port)4s %(id)3s" % d xm.prog(ProgConsoles) From b2d94974603e025dfe4b4258ca70f3030956b044 Mon Sep 17 00:00:00 2001 From: "kaf24@scramble.cl.cam.ac.uk" Date: Wed, 7 Jul 2004 13:07:37 +0000 Subject: [PATCH 36/36] bitkeeper revision 1.1041.15.2 (40ebf599xwzX2YRHxQvVAFkLp9CM5g) Fix disconnect handling in netif/blkif drivers. Add debug tracing to control-interface routines. --- .../xen/drivers/blkif/backend/interface.c | 4 ++- .../arch/xen/drivers/netif/backend/common.h | 2 +- .../xen/drivers/netif/backend/interface.c | 4 ++- .../arch/xen/kernel/ctrl_if.c | 31 +++++++++++++++++++ 4 files changed, 38 insertions(+), 3 deletions(-) diff --git a/linux-2.4.26-xen-sparse/arch/xen/drivers/blkif/backend/interface.c b/linux-2.4.26-xen-sparse/arch/xen/drivers/blkif/backend/interface.c index 16b37164ab..a555b18e72 100644 --- a/linux-2.4.26-xen-sparse/arch/xen/drivers/blkif/backend/interface.c +++ b/linux-2.4.26-xen-sparse/arch/xen/drivers/blkif/backend/interface.c @@ -220,9 +220,11 @@ int blkif_disconnect(blkif_be_disconnect_t *disconnect, u8 rsp_id) free_irq(blkif->irq, blkif); blkif_deschedule(blkif); blkif_put(blkif); + return 0; /* Caller should not send response message. */ } - return 0; /* Caller should not send response message. */ + disconnect->status = BLKIF_BE_STATUS_OKAY; + return 1; } void __init blkif_interface_init(void) diff --git a/linux-2.4.26-xen-sparse/arch/xen/drivers/netif/backend/common.h b/linux-2.4.26-xen-sparse/arch/xen/drivers/netif/backend/common.h index f3eff0d81b..87fdb730d1 100644 --- a/linux-2.4.26-xen-sparse/arch/xen/drivers/netif/backend/common.h +++ b/linux-2.4.26-xen-sparse/arch/xen/drivers/netif/backend/common.h @@ -21,7 +21,7 @@ #define ASSERT(_p) \ if ( !(_p) ) { printk("Assertion '%s' failed, line %d, file %s", #_p , \ __LINE__, __FILE__); *(int*)0=0; } -#define DPRINTK(_f, _a...) printk("(file=%s, line=%d) " _f, \ +#define DPRINTK(_f, _a...) printk(KERN_ALERT "(file=%s, line=%d) " _f, \ __FILE__ , __LINE__ , ## _a ) #else #define ASSERT(_p) ((void)0) diff --git a/linux-2.4.26-xen-sparse/arch/xen/drivers/netif/backend/interface.c b/linux-2.4.26-xen-sparse/arch/xen/drivers/netif/backend/interface.c index ff3bc7bbf7..757d10ba2c 100644 --- a/linux-2.4.26-xen-sparse/arch/xen/drivers/netif/backend/interface.c +++ b/linux-2.4.26-xen-sparse/arch/xen/drivers/netif/backend/interface.c @@ -269,9 +269,11 @@ int netif_disconnect(netif_be_disconnect_t *disconnect, u8 rsp_id) free_irq(netif->irq, netif); netif_deschedule(netif); netif_put(netif); + return 0; /* Caller should not send response message. */ } - return 0; /* Caller should not send response message. */ + disconnect->status = NETIF_BE_STATUS_OKAY; + return 1; } void netif_interface_init(void) diff --git a/linux-2.4.26-xen-sparse/arch/xen/kernel/ctrl_if.c b/linux-2.4.26-xen-sparse/arch/xen/kernel/ctrl_if.c index 0e6389406c..f208efe100 100644 --- a/linux-2.4.26-xen-sparse/arch/xen/kernel/ctrl_if.c +++ b/linux-2.4.26-xen-sparse/arch/xen/kernel/ctrl_if.c @@ -17,6 +17,13 @@ #include #include +#if 0 +#define DPRINTK(_f, _a...) printk(KERN_ALERT "(file=%s, line=%d) " _f, \ + __FILE__ , __LINE__ , ## _a ) +#else +#define DPRINTK(_f, _a...) ((void)0) +#endif + /* * Only used by initial domain which must create its own control-interface * event channel. This value is picked up by the user-space domain controller @@ -86,6 +93,11 @@ static void __ctrl_if_tx_tasklet(unsigned long data) { msg = &ctrl_if->tx_ring[MASK_CONTROL_IDX(ctrl_if_tx_resp_cons)]; + DPRINTK("Rx-Rsp %u/%u :: %d/%d\n", + ctrl_if_tx_resp_cons, + ctrl_if->tx_resp_prod, + msg->type, msg->subtype); + /* Execute the callback handler, if one was specified. */ if ( msg->id != 0xFF ) { @@ -131,8 +143,15 @@ static void __ctrl_if_rx_tasklet(unsigned long data) { pmsg = &ctrl_if->rx_ring[MASK_CONTROL_IDX(ctrl_if_rx_req_cons++)]; memcpy(&msg, pmsg, offsetof(ctrl_msg_t, msg)); + + DPRINTK("Rx-Req %u/%u :: %d/%d\n", + ctrl_if_rx_req_cons-1, + ctrl_if->rx_req_prod, + msg.type, msg.subtype); + if ( msg.length != 0 ) memcpy(msg.msg, pmsg->msg, msg.length); + if ( test_bit(msg.type, &ctrl_if_rxmsg_blocking_context) ) { pmsg = &ctrl_if_rxmsg_deferred[MASK_CONTROL_IDX( @@ -185,6 +204,11 @@ int ctrl_if_send_message_noblock( msg->id = i; } + DPRINTK("Tx-Req %u/%u :: %d/%d\n", + ctrl_if->tx_req_prod, + ctrl_if_tx_resp_cons, + msg->type, msg->subtype); + memcpy(&ctrl_if->tx_ring[MASK_CONTROL_IDX(ctrl_if->tx_req_prod)], msg, sizeof(*msg)); wmb(); /* Write the message before letting the controller peek at it. */ @@ -262,11 +286,18 @@ void ctrl_if_send_response(ctrl_msg_t *msg) * In this situation we may have src==dst, so no copying is required. */ spin_lock_irqsave(&ctrl_if_lock, flags); + + DPRINTK("Tx-Rsp %u :: %d/%d\n", + ctrl_if->rx_resp_prod, + msg->type, msg->subtype); + dmsg = &ctrl_if->rx_ring[MASK_CONTROL_IDX(ctrl_if->rx_resp_prod)]; if ( dmsg != msg ) memcpy(dmsg, msg, sizeof(*msg)); + wmb(); /* Write the message before letting the controller peek at it. */ ctrl_if->rx_resp_prod++; + spin_unlock_irqrestore(&ctrl_if_lock, flags); ctrl_if_notify_controller();