Flier's Sky

天空,蓝色的天空,眼睛看不到的东西,眼睛看得到的东西
posts - 115, comments - 295, trackbacks - 24, articles - 0

2008年1月23日

更新:程序员的思维模式都差不多,Kerem KusmezerJohn Robbin 发布了一个类似的工具.NET Mass Downloader。既然有的用我就不重新发明轮子了,下面那个项目停止维护,有需求的朋友直接用那个工具好了,具体使用说明可以参考


Download All the .NET Reference Source Code at Once with Net Mass Downloader

更新:在 sourceforge 上申请了一个项目,有兴趣的朋友可以上去下载代码,或者提交bug和改进建议。不过我估计也就年后才有时间继续处理,暂且挖个坑反正这里吧,呵呵

    从去年MS就开始喊着要开放.NET源代码,如今终于在一个含糊不清的授权协议下,通过Source Server的方式放了出来。虽然是如愿开源,但目前只提供几个核心模块,而且还限制必须在VS2008里面在线访问。
    其实既然决定开放,何必搞那么多限制出来,让偶等用着不爽还得自己动手丰衣足食,写个程序直接模拟VS2008获取源码的行为,一次性全部拖回来备用。
    空口无凭,上载一个
System.Xml 的源码包,和一个理论上能跑的程序原型,有兴趣的朋友可以试试。回头有时间了把相关代码整理一下再放出来,下面先大概说一下思路。

    首先,VS2008虽然要
打个补丁才能用源码调试,但这并不是下载源码的必要条件。MS发布源码所依赖的Source Server的机制,很早就通过 WinDbg 的发布包引入了。有兴趣的朋友可以使用 WinDbg 工具自己架设 Source Server,具体步骤请参考 %Debugging Tools for Windows%\sdk\srcsrv\ 目录下文档和脚本。
    而这个 Source Server 说白就是从 .pdb 调试符号文件里面,获取被绑定的已索引文件列表,然后根据系统_NT_SOURCE_PATH环境变量指定的服务器,拼接出一个 URL 然后通过http下载。具体这块的配置,可以参考
    Configuring Visual Studio to Debug .NET Framework Source Code
    讨厌的是MS在dbghelp.dll里面做了一些手脚,直接通过url去下载调试符号和源码是不被允许的。刚好scz前面研究过symbol server的行为,基本确定ms服务端是根据user agent来进行判断的。也就是说在发起请求时,把当前http的user agent改成ms认可的方式,就能够模拟dbghelp.dll通过srcsrv.dll完成的工作,具体代码类似

public const string DefaultUserAgent = "Microsoft-Symbol-Server/9.9.9.9 (C; V; ;)";

    
public void Restart(Uri uri)
    
{
      _request 
= (HttpWebRequest)WebRequest.Create(uri);
      _request.UserAgent 
= DefaultUserAgent;    

      IAsyncResult result 
= (IAsyncResult)_request.BeginGetResponse(
        
new AsyncCallback(ResponseCallback), this);
      ThreadPool.RegisterWaitForSingleObject(result.AsyncWaitHandle,
        
new WaitOrTimerCallback(TimeoutCallback), this, _timeout, true);      
    }
    另外一个罗嗦的事情,是每个链接建立后,MS服务器会先返回一个罗嗦的license声明,srcsrv.dll会弹出一个对话框让你Accept才能继续下载。
    例如你通过命令行去下载一个文件
wget  --user-agent=Microsoft-Symbol-Server/9.9.9.9
    Http:
//ReferenceSource.microsoft.com/source/.net/8.0/DEVDIV/
    depot
/DevDiv/releases/whidbey/REDBITS/ndp/fx/src/Misc/
   
InvariantComparer.cs/1/InvariantComparer.cs
    会直接返回一对垃圾信息,类似
SYMSRVCOMMAND:
YESNODIALOG:
IDYES:Accept:Accept=0cf80f849aa7449e9d064ade971bd887
IDNO:Decline:Decline=0cf80f849aa7449e9d064ade971bd887
TITLE:End User License Agreement
BUTTONDESCRIPTION:Please read carefully and understand the license agreement above. 
If you want to accept the license agreement, please click the “Accept” button.
TEXT:This license applies to the .NET Framework components that Microsoft makes available to you
in source code form.  To print these terms, select the contents of this area and copy then paste
into an application that can print text.

MICROSOFT .NET FRAMEWORK REFERENCE LICENSE
.NET FRAMEWORK REFERENCE SOURCE CODE


This license governs use of the accompanying software. If you use the software, you accept this license.
If you do not accept the license, do not use the software.
1. Definitions
The terms "reproduce," "reproduction" and "distribution" have the same meaning here as under U.S. copyright law.
 


    解决方法很简单,直接用正则表达式找到里面一个随机生成的id,然后程序自动Accept即可,代码类似
    private static Regex _accept = new Regex(@"IDYES:Accept:Accept=(\w*)");

          
if (task._auth)
          
{
          }

          
else
          
{
            
string license = Encoding.Unicode.GetString(task._buf, 0, read);

            Match m 
= _accept.Match(license);

            
if (m.Success)
            
{

              task._auth 
= true;

              
string id = m.Groups[1].Value;

              _logger.DebugFormat(
"Accept license id {0} for {1}", id, task._request.Address);

              Uri uri 
= new Uri(string.Format("{0}?Accept={1}", task._uri.ToString(), id));

              task.Restart(uri);
            }

          }

其他的基本上没什么需要说明的,就是很基本的http请求调用啥的,呵呵

至于从.pdb里面获取文件名列表,需要调用dbghelp.dll里面的一组api
SymInitializeW/SymCleanup用来初始化和析构symbol engine
SymLoadModuleExW/SymUnloadModule64用来加载要便利源代码的模块
SymEnumSourceFilesW用来遍历一个有.pdb符号且包含已索引源码的列表
SymGetSourceFileW和SymGetSourceFileTokenW/SymGetSourceFileFromToken两套API,都可以用来获得特定源码的下载URL,然后把这个地址用上面两个方法处理一下即可。

注意:目前的实现只是个原型,需要手动下载和配置.pdb文件,并且直接发起大量的异步http请求,对网速慢的朋友,可能需要用 -i 参数增加超时时间(确实15分钟)


   
   
 

posted @ 2008-01-23 02:50 Flier Lu 阅读(4511) | 评论 (21)编辑

2006年2月19日

     摘要: 原文:http://www.blogcn.com/User8/flier_lu/blog/29042138.html1.3 局部重绘模式的服务器端响应在第一小节中,我们曾提到 ScriptManager 在重载的 Web.UI.Control.OnInit 事件中,会根据页面请求中 delta = true 是否存在,判断当前页面是否处于局部重绘模式中,并接管 LoadComplete 时间来处理... 阅读全文

posted @ 2006-02-19 23:40 Flier Lu 阅读(5144) | 评论 (7)编辑

2006年2月18日

     摘要: 原文:http://www.blogcn.com/User8/flier_lu/blog/28981917.html1.2UpdatePanel与局部重绘模式(PartialRenderingMode)在上一节介绍Altas整体结构时曾经提到,可以在启用局部重绘模式的情况下,通过通过<altas:UpdatePanel.../>标签定义需要异步更新的范围。我们知道,传统的HTTP协议应... 阅读全文

posted @ 2006-02-18 00:49 Flier Lu 阅读(4530) | 评论 (4)编辑

2006年2月17日

     摘要: 原文:http://www.blogcn.com/User8/flier_lu/blog/28949768.html[0]概述上周MS发布了面向ASP.NET的AJAX框架——Atlas最新CTP2006.1预览版,ScottGu在其blog上做了较为详细的介绍。NewAtlasBuildAvailableforDownloadwithASP.NET2.0更详细的更新说明,可以参考nikhilk的... 阅读全文

posted @ 2006-02-17 00:16 Flier Lu 阅读(5565) | 评论 (11)编辑

2005年12月30日

     摘要: 原文:http://www.blogcn.com/User8/flier_lu/blog/27498923.html.NET2.0在底层实现上的一个非常重要的改进,是在引入了ExecutionContext的概念。从而引入了一个类似COM中套间(Apartment)概念的一个逻辑上的执行环境。这在很大程度上改变了.NET1.x中对线程以及其执行环境的管理机制,并进而可以实现非常灵活的控制机制。因为... 阅读全文

posted @ 2005-12-30 01:36 Flier Lu 阅读(3360) | 评论 (2)编辑

2005年12月27日

     摘要: 原文:http://www.blogcn.com//User8/flier_lu/blog/27401974.html与ASP.NET1.0相比,ASP.NET2.0的各方面改进可以说是非常巨大的。但就其实现层面来说,最大的增强莫过于提供了对异步页面的支持。通过此机制,编写良好的页面可以将数据库、WebService调用等慢速操作,对网站吞吐能力的影响降到最低,并极大的改善网站的平均页面响应速度。... 阅读全文

posted @ 2005-12-27 00:28 Flier Lu 阅读(8703) | 评论 (10)编辑

2005年11月20日

    前两个月大概翻过应用框架的设计与实现——.NET平台一书,也曾在MSN space上发过一个简短的书评。因为刚刚看到某人的一篇书评,感觉赞誉太过。于是把以前的书评翻出来转贴一下,如有观点过于偏激权且博大家一笑。

http://spaces.msn.com/members/flierlu/Blog/cns!1pQ1oe7hJhEc4MgjNgGwRvvA!153.entry

9月18日



《应用框架的设计与实现——.NET平台》


    用一周左右时间零零碎碎抽空把应用框架的设计与实现——.NET平台一书翻了一遍,感觉作者 Xin Chen 的确有一些自己的想法,但有些问题并没有想的非常明白。在应用框架的层面来说,书中涉及的范围基本上是较为全面的,但就如其示例实现 SAF (Simplified Application Framework) 的名字一样,有些问题的思考和解决方法过于简单。

 
    从全书的整体布局来说,首先是作者的全局理解不错,前三章对应用框架的分析和理解大部分还是很到位的。相对很多上来就大谈实现技术的所谓企业级开发书籍来 说,能想到并且言之有物的将 blueprint 先说明白,说明作者在整体框架的发展上有过较多的思考。而实际上这个层面的思考,是 Windows 平台下企业级开发所最为欠缺的。而从第4章到第15章,每章介绍一个框架的主要构成部分,先原理后实现还是挺不错的,最起码能够浅显易懂,呵呵。不过个人 感觉对基础性支持介绍的太多了,不如改为结合实际项目的应用场景分析。毕竟能有目的性看这种书籍的读者,大部分都不会存在技术性知识的缺乏。也不知是否书 籍定位的问题,感觉很多问题作者是想到但并没有讲明白,给出的解决方法也仅仅停留在思路层面,很多地方缺乏实用性和完整性。
    第4章介绍类工厂服务,给出一个基于 reflection 机制的可配置类工厂实现思路。不过居然没有提及任何 IoC 方面的知识,真难以想象这是一本2004年才出版的书。毕竟将构建对象与使用对象解耦,只是容器最基本的一个层面的功能,更高层面的对象依赖关系管理、配置管理、AOP 支持以及服务生命期管理等等,才是一个真正的企业级容器所必须的。
    第5章介绍缓存服务,给出一个基于 hashtable 的缓存实现思路。值得肯定的是明确提出了存储策略的引入,这为平滑支持基于外部存储和基于cluster 的缓存提供了思路,实际上 Java 阵营的大部分 Cache 实现也是类似。亮点是采用 XML DOM 树作为 key 的存储机制的思路,通过 xpath 来定位存储内容,相对于平面的基于 key 对象自身可比较性的思路,有着其特有的易用性。可惜给出的参考实现只能用简陋来形容,作为学习用的范例还凑合。
    第6章介绍配置服务,基本上就是基于 CLR 现有配置架构,没有太多新意。直接用 Enterpise Library 的相关 Block 是更好的选择。感觉 windows 平台的开发者在 XML 处理方面的思路太僵化了,来来去去都是 MS 那套机制,不像 Java 阵营百花齐放,digester 与 xstream 齐飞,不同模式让人有选择余地。
    第7章介绍事件通知服务,给出一个集中事件分发服务的雏形。这块对事件分发和异步执行的好多想法很不错,但实现的方式太简单了。虽然统一的中间服务简化编 程模型,但在参数传递、传送拓扑、底层协议等等很多方面受限。某些时候网状拓扑比这种星状拓扑的灵活性更大,或者基于总线的思路也更先进。这方面 ESB 的思路应该是大势所趋,MS 方面就看 Indigo 的本事了。
    第8章介绍 Windows 服务,说白了就是用一个 Windows Service 做容器来运行任务。能明确提出这一点来,可以说作者对如何将应用框架与 Windows 平台结合做过一些思考,可惜仅仅在这儿有所体现,而可以做努力的方向还很多。而且其对服务支持仅仅停留在运行容器支持层面,基本上没有考虑如何在服务与服务之间、服务与使用者之间,提供无缝交互的支持,而隔离的服务对于框架来说是孤立的。
    第9章介绍消息队列服务,基本上就是对 MSMQ 和 MQSeries 的简单封装。如果能够考虑消息路由、同步模式等等高级特性,可能会更加实用一些。这一章实际上可以跟事件通知服务合并到一起,毕竟他们是为了解决类似的问题,不应该仅仅以实现技术来划分。
    第10、11、12章介绍授权、身份验证、加密服务,基本上就是对 CLR 现有机制的包装和整理。亮点是明确提出应该将授权等定义与具体代码实现分离,并给出一个简单但可用的实现。真不明白这么简单的一个道理,为什么 MS 到现在就是不明白 :S 此外这儿单独提出了对身份扮演的支持,但在与架构一级的整合上力度不够,仅仅给出实现一级的方法。
    第13章介绍事件服务,主要包括如何通过 COM+/DTC 使用分布式事务。亮点是明确提出抽取独立调度类提供 COM+ 事务与隔离性支持,避免在实现代码一级静态定义。不过作者似乎对 COM+ 1.5 不是太熟悉,居然没有用新增的服务域的特性。而且他在抽取事务与隔离性支持时,使用了设计上巨龌龊的枚举组合方法,用 4x5=20 个服务类来表示所有组合。其实完全可以通过动态类生成方式,提供更为幽雅的实现。而且事务的定义,也应该有相应的配置文件级支持,作者好像把这块也忽略掉了,而前面几个模块缺都有,真是奇怪。
    第14、15章介绍文档层和工作流服务,基本上就只是简单介绍了一下概念,感觉是敷衍了事 :S 而且两章罗罗嗦嗦说了半天,说白了都是用的责任链的模式,还挂着个工作流的羊头。估计可能是因为作者有 biztalk 的背景,这部分大部分工作用现成工具完成了吧。
    总体来说此书还是一本非常值得一读的入门级应用框架设计书籍,能够非常清晰明确的提出问题并给出简单的参考实现,但在问题思考的深度、广度,以及解决方法的时效性和先进性方面,只能说是一般而已。相对于 SpringFramework 作者那两本重量级作品,此书也就是大概翻翻就行了。

posted @ 2005-11-20 16:11 Flier Lu 阅读(2050) | 评论 (3)编辑

2005年8月28日

原文:http://www.blogcn.com/User8/flier_lu/blog/24143356.html

    Yun Jin 的 blog 上最近有两篇有趣的文章,介绍了 CLR 中线程概念的内部实现以及缺省提供的特殊线程。
    
    Thread, System.Threading.Thread, and !Threads (I)
    Special threads in CLR
    
    其中提到 EE 在启动时会初始化一个专用的调试线程。

2. Debugger helper thread. As its name suggests, this thread helps interop debugger to get information of the managed process and to execute certain debugging operations. The thread is created when EE initializes debugger during start up. In Rotor, the thread proc for this thread is DebuggerRCThread::ThreadProcStatic (debug\ee\Rcthread.cpp). Also see Mike Stall's blog about impact of this helper thread。    

    与传统的 Native Win32 程序不同,CLR 对调试的支持是通过 In-Proc 模式提供的。Mike Stall 在其 blog 上介绍了这种模式的优劣:
    
     Implications of using a helper thread for debugging
    
    首先,我们来看看运行时的调试支持情况。
    
    用 windbg 启动一个 CLR 程序后,可以用 ~ 命令和 sos 的 ~threads 命令,看看 Native 线程和 CLR 线程的对应情况如下:

0:003> ~
   0  Id: 1040.1fbc Suspend: 1 Teb: 7ffdd000 Unfrozen
   1  Id: 1040.1fc4 Suspend: 1 Teb: 7ffdc000 Unfrozen
   2  Id: 1040.1e64 Suspend: 1 Teb: 7ffdb000 Unfrozen
.  3  Id: 1040.1e14 Suspend: 1 Teb: 7ffda000 Unfrozen

0:003> !threads
ThreadCount: 2
UnstartedThread: 0
BackgroundThread: 1
PendingThread: 0
DeadThread: 0
                             PreEmptive   GC Alloc               Lock     
       ID ThreadOBJ    State     GC       Context       Domain   Count APT Exception
  0  1fbc 0015e890      6020 Enabled  00bfe82c:00bffff4 00158ef8     0 STA
  2  1e64 00151530      b220 Enabled  00000000:00000000 00158ef8     0 MTA (Finalizer)
    
    可以看到正如 Yun Jin 所说,除了与主线程 (ID:1fbc) 和 Finalizer 线程 (ID:1e64) 对应的 Native 线程外,还有两个 (ID: 1fc4, 1e14) Native 线程。
用 ~* 命令查看线程的详细情况如下:

0:003> ~*
   0  Id: 1040.1fbc Suspend: 1 Teb: 7ffdd000 Unfrozen
      Start: *** WARNING: Unable to verify checksum for image00400000
*** ERROR: Module load completed but symbols could not be loaded for image00400000
image00400000+0x61de (004061de) 
      Priority: 0  Priority class: 32
   1  Id: 1040.1fc4 Suspend: 1 Teb: 7ffdc000 Unfrozen
      Start: KERNEL32!BaseThreadStartThunk (7c82b5bb) 
      Priority: 0  Priority class: 32
   2  Id: 1040.1e64 Suspend: 1 Teb: 7ffdb000 Unfrozen
      Start: KERNEL32!BaseThreadStartThunk (7c82b5bb) 
      Priority: 2  Priority class: 32
.  3  Id: 1040.1e14 Suspend: 1 Teb: 7ffda000 Unfrozen
      Start: ntdll!DbgUiRemoteBreakin (7c975e73) 
      Priority: 0  Priority class: 32


      其中线程 (ID: 1e14) 是 WinDbg 调试用,可以暂且不记。另外一个线程 (ID: 1fc4) 就是我们的目标:调试支持线程。用 sysinternals 的 Process Explorer 可以查看其运行时堆栈如下:

...
KERNEL32.dll!WaitForMultipleObjects+0x18
mscorwks.dll!DebuggerRCThread::MainLoop+0x90
mscorwks.dll!DebuggerRCThread::ThreadProc+0x68
mscorwks.dll!DebuggerRCThread::ThreadProcStatic+0xb
KERNEL32.dll!BaseThreadStart+0x34

      在大致了解了其运行时状况后,我们来看看实际的实现方法。

      在 《用WinDbg探索CLR世界 [2] 线程》 一文中曾介绍过 CLR 初始化 EE (Execute Engine) 的步骤。通过 CoInitializeEE -> TryEEStartup -> EEStartup 的调用,最终由 EEStartup 函数 (vm\ceemain.cpp:206) 完成实际的初始化工作。
EEStartup 函数会在完成最基本的初始化工作,如启动 IPC 引擎后;在建立任何 EE 线程之前,初始化调试服务:
#ifdef DEBUGGING_SUPPORTED
    
// This must be done before initializing the debugger services so that
    
// if the client chooses to attach the debugger that it gets in there
    
// in time for the initialization of the debugger services to
    
// recognize that someone is already trying to attach and get everything
    
// to work accordingly.
    IfFailGo(NotifyService());

    
//
    
// Initialize the debugging services. This must be done before any
    
// EE thread objects are created, and before any classes or
    
// modules are loaded.
    
//
    hr = InitializeDebugger();
    _ASSERTE(SUCCEEDED(hr));
    IfFailGo(hr);
#endif // DEBUGGING_SUPPORTED

      因为 CLR 的调试支持依赖于基于 IPC 的 Notify 机制,因此在初始化调试支持之前,需要先完成对 IPC 和 Notify 服务的支持。
Notify 服务本质上就是一块全局的共享内存块,其 Section 在 Rotor 中名称为 ROTORSvcEventQueue,在 .NET 1.1 中名称为 CORSvcEventQueue。通过这块共享内存,CLR 会维护一个 ServiceEventBlock 类 (clr/src/inc/corsvcpriv.h:70),提供跨进程一级的消息队列机制。这个内存块会由一个独立的服务进程维护,负责对 CLR 启动和服务停止等事件进行分发。如果此全局服务存在,NotifyService 函数会在队列中现有事件已经分发完毕后,构造一个类型为 runtimeStarted 的 ServiceEvent 提交给它,以通告 CLR 正在启动。通过这个机制可以完成一些非常有趣的功能,但因为不涉及此次讨论的主体,暂且放下回头有空专门写文章讨论。

      负责初始化调试器支持的 InitializeDebugger 函数 (vm/ceemain.cpp:1868) 主要负责构造调试器对象和初始化调试器接口。InitializeDebugger 函数及其相关伪代码如下:
//
// InitializeDebugger initialized the Runtime-side COM+ Debugging Services
//
static HRESULT InitializeDebugger(void)
{
  
// 构造面向外部调试器的 EE 调试接口
  EEDbgInterfaceImpl::Init();

// 构造调试器 Debugger 类实例
if (SUCCEEDED(CorDBGetInterface(&g_pDebugInterface)))
{
  g_pDebugInterface
->SetEEInterface(g_pEEDbgInterfaceImpl);
  
  
// 启动调试器
  if (SUCCEEDED(g_pDebugInterface->Startup()))
  
{
      
// 如果使用调试器线程控制接口,则更新特殊线程列表
      if (CorHost::GetDebuggerThreadControl())
      
{
        CorHost::RefreshDebuggerSpecialThreadList();
      }

  }

}


  
if (IDebuggerThreadControl *pDTC = CorHost::GetDebuggerThreadControl())
    g_pDebugInterface
->SetIDbgThreadControl(pDTC);
}


FORCEINLINE 
void EEDbgInterfaceImpl::Init(void)
{
    g_pEEDbgInterfaceImpl 
= new EEDbgInterfaceImpl();
}


HRESULT __cdecl CorDBGetInterface(DebugInterface
** rcInterface)
{
  HRESULT hr 
= S_OK;
 
if (rcInterface != NULL)
{
  
if (g_pDebugger == NULL)
  
{
    g_pDebugger 
= new Debugger();
    
if (g_pDebugger == NULL) 
hr 
= E_OUTOFMEMORY;
  }

  
*rcInterface = g_pDebugger;
}

return hr;
}


      首先调用 EEDbgInterfaceImpl::Init 函数 (vm/eedbginterfaceimpl.h:53) 构造面向外部调试器的 EE 调试接口,并存储在全局变量 g_pEEDbgInterfaceImpl 中。
然后调用 CorDBGetInterface 函数 (debug/ee/debugger.cpp:130) 构造调试器 Debugger 类 (debug/ee/debugger.h:631) 的实例,并存储于全局变量 g_pDebugger 中。而 CLR 内部则通过通用保存全局变量 g_pDebugInterface 中的 DebugInterface 抽象类 (vm/dbginterface.h:34) 的指针使用此实例。
最后在 Debugger 构造成功后,调用其 Startup 方法启动调试器。

      如果使用者通过 CLR 的 Host API 接口 ICorRuntimeHost,获取配置接口 ICorConfiguration,并设置调试线程控制接口 IDebuggerThreadControl,则 InitializeDebugger 函数还需要针对此接口做特殊处理。
主要工作包括调用 CorHost::RefreshDebuggerSpecialThreadList 函数 (vm/corhost.cpp:654) 更新特殊线程列表,避免调试器针对这些线程进行处理,不过貌似没有直接使用到此机制。

      通过上面的分析我们可以知道,CLR 的调试支持机制实际上是分为两个层面的。

      EEDbgInterfaceImpl 通过 facade 模式,将 EE 内部对调试所需功能的支持集成到一个 EEDebugInterface 接口 (vm/eedbginterface.h:55)。
      Debugger 则通过实现 DebugInterface 抽象类的功能,将 ICorDebugInfo 接口 (inc/corinfo.h:1168) 暴露给最终的调试功能使用者。

      EEDbgInterfaceImpl 的实现基本上是对 EE 内部对象和功能的调用,自身没有数据,因此这儿暂时不讨论。
Debugger 则负责向外部调试机制使用者提供接口,其 Debugger::Startup 方法 (debug/ee/debugger.cpp:513) 完成对调试环境的启动工作。
      Debugger::Startup 方法的主要工作包括:

      1.初始化多线程安全的调试堆
      2.建立、初始化并启动调试控制线程 DebuggerRCThread
      3.创建一组调试用 Event/Mutex 内核对象
      4.创建并初始化用于枚举 appdomain 的 IPC 共享内存控制块

      此外对于在调试器中启动 CLR 的情况,将做特殊处理。

      伪代码大致如下:

      对 Debugger 对象的调试堆来说,功能上就是为基础的 gmallocHeap 堆,增加了多线程安全的线程同步支持,避免因为并行使用调试接口造成内存分派上的问题。而 debugger.h 中通过重新定义全局 new/delete 操作符的方式,将 DebuggerRCThread 等对象创建的内存分派,都接管到调试堆中。代码如下:
class InteropSafe {};
#define interopsafe (*(InteropSafe*)NULL)
        
static inline void * __cdecl operator new(size_t n, const InteropSafe&[img]/images/wink.gif[/img]
{
    _ASSERTE(g_pDebugger 
!= NULL);
    _ASSERTE(g_pDebugger
->m_heap != NULL);
    
    
return g_pDebugger->m_heap->Alloc(n);
}


//  其他对应的 new[], delete, delete[] 操作符重载
      创建的调试用内核对象基本上是为 CLR 和调试接口各准备了一套,其中面向调试接口的一套内核对象,命名方式遵循 "CorDB + IPC + 对象名 + _ + 进程 ID" 的模式,并且将其安全属性通过 IPCManager 设置为只有同一帐号才能进行控制。如果在 Rotor 下则前缀 CorDB 改为 RotorDB,如:
#define CorDBIPCSetupSyncEventName L"Global\\RotorDBIPCSetupSyncEvent_%d"
#define CorDBIPCLSEventAvailName   L"Global\\RotorDBIPCLSEventAvailName_%d"
#define CorDBIPCLSEventReadName    L"Global\\RotorDBIPCLSEventReadName_%d"
#define CorDBDebuggerAttachedEvent L"Global\\RotorDBDebuggerAttachedEvent_%d"
      通过分析上述代码可以知道,CLR 的调试支持机制,实际上在运行时是由进程内的 DebuggerRCThread 线程,与进程外的调试器线程,通过一组 CorDBIPCxxx_xxx 事件进行通讯来完成的。就好比在调试支持初始化并启动后,如果 CLR 在调试器中启动,则触发 m_debuggerAttachedEvent 来通知调试器可以进行调试。这种机制与 Native WIN32 API 的调试支持机制基本相同,都是基于事件的触发调试模型。只不过 Native 的调试器是由内核一级的调试子系统来完成事件的分发和处理工作,而 CLR 因为不希望涉及内核态操作,自行通过调试控制线程完成类似的机制。因此我们如果希望进一步深入了解调试支持,就可以简化为对调试事件的支持与分析。

      而调试支持线程 DebuggerRCThread 的构造与初始化,基本上就是对其内部结构的处理。其中值得注意的是调试控制线程中,为 InProc/OutOfProc 两部分调试支持机制,各维护了一个 DebuggerIPCControlBlock 控制块结构,并维护了各部分的调试相关基础信息。对 InProc 这部分的信息,Init 方法会自行初始化;而 OutOfProc 部分的信息,则通过 IPCManager,在调试器 attach 的时候从外部进程获取。

      这一小节我们了解了 CLR 调试支持机制的整体结构,下一节我们继续分析调试支持线程是如何处理各种相关事件的。

to be continue...

posted @ 2005-08-28 22:15 Flier Lu 阅读(3683) | 评论 (10)编辑

2005年8月24日

http://spaces.msn.com/members/flierlu/Blog/cns!1pQ1oe7hJhEc4MgjNgGwRvvA!138.entry


    如果让我推荐学习 Java 语言的书单,除了面向初学者的 Thinking in Java 和面向进阶者的 Inside JVM 之外,现在又可以增加一本面向执着者的 Java Rules
 

 
    虽然相对枯燥的第 1 章曾让我一度放下此书改看其他书籍,但在读完第 2, 3 章后我就确信,此书绝对是属于那种可以看两遍以上的书籍。虽然就内容来说,总共 6 章的内容看起来并不多,而且其中有 3 章近 330 页,用来介绍其他书籍里面几乎不屑于详细讨论的基础内容。([4] 原始数据类型和 Object 类、[5] 字符串和其他通用类型、[6] 数组和集合框架)但其内容所涉及技术的深度和广度,绝对是绝大多数所谓“编程”书籍无法比拟的。
    举个最简单的例子,在第 2 章 编译单元 的讨论中,作者花了 8 页 16 面纸的篇幅,用来讨论包引用中的 import 语句。而且介绍内容绝对是言之有物、条理清晰,对技术的介绍则是旁征博引、触类旁通。
    此书的定位是介于 JLS (Java Language Specification) 和语法书籍之间,从语言设计的角度来展示 JVM 的细节,是阅读前面提到两本书籍后,最合适的黏合剂。可以让读者将 Java 语法和 JVM 实现,通过语言设计和实现的细节,有机的将知识联系到一起。美中不足的是文风有时过于学术化,好些句子绕来绕去让你看不真切。不过也可能是翻译水平问题导致,回头弄本原版的来比对一下。
    不过相对于普通的阅读者,这个层面的讨论似乎过于繁琐和细致,因而我将之规类为面向执着者的书籍,呵呵。好在偶连 JLS 语言规范都硬着头皮啃过,看起这个来还不算太吃力,而且经常有意外的收获,非常过瘾 :D
    而就翻译质量来说,javaresearch.org 这个组织还算不错,基本上中规中矩,没发现什么太大的纰漏。也好歹没把书名改成个诸如《xxx 深入浅出》、《xxx 技术内幕》或者《Java 和 xxx 不得不说的故事》之类 BT 的名字,原汁原味算是积德了。此外这个组织翻译的 Concurrent Programming in Java 一书也是非常不错。

posted @ 2005-08-24 22:55 Flier Lu 阅读(1159) | 评论 (1)编辑

2005年8月21日

http://spaces.msn.com/members/flierlu/Blog/cns!1pQ1oe7hJhEc4MgjNgGwRvvA!131.entry

    《Enterprise Services with the .NET Framework》一书实际上漏掉了一个非常重要的议题,那就是对企业级服务自身的可管理性支持。JSE 5 中一个非常重要的改进,就是直接集成了对 JMX 标准的支持,这一特性的运用能大大增强服务的可用性。JBoss 的设计人员就曾评价说,JBoss 4 之所以能够成功,很大程度上依赖于基于 JMX 的微内核结构的设计,而 JMX 在 JBoss 实现上也起到了事实上的服务容器与管理机制的作用。虽然普通的企业级应用,没有必要灵活到全部通过 JMX 类似的机制管理,但基于 JMX 机制提供服务自身的监控和管理支持确实非常必要的选择。而 Java 阵营的绝大多数引擎和服务,都陆续提供了 JMX 支持和集成;MS 自身的几乎所有服务器端产品,也都内嵌了 WMI 和性能监视器的支持。
    Windows 平台下与 JMX 对应的是 WMI 架构,它在底层通过类似 SNMP MIB 表的机制定义自己的 Metadata 模型,在上层则通过类似 LDAP 的机制提供访问和查询。并且也提供了非常灵活的事件通知机制,以及各种辅助开发工具。
    WMI 的概念和应用可以参考:
 
 
    .NET 在这方面提供了非常易于使用的封装和支持
 
 
    不过 WMI 在针对分布式系统的监控上,相对于 JMX 缺乏良好的支持。不知是不是因为 MS 将这块的特性,准备放到单独的 MOM ( Microsoft Operations Manager ) 产品中销售,因此故意不去增加支持 :S
 
 
    不过总体上 MS 给人的感觉是,在企业级应用层面想的不太明白,往往看到 JEE 阵营有什么好东东,就抄过来实现之。但却始终没有想明白一个问题,有功能和能将功能用起来,对于企业级应用来说是完全两码事。毕竟指望每个 MS 架构下的设计师都通晓其所有的技术,这本身就不太现实。而通过种种看似方便,实际上分散且繁琐的封装和工具,虽然可以缓解这一问题,但长期来说只会导致大家都偷懒用缺省配置,虽然效率低但好歹能工作,知其然而不知其所以然。Windows 下的企业级应用,从 DNA 开始扯到现在,仍是个半死不活的状况(起码就国内来说如此),MS 应该好好检讨一下自己的相关策略了。

posted @ 2005-08-21 11:29 Flier Lu 阅读(1127) | 评论 (3)编辑