[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH 01 of 12] xenalyze: Allow several summary handlers to register on a single vmexit



VMX tends to have several distinct kinds of handlers for a single
vmexit type; notably, EXCEPTION_NMI gets page faults, other traps,
emulations, and sometimes other kinds of traps as well; while for
SVM, each different trap has a different call type.

This patch introduces a signal-style callback mechanism that allows
several callbacks to be attached to a given exit reason.  Each of these
callbacks will be called in the case of a summary event.

In order to distinguish different kinds of callbacks, the callback also
includes a value which is passed as-is to the function when it's called.
It's the size of a pointer so that it can be used as a pointer if necessary;
typically it will probably be a small integer value.

Each vmexit should only register a handler once with any given data value;
there is some syntactic sugar to make sure this happens.

Signed-off-by: George Dunlap <george.dunlap@xxxxxxxxxxxxx>

diff -r 288573cb0f11 -r 2e85d4c4042e xenalyze.c
--- a/xenalyze.c        Fri Oct 07 11:49:04 2011 +0100
+++ b/xenalyze.c        Mon Nov 28 16:16:23 2011 +0000
@@ -1308,6 +1308,14 @@ struct pcpu_info;
 #define RESYNCS_MAX 17
 #define PF_XEN_FIXUP_UNSYNC_RESYNC_MAX 2
 
+struct hvm_data;
+
+struct hvm_summary_handler_node {
+    void (*handler)(struct hvm_data *, void* data);
+    void *data;
+    struct hvm_summary_handler_node *next;
+};
+
 struct hvm_data {
     /* Summary information */
     int init;
@@ -1318,7 +1326,7 @@ struct hvm_data {
     /* SVM / VMX compatibility. FIXME - should be global */
     char ** exit_reason_name;
     int exit_reason_max;
-    void (* exit_reason_summary_handler[HVM_EXIT_REASON_MAX])(struct hvm_data 
*);
+    struct hvm_summary_handler_node 
*exit_reason_summary_handler_list[HVM_EXIT_REASON_MAX];
 
     /* Information about particular exit reasons */
     struct {
@@ -3011,23 +3019,58 @@ void hvm_short_summary(struct hvm_short_
     }
 }
 
-void hvm_set_summary_handler(struct hvm_data *h, void (*s)(struct hvm_data 
*h)) {
+/* Wrapper to try to make sure this is only called once per
+ * call site, rather than walking through the list each time */
+#define hvm_set_summary_handler(_h, _s, _d)                             \
+    do {                                                                \
+        static int done=0;                                              \
+        int ret;                                                        \
+        if(!done) {                                                     \
+            if ((ret=__hvm_set_summary_handler(_h, _s, _d)))            \
+                fprintf(stderr, "%s: hvm_set_summary_handler returned %d\n", \
+                        __func__, ret);                                 \
+            done=1;                                                     \
+        }                                                               \
+    } while(0)
+
+int __hvm_set_summary_handler(struct hvm_data *h, void (*s)(struct hvm_data 
*h, void*d), void*d) {
     /* Set summary handler */
     if(h->exit_reason < h->exit_reason_max)
     {
-        if(h->exit_reason_summary_handler[h->exit_reason])
+        struct hvm_summary_handler_node *p, **q;
+
+        /* Find the end of the list, checking to make sure there are no
+         * duplicates along the way */
+        q=&h->exit_reason_summary_handler_list[h->exit_reason];
+        p = *q;
+        while(p)
         {
-            if(h->exit_reason_summary_handler[h->exit_reason]!= s)
-                fprintf(warn, "Strange, unexpected summary handler for 
exit_reason %s (%d!)\n",
-                        h->exit_reason_name[h->exit_reason], h->exit_reason);
-        }
-        else
-        {
-            h->exit_reason_summary_handler[h->exit_reason] = s;
-            fprintf(warn, "Setting exit_reason %s (%d) summary handler\n",
-                    h->exit_reason_name[h->exit_reason], h->exit_reason);
-        }
-    }
+            if(p->handler == s && p->data == d)
+            {
+                fprintf(stderr, "%s: Unexpected duplicate handler %p,%p\n",
+                        __func__, s, d);
+                error(ERR_STRICT, NULL);
+            return -EBUSY;
+            }
+            q=&p->next;
+            p=*q;
+        }
+
+        assert(p==NULL);
+
+        /* Insert the new handler */
+        p=malloc(sizeof(*p));
+        if (!p) {
+            fprintf(stderr, "%s: Malloc failed!\n", __func__);
+            error(ERR_SYSTEM, NULL);
+        }
+        p->handler=s;
+        p->data = d;
+        p->next=*q;
+        *q=p;
+        return 0;
+    }
+    return -EINVAL;
 }
 
 #define SIGN_EXTENDED_BITS (~((1ULL<<48)-1))
@@ -3040,7 +3083,7 @@ static inline int is_valid_addr64(unsign
         return ((va & SIGN_EXTENDED_BITS) == 0);
 }
 
-void hvm_pf_xen_summary(struct hvm_data *h) {
+void hvm_pf_xen_summary(struct hvm_data *h, void *d) {
     int i,j, k;
     
     for(i=0; i<PF_XEN_MAX; i++)
@@ -3314,7 +3357,7 @@ void hvm_pf_xen_postprocess(struct hvm_d
         }
 
         /* Set summary handler */
-        hvm_set_summary_handler(h, hvm_pf_xen_summary);
+        hvm_set_summary_handler(h, hvm_pf_xen_summary, NULL);
     }
 
     if(opt.dump_cooked)
@@ -4061,7 +4104,7 @@ void cr3_dump_list(struct cr3_value_stru
     free(qsort_array);
 }
 
-void hvm_cr3_write_summary(struct hvm_data *h) {
+void hvm_cr3_write_summary(struct hvm_data *h, void *data) {
     int j;
 
     for(j=0; j<RESYNCS_MAX; j++)
@@ -4071,7 +4114,7 @@ void hvm_cr3_write_summary(struct hvm_da
                   "     *[MAX] ");
 }
 
-void hvm_cr_write_summary(struct hvm_data *h)
+void hvm_cr_write_summary(struct hvm_data *h, void *data)
 {
     int i;
 
@@ -4081,7 +4124,7 @@ void hvm_cr_write_summary(struct hvm_dat
                       "   cr%d ", i);
         switch(i) {
         case 3:
-            hvm_cr3_write_summary(h);
+            hvm_cr3_write_summary(h, NULL);
             break;
         }
     }
@@ -4168,11 +4211,11 @@ void hvm_cr_write_postprocess(struct hvm
         if ( opt.svm_mode ) {
             /* For svm, only need a summary for cr3 */
             if ( h->exit_reason == VMEXIT_CR3_WRITE )
-                hvm_set_summary_handler(h, hvm_cr3_write_summary);
+                hvm_set_summary_handler(h, hvm_cr3_write_summary, NULL);
         } else {
             /* For vmx, real mode may cause EXNMI exits on cr accesses */
             if ( h->exit_reason !=  EXIT_REASON_EXCEPTION_NMI )
-                hvm_set_summary_handler(h, hvm_cr_write_summary);
+                hvm_set_summary_handler(h, hvm_cr_write_summary, NULL);
         }
     }
 }
@@ -4229,7 +4272,7 @@ void hvm_cr_write_process(struct record_
 }
 
 /* msr_write */
-void hvm_msr_write_summary(struct hvm_data *h)
+void hvm_msr_write_summary(struct hvm_data *h, void *d)
 {
 }
 
@@ -4247,7 +4290,7 @@ void hvm_msr_write_postprocess(struct hv
     }
 
     /* Set summary handler */
-    hvm_set_summary_handler(h, hvm_msr_write_summary);
+    hvm_set_summary_handler(h, hvm_msr_write_summary, NULL);
 }
 
 void hvm_msr_write_process(struct record_info *ri, struct hvm_data *h)
@@ -4274,7 +4317,7 @@ void hvm_msr_write_process(struct record
 }
 
 /* msr_read */
-void hvm_msr_read_summary(struct hvm_data *h)
+void hvm_msr_read_summary(struct hvm_data *h, void *d)
 {
 }
 
@@ -4292,7 +4335,7 @@ void hvm_msr_read_postprocess(struct hvm
     }
 
     /* Set summary handler */
-    hvm_set_summary_handler(h, hvm_msr_read_summary);
+    hvm_set_summary_handler(h, hvm_msr_read_summary, NULL);
 }
 
 void hvm_msr_read_process(struct record_info *ri, struct hvm_data *h)
@@ -4318,7 +4361,7 @@ void hvm_msr_read_process(struct record_
     h->post_process = hvm_msr_read_postprocess;
 }
 
-void hvm_vmcall_summary(struct hvm_data *h)
+void hvm_vmcall_summary(struct hvm_data *h, void *d)
 {
     int i;
 
@@ -4343,6 +4386,7 @@ void hvm_vmcall_postprocess(struct hvm_d
         else
             update_summary(&h->summary.vmcall[HYPERCALL_MAX],
                        h->arc_cycles);
+        hvm_set_summary_handler(h, hvm_vmcall_summary, NULL);
     }
 }
 
@@ -4365,7 +4409,6 @@ void hvm_vmcall_process(struct record_in
     }
 
     if(opt.summary) {
-        hvm_set_summary_handler(h, hvm_vmcall_summary);
         h->inflight.vmcall.eax = r->eax;
         h->post_process = hvm_vmcall_postprocess;
     }
@@ -4391,7 +4434,7 @@ void hvm_inj_exc_process(struct record_i
     
 }
 
-void hvm_intr_summary(struct hvm_data *h)
+void hvm_intr_summary(struct hvm_data *h, void *d)
 {
     int i;
 
@@ -4483,7 +4526,7 @@ void hvm_intr_process(struct hvm_data *h
 
     if(opt.summary_info) {
         if(opt.summary)
-            hvm_set_summary_handler(h, hvm_intr_summary);
+            hvm_set_summary_handler(h, hvm_intr_summary, NULL);
 
         if(vec < EXTERNAL_INTERRUPT_MAX)
             h->summary.extint[vec]++;
@@ -5321,6 +5364,8 @@ void hvm_summary(struct hvm_data *h) {
 
    printf("Exit reasons:\n");
    for(i=0; i<h->exit_reason_max; i++) {
+       struct hvm_summary_handler_node *p;
+
        if ( h->exit_reason_name[i] )
            PRINT_SUMMARY(h->summary.exit_reason[i],
                          " %-20s ", h->exit_reason_name[i]);
@@ -5328,8 +5373,12 @@ void hvm_summary(struct hvm_data *h) {
            PRINT_SUMMARY(h->summary.exit_reason[i],
                          " %20d ", i);
 
-       if(h->exit_reason_summary_handler[i])
-           h->exit_reason_summary_handler[i](h);
+       p=h->exit_reason_summary_handler_list[i];
+       while(p)
+       {
+           p->handler(h, p->data);
+           p=p->next;
+       }
    }
 
    printf("Guest interrupt counts:\n");
@@ -6238,7 +6287,7 @@ void shadow_process(struct pcpu_info *p)
     if(sevt.minor <= PF_XEN_LAST_FAULT)  {
         h->inflight.pf_xen.pf_case = sevt.minor;
         if(opt.summary) {
-            hvm_set_summary_handler(h, hvm_pf_xen_summary);
+            hvm_set_summary_handler(h, hvm_pf_xen_summary, NULL);
         }
     }
 

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.