Hi, Ben & all.

Attached is a patch to rewrite the 'Pipeline' & 'RunHooks' methods without the 
use of yield.
The code is under '#if TARGET_JVM' and is meant for the Grasshopper 
configuration.
Ben & Miguel - would you prefer having this patch as is (including the #if 
TARGET_J2EE) or
is it acceptable that we will share the new code for Mono and remove the use of 
'yield' from
HttpApplication?
Here is a brief description of the changes:
  * RunHooks creates an instance of RunHooksEnumerator.
      * RunHooksEnumerator is rather simple - it goes over the delegate 
invocation list
        and processes each delegate (code taken from the original RunHooks).
        If the ProcessDelegate returns true the enumerator MoveNext returns and 
the enumerator
        Current value will be the app's stop_processing flag.
  * Pipeline creates and instance of PipeLineEnumerator. PipeLineEnumerator is 
more complex.
      * It main logic is to enumerate delegates through the RunHooks enumerator.
      * I took the central parts of Pipeline and broke them into three methods
        AllocateHandler, ProcessHandler & ReleaseHandler. When these methods 
return true the
        enumerator MoveNext stops and returns true.
      * The scheduler of Pipeline is in FindNextDelegate which has a switch 
that lists
        the delegates that the pipeline enumerates by their order.
  * Tick didn't work as is in the TARGET_J2EE model. We don't manage our own 
thread pool for
    ASP.Net (the J2EE servlet does this) and I replaced the 'if 
(pipeline.MoveNext ())'
    with a 'while (pipeline.MoveNext ())'. I do not understand well enough how 
the Tick
    ticks in Mono, especially where I see in Resume that it does not Tick if 
it's still
    in the state of 'in_begin'.
Any comments on the class design and correctness of this rewrite are more then 
welcome.
If you can elaborate more about 'Tick' and how it works in Mono it will help me 
to understand
where the TARGET_J2EE behaves differently and find the correct solution for 
this (I see the
use of 'while' as hack).

Eyal.
Index: System.Web/HttpApplication.cs

===================================================================

--- System.Web/HttpApplication.cs       (revision 49680)

+++ System.Web/HttpApplication.cs       (working copy)

@@ -553,17 +553,33 @@

                //
                // Ticks the clock: next step on the pipeline.
                //
+#if TARGET_J2EE
                void Tick ()
                {
                        try {
+                               while (pipeline.MoveNext ()){
+                                       if ((bool)pipeline.Current) {
+                                               PipelineDone ();
+                                               break;
+                                       }
+                               }
+                       } catch (Exception e) {
+                               Console.WriteLine ("Tick caught an exception 
that has not been propagated:\n" + e.GetType().FullName + e.Message + 
e.StackTrace);
+                       }
+               }
+#else
+               void Tick ()
+               {
+                       try {
                                if (pipeline.MoveNext ()){
                                        if ((bool)pipeline.Current)
                                                PipelineDone ();
                                }
                        } catch (Exception e) {
-                               Console.WriteLine ("Tick caught an exception 
that has not been propagated:\n" + e);
+                               Console.WriteLine ("Tick caught an exception 
that has not been propagated:\n" + e.GetType().FullName + e.Message + 
e.StackTrace);
                        }
                }
+#endif
 
                void Resume ()
                {
@@ -602,14 +618,106 @@

                        
                        Resume ();
                }
-               
+
                //
                // This enumerator yields whether processing must be stopped:
                //    true:  processing of the pipeline must be stopped
                //    false: processing of the pipeline must not be stopped
                //
+#if TARGET_JVM
+               internal class RunHooksEnumerator : IEnumerable, IEnumerator
+               {
+                       Delegate [] delegates;
+                       int currentStep = 0;
+                       HttpApplication app;
+
+                       internal RunHooksEnumerator(HttpApplication app, 
Delegate list)
+                       {
+                               this.app = app;
+                               delegates = list.GetInvocationList ();
+                       }
+
+                       public virtual IEnumerator GetEnumerator() { return 
this; }
+                       public virtual object Current { get{ return 
app.stop_processing; } }
+                       public virtual void Reset()
+                       {
+                               throw new 
NotImplementedException("HttpApplication.RunHooksEnumerator.Reset called.");
+                       }
+                       public virtual bool MoveNext ()
+                       {
+                               while (currentStep < delegates.Length) {
+                                       if 
(ProcessDelegate((EventHandler)delegates[currentStep++]))
+                                               return true;
+                               }
+                               return false;
+                       }
+
+                       bool ProcessDelegate(EventHandler d)
+                       {
+                               if (d.Target != null && (d.Target is 
AsyncInvoker)){
+                                       app.current_ai = (AsyncInvoker) 
d.Target;
+
+                                       try {
+                                               app.must_yield = true;
+                                               app.in_begin = true;
+                                               
app.context.BeginTimeoutPossible ();
+                                               app.current_ai.begin (app, 
EventArgs.Empty, new AsyncCallback(app.async_callback_completed_cb), 
app.current_ai.data);
+                                       }
+                                       catch (ThreadAbortException taex){
+                                               object obj = 
taex.ExceptionState;
+                                               Thread.ResetAbort ();
+                                               app.stop_processing = true;
+                                               if (obj is StepTimeout)
+                                                       app.ProcessError (new 
HttpException ("The request timed out."));
+                                       }
+                                       catch (Exception e){
+                                               app.ProcessError (e);
+                                       }
+                                       finally {
+                                               app.in_begin = false;
+                                               app.context.EndTimeoutPossible 
();
+                                       }
+
+                                       //
+                                       // If things are still moving forward, 
yield this
+                                       // thread now
+                                       //
+                                       if (app.must_yield)
+                                               return true;
+                                       else if (app.stop_processing)
+                                               return true;
+                               }
+                               else {
+                                       try {
+                                               
app.context.BeginTimeoutPossible ();
+                                               d (app, EventArgs.Empty);
+                                       } catch (ThreadAbortException taex){
+                                               object obj = 
taex.ExceptionState;
+                                               Thread.ResetAbort ();
+                                               app.stop_processing = true;
+                                               if (obj is StepTimeout)
+                                                       app.ProcessError (new 
HttpException ("The request timed out."));
+                                       }
+                                       catch (Exception e){
+                                               app.ProcessError (e);
+                                       }
+                                       finally {
+                                               app.context.EndTimeoutPossible 
();
+                                       }
+                                       if (app.stop_processing)
+                                               return true;
+                               }
+                               return false;
+                       }
+               }
+
                IEnumerable RunHooks (Delegate list)
                {
+                       return new RunHooksEnumerator(this, list);
+               }
+#else
+               IEnumerable RunHooks (Delegate list)
+               {
                        Delegate [] delegates = list.GetInvocationList ();
 
                        foreach (EventHandler d in delegates){
@@ -620,7 +728,7 @@

                                                must_yield = true;
                                                in_begin = true;
                                                context.BeginTimeoutPossible ();
-                                               current_ai.begin (this, 
EventArgs.Empty, async_callback_completed_cb, current_ai.data);
+                                               current_ai.begin (this, 
EventArgs.Empty, new AsyncCallback(async_callback_completed_cb), 
current_ai.data);
                                        } catch (ThreadAbortException taex){
                                                object obj = 
taex.ExceptionState;
                                                Thread.ResetAbort ();
@@ -662,6 +770,7 @@

                                }
                        }
                }
+#endif
 
                static void FinalErrorWrite (HttpResponse response, string 
error)
                {
@@ -756,6 +865,215 @@

                        PostDone ();
                }
 
+#if TARGET_JVM
+               class PipeLineEnumerator : IEnumerator
+               {
+                       HttpApplication app;
+                       IEnumerator currentEnumerator = null;
+                       int currentStep = 0;
+                       bool pipelineFinished = false;
+                       IHttpHandler handler = null;
+                       bool currentVal;
+                       InternalStepDelegate AllocateHandlerDel;
+                       InternalStepDelegate ProcessHandlerDel;
+                       InternalStepDelegate ReleaseHandlerDel;
+
+                       // true means that we need to yield and return the 
current value;
+                       // false means that we need to go on to the next 
delegate and return
+                       // values from there.
+                       delegate bool InternalStepDelegate();
+
+                       internal PipeLineEnumerator(HttpApplication app)
+                       {
+                               this.app = app;
+                               AllocateHandlerDel = new 
InternalStepDelegate(AllocateHandler);
+                               ProcessHandlerDel = new 
InternalStepDelegate(ProcessHandler);
+                               ReleaseHandlerDel = new 
InternalStepDelegate(ReleaseHandler);
+                       }
+
+                       public virtual object Current
+                       {
+                               get
+                               {
+                                       if (currentEnumerator != null)
+                                               return 
currentEnumerator.Current;
+                                       return currentVal;
+                               }
+                       }
+
+                       // See InternalStepDelegate for meaning of true/false 
return value
+                       bool AllocateHandler()
+                       {
+                               // Obtain the handler for the request.
+                               try {
+                                       handler = app.GetHandler (app.context);
+                               }
+                               catch (FileNotFoundException fnf){
+                                       if (app.context.Request.IsLocal)
+                                               app.ProcessError (new 
HttpException (404, String.Format ("File not found {0}", fnf.FileName), fnf));
+                                       else
+                                               app.ProcessError (new 
HttpException (404, "File not found", fnf));
+                               } catch (DirectoryNotFoundException dnf){
+                                       app.ProcessError (new HttpException 
(404, "Directory not found", dnf));
+                               } catch (Exception e) {
+                                       app.ProcessError (e);
+                               }
+
+                               if (app.stop_processing) {
+                                       currentVal = false;
+                                       return true;
+                               }
+                               return false;
+                       }
+
+                       // See InternalStepDelegate for meaning of true/false 
return value
+                       bool ProcessHandler()
+                       {
+                               //
+                               // From this point on, we need to ensure that 
we call
+                               // ReleaseRequestState, so the code below jumps 
to
+                               // `release:' to guarantee it rather than 
yielding.
+                               //
+                               if (app.PreRequestHandlerExecute != null)
+                                       foreach (bool stop in app.RunHooks 
(app.PreRequestHandlerExecute))
+                                               if (stop)
+                                                       return false;
+
+                               try {
+                                       app.context.BeginTimeoutPossible ();
+                                       if (handler != null){
+                                               IHttpAsyncHandler async_handler 
= handler as IHttpAsyncHandler;
+                                       
+                                               if (async_handler != null){
+                                                       app.must_yield = true;
+                                                       app.in_begin = true;
+                                                       
async_handler.BeginProcessRequest (app.context, new 
AsyncCallback(app.async_handler_complete_cb), handler);
+                                               } else {
+                                                       app.must_yield = false;
+                                                       handler.ProcessRequest 
(app.context);
+                                               }
+                                       }
+                               }
+                               catch (ThreadAbortException taex){
+                                       object obj = taex.ExceptionState;
+                                       Thread.ResetAbort ();
+                                       app.stop_processing = true;
+                                       if (obj is StepTimeout)
+                                               app.ProcessError (new 
HttpException ("The request timed out."));
+                               }
+                               catch (Exception e){
+                                       app.ProcessError (e);
+                               }
+                               finally {
+                                       app.in_begin = false;
+                                       app.context.EndTimeoutPossible ();
+                               }
+                               if (app.must_yield) {
+                                       currentVal = app.stop_processing;
+                                       return true;
+                               }
+                               else if (app.stop_processing)
+                                       return false;
+                       
+                               // These are executed after the application has 
returned
+                               if (app.PostRequestHandlerExecute != null)
+                                       foreach (bool stop in app.RunHooks 
(app.PostRequestHandlerExecute))
+                                               if (stop)
+                                                       return false;
+
+                               return false;
+                       }
+
+                       // See InternalStepDelegate for meaning of true/false 
return value
+                       bool ReleaseHandler()
+                       {
+                               if (app.ReleaseRequestState != null){
+                                       foreach (bool stop in app.RunHooks 
(app.ReleaseRequestState)){
+                                               //
+                                               // Ignore the stop signal while 
release the state
+                                               //
+                                       }
+                               }
+
+                               if (app.stop_processing) {
+                                       currentVal = true;
+                                       return true;
+                               }
+                               return false;
+                       }
+
+                       Delegate FindNextDelegate ()
+                       {
+                               switch(currentStep++) {
+                                       case  1: return app.BeginRequest;
+                                       case  2: return app.AuthenticateRequest;
+                                       case  3: return 
app.DefaultAuthentication;
+#if NET_2_0
+                                       case  4: return 
app.PostAuthenticateRequest;
+#endif
+                                       case  5: return app.AuthorizeRequest;
+#if NET_2_0
+                                       case  6: return 
app.PostAuthorizeRequest;
+#endif
+                                       case  7: return app.ResolveRequestCache;
+                                       case  8: return AllocateHandlerDel;
+#if NET_2_0
+                                       case  9: return 
app.PostResolveRequestCache;
+#endif
+#if NET_2_0
+                                       case 10: return 
app.PostMapRequestHandler;
+#endif
+                                       case 11: return app.AcquireRequestState;
+#if NET_2_0
+                                       case 12: return 
app.PostAcquireRequestState;
+#endif
+                                       case 13: return app.ResolveRequestCache;
+                                       case 14: return ProcessHandlerDel;
+                                       case 15: return ReleaseHandlerDel;
+#if NET_2_0
+                                       case 16: return 
app.PostReleaseRequestState;
+#endif
+                                       case 17: return app.UpdateRequestCache;
+#if NET_2_0
+                                       case 18: return 
app.PostUpdateRequestCache;
+#endif
+                                       case 19: pipelineFinished = true; 
return null;
+                               }
+                               return null;
+                       }
+
+                       public virtual bool MoveNext ()
+                       {
+                               while (!pipelineFinished) {
+                                       if (currentEnumerator != null && 
currentEnumerator.MoveNext())
+                                               return true;
+                                       currentEnumerator = null;
+
+                                       Delegate d = FindNextDelegate();
+                                       InternalStepDelegate d1 = d as 
InternalStepDelegate;
+                                       if (d1 != null) {
+                                               if (d1())
+                                                       return true;
+                                       }
+                                       else if (d != null)
+                                               currentEnumerator = 
app.RunHooks(d).GetEnumerator();
+                               }
+
+                               app.PipelineDone ();
+                               return false;
+                       }
+
+                       public virtual void Reset()
+                       {
+                               throw new 
NotImplementedException("HttpApplication.PipelineEnumerator.Reset called.");
+                       }
+               }
+
+               IEnumerator Pipeline ()
+               {
+                       return new PipeLineEnumerator(this);
+               }
+#else
                //
                // Events fired as described in `Http Runtime Support, 
HttpModules,
                // Handling Public Events'
@@ -882,14 +1200,12 @@

                        
                release:
                        if (ReleaseRequestState != null){
-#pragma warning disable 168
                                foreach (bool stop in RunHooks 
(ReleaseRequestState)){
                                        //
                                        // Ignore the stop signal while release 
the state
                                        //
                                        
                                }
-#pragma warning restore 168
                        }
                        
                        if (stop_processing)
@@ -912,6 +1228,7 @@

 #endif
                        PipelineDone ();
                }
+#endif
 
                void PreStart ()
                {
@@ -1016,12 +1333,15 @@

                        done.Reset ();
                        
                        begin_iar = new AsyncRequestState (done, cb, extraData);
-
+#if TARGET_J2EE
+                       Start (null);
+#else
                        if (Thread.CurrentThread.IsThreadPoolThread)
                                Start (null);
                        else
                                ThreadPool.QueueUserWorkItem (new WaitCallback 
(Start), null);
-                       
+#endif
+
                        return begin_iar;
                }
 
_______________________________________________
Mono-devel-list mailing list
[email protected]
http://lists.ximian.com/mailman/listinfo/mono-devel-list

Reply via email to