为何IOCP能够同时处理成千上万个连接???(20分)

  • 主题发起人 主题发起人 mill666
  • 开始时间 开始时间
我为什么骂那么多人,因为他们是高手,他们不知道自己的表率作用,就妄称高手。国外的新技术我经常追踪,这些东西都是学者研究的心血,但是语言障碍让我们的系统无法最快速的用上这些技术。微软在欺骗大家,在掩饰很多东西,看似搭积木的编程越来越轻松,但是我们的产业被破坏了,很多人看了入门的书就进来,结果800元的程序员都出现在Delphi开发群里面,国外系统内核高手好多,微软在国外不讨好的,但是在这里被当作了神,当作了万能。

哪些新技术?学术上研究的新技术很多是理论而已,你说说一些新技术,我英语还可以,你可以说一下让我利用一下。国内系统内核高手也不少,驱动开发网在国外也相当有名气的,我有一朋友出国后跟我讲,其实国外也没多少人用LINUX...绝大部分还是WINDOWS。linux还是被一些大厂商忽悠起来的,让我们觉得这个产业链好大,其实没啥实际东东。
 
这么多手机用的啥子系统-linux,
这么多网站用的啥子系统-linux,
这么多网络防火墙用的啥子系统-linux,
这么多高级交换机用的啥子系统-linux,
你每天搜索的google用的啥子系统-linux,
美国新出厂的机器会装一个叫做TrueImage的备份系统,用的啥子系统-linux,
我给国内的几个品牌机开发的一键还原用的啥子系统-linux,卖的还不少呢,嘿嘿。

还咱们的军队,飞机,大炮,导弹,雷达,导航系统.....,没有linux,咱可怜的龙芯阿.....,不说了,要被骂了。
 
强帖强人。。。按照我理解,完成端口叫是完成队列或者结果流水线更加合适。
降低了线程的切换也是绝对正确的原因之一,完成端口的长处不是大数据流量而是大连接数量。采用完成端口可以使你同时处理上万的连接,但是不可能使单个连接的速度提高1%。
当然只是之一。采用完成端口还避免了其它的开销,CPU的占用并不是因为数据流量大,而是因为数据包流量大。没记错的话,tcp是属于传输层的,那么我们写的驱动是属于哪个层呢?我是菜菜,表骂我。
我说硬件的功能是我在几年前接触过一种网卡,是原adaptec的几个核心出来搞的(好象现在又被收购去了)。卡上带cpu和几M的内存,一个卡卖900$。应邀请从hk跑到公司搞了个讲座又给了我2块测试。这个卡安了硬件驱动后,在使用巨帧情况下,确实比当时任何一个intel的服务器网卡快60%以上。这个卡利用板上硬件实现了tcp/ip协议栈,如果这个时候自己跑去再搞个驱动是不是有点傻?现在这种卡越来越多了,貌似目前的桌面级千兆也慢慢开始实现了部分toe能力。
 
sevencat是savetime吧
王府井是谁呢,是不是章元庆呢!?
 
自己写驱动的话,直接用tdi层,其实比winsock2相比就是少经过几个调用层次,不过好像缓冲是放在afd.sys,直接用tcpip.sys会不会有什么影响。afd.sys的代码我并没有仔细看过,不是很清楚。

完成端口其实是跟网络编程没啥关系的,他只是导出了系统接口_KQUEUE,
KeInitializeQueue
The KeInitializeQueue routine initializes a queue object on which threads can wait for entries.
VOID KeInitializeQueue(IN PKQUEUE Queue,IN ULONG Count OPTIONAL);
创建一个完成端口就相当于创建一个这样的东东,至于这个东东,开发过驱动的应该知道的。
Usually the caller of KeInitializeQueue also creates a set of dedicated threads to queue and dequeue its entries. Such a caller can specify an explicit Count to prevent too many of its dedicated threads from waiting concurrently on its queue object.

KeInitializeQueue sets the queue object's initial signal state to Not Signaled.

For more information on using driver-managed internal queues, see Driver-Managed Queues in the DDK Kernel-Mode Driver Architecture Reference.

Callers of KeInitializeQueue must be running at IRQL <= DISPATCH_LEVEL.

从完成端口移除一条消息用的
PLIST_ENTRY KeRemoveQueue(IN PKQUEUE Queue,IN KPROCESSOR_MODE WaitMode,IN PLARGE_INTEGER Timeout OPTIONAL);

插一条东东到完成端口就是调用这个(无论是异步操作完成后系统插还是你用Post自己插):
LONG KeInsertQueue(IN PKQUEUE Queue,IN PLIST_ENTRY Entry);

其实事情就是这么简单,理解了kqueue就理解了完成端口。
 
要效率最高,以前我们公司总部在网卡上做VOD系统。把文件系统也做在网卡上,然后所有的东东就是从网卡直接走掉。(流量大得吓人呢)

但我们公司在其他的很多相关应用中也用的是j2ee,ftp服务器,http服务器。

王府井不用在这里吓人了,以为说大话就能吓得住人啊。不要老吹什么开发操作系统这些鬼话了,对外吹吹无妨,以前我们对外也说自己的防火墙是自主研发自主操作系统的硬件防火墙的。从你的贴子就能看出你的水平的,不要用代码来掩饰自己的无知了,
这年头,这个行业混久了,谁手头上没有一大套代码啊。

在ring0写网络,木马或者一些系统级的用用还无妨,其他地方用没啥必要,真正要处理大流量的数据(像路由器之类的),直接用单片机来实现了。
 
爱元元的哥哥:完成端口是微软APC思想的最好体现,all right!

从设计角度来看:完成端口是一个 NT 执行子系统的核心对象。通过将完成端口与任意个 I/O 句柄(文件或Socket等)关联,使得用户可以通过完成端口这一统一途径,异步的获取并处理 I/O 操作的结果,同时能够最大限度利用多 CPU 的优势。而且因为完成端口实际上是 NT 系统很多底层机制如 APC 的实现手段,故而在效率上是最高的,因为绝大多数其他类似解决方法最终还是使用完成端口实现。与 WaitForMultipleObjects 函数不同,完成端口是由系统直接提供并行优化支持的,通过建立完成端口时指定的并行线程值,系统可以保证工作在同一完成端口上的线程数量受控(一般等于系统CPU数量),这样就可以避免无意义的线程上下文切换,获取更高的性能。

我的比喻:完成端口是微软在网络系统上的DirectX,vista直接用directx来代替GDI了。

源代码分析:
CreateIoCompletionPort 函数在 ExistingCompletionPort 参数为空的时候调用 NtCreateIoCompletion 函数创建一个新的完成端口对象;然后处理 FileHandle 参数为 INVALID_HANDLE_VALUE 时的情况;最后调用 NtSetInformationFile 函数试图将 I/O 句柄绑定到完成端口上。

CloseHandle 在处理完成端口时则直接调用 IopDeleteIoCompletion 函数。而 GetQueuedCompletionStatus 函数和 PostQueuedCompletionStatus 函数,则分别是 NtRemoveIoCompletion 函数和 NtSetIoCompletion 函数的简单包装。

从实现角度来看,完成端口实际上是一个 IoCompletionObjectType 类型的内核对象,其对象体就是一个 KQUEUE 结构维护的内核队列。NtCreateIoCompletion 函数只是简单地构造并初始化这个内核对象。首先对来自用户态的调用验证 IoCompletionHandle 参数指向内存可写;然后调用 ObCreateObject 函数构造内核对象;如果成功则调用KeInitializeQueue 函数初始化内核队列;并且调用 ObInsertObject 函数将内核对象加入到当前进程的句柄表中;最后将构造的内核对象的句柄返回给调用者。

系统还提供了一个相应的 NtOpenIoCompletion 函数支持打开已经建立的有名字的完成端口。其调用 ObOpenObjectByName 函数完成名字到内核对象的映射,并最终将完成端口对象句柄返回给调用者。

在建立了完成端口对象后,可以通过 NtQueryIoCompletion 函数(iocomplete.c:282)查询此完成端口队列中阻塞的 I/O 完成包的数量。此函数实际上是对读取内核队列状态 KeReadStateQueue 函数(kequeueobj.c:92)的封装,从 KQUEUE::Header::SignalState 字段读取完成端口内部使用的内核队列对象的阻塞深度。

NtRemoveIoCompletion 函数和 NtSetIoCompletion 函数实际上也只是直接调用内核队列维护函数 KeRemoveQueue 函数和 KeRundownQueue 函数完成对内核队列的操作。

在构造和初始化完成端口内核对象后,需要开始对完成端口进行操作,以实现对完成端口获取或发送完成包的操作。而这些操作归根结底实际上都是对内核队列进行操作。

下面把NT的相关源代码贴出来,前人栽树,我们乘凉。
 
#ifdef ALLOC_PRAGMA
00042 #pragma alloc_text(PAGE, NtCreateIoCompletion)
00043 #pragma alloc_text(PAGE, NtOpenIoCompletion)
00044 #pragma alloc_text(PAGE, NtQueryIoCompletion)
00045 #pragma alloc_text(PAGE, NtRemoveIoCompletion)
00046 #pragma alloc_text(PAGE, NtSetIoCompletion)
00047 #pragma alloc_text(PAGE, IoSetIoCompletion)
00048 #endif
00049
00050 NTSTATUS
00051 NtCreateIoCompletion (
00052 IN PHANDLE IoCompletionHandle,
00053 IN ACCESS_MASK DesiredAccess,
00054 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
00055 IN ULONG Count OPTIONAL
00056 )
00057
00058 /*++
00059
00060 Routine Description:
00061
00062 This function creates an I/O completion object, sets the maximum
00063 target concurrent thread count to the specified value, and opens
00064 a handle to the object with the specified desired access.
00065
00066 Arguments:
00067
00068 IoCompletionHandle - Supplies a pointer to a variable that receives
00069 the I/O completion object handle.
00070
00071 DesiredAccess - Supplies the desired types of access for the I/O
00072 completion object.
00073
00074 ObjectAttributes - Supplies a pointer to an object attributes structure.
00075
00076 Count - Supplies the target maximum number of threads that should
00077 be concurrently active. If this parameter is not specified, then
00078 the number of processors is used.
00079
00080 Return Value:
00081
00082 STATUS_SUCCESS is returned if the function is success. Otherwise, an
00083 error status is returned.
00084
00085 --*/
00086
00087 {
00088
00089 HANDLE Handle;
00090 KPROCESSOR_MODE PreviousMode;
00091 PVOID IoCompletion;
00092 NTSTATUS Status;
00093
00094 //
00095 // Establish an exception handler, probe the output handle address, and
00096 // attempt to create an I/O completion object. If the probe fails, then
00097 // return the exception code as the service status. Otherwise, return the
00098 // status value returned by the object insertion routine.
00099 //
00100
00101 try {
00102
00103 //
00104 // Get previous processor mode and probe output handle address if
00105 // necessary.
00106 //
00107
00108 PreviousMode = KeGetPreviousMode();
00109 if (PreviousMode != KernelMode) {
00110 ProbeForWriteHandle(IoCompletionHandle);
00111 }
00112
00113 //
00114 // Allocate I/O completion object.
00115 //
00116
00117 Status = ObCreateObject(PreviousMode,
00118 IoCompletionObjectType,
00119 ObjectAttributes,
00120 PreviousMode,
00121 NULL,
00122 sizeof(KQUEUE),
00123 0,
00124 0,
00125 (PVOID *)&IoCompletion);
00126
00127 //
00128 // If the I/O completion object was successfully allocated, then
00129 // initialize the object and attempt to insert it in the handle
00130 // table of the current process.
00131 //
00132
00133 if (NT_SUCCESS(Status)) {
00134 KeInitializeQueue((PKQUEUE)IoCompletion, Count);
00135 Status = ObInsertObject(IoCompletion,
00136 NULL,
00137 DesiredAccess,
00138 0,
00139 (PVOID *)NULL,
00140 &Handle);
00141
00142 //
00143 // If the I/O completion object was successfully inserted in
00144 // the handle table of the current process, then attempt to
00145 // write the handle value. If the write attempt fails, then
00146 // do not report an error. When the caller attempts to access
00147 // the handle value, an access violation will occur.
00148 //
00149
00150 if (NT_SUCCESS(Status)) {
00151 try {
00152 *IoCompletionHandle = Handle;
00153
00154 } except(ExSystemExceptionFilter()) {
00155 NOTHING;
00156 }
00157 }
00158 }
00159
00160 //
00161 // If an exception occurs during the probe of the output handle address,
00162 // then always handle the exception and return the exception code as the
00163 // status value.
00164 //
00165
00166 } except(ExSystemExceptionFilter()) {
00167 Status = GetExceptionCode();
00168 }
00169
00170 //
00171 // Return service status.
00172 //
00173
00174 return Status;
00175 }
00176
00177 NTSTATUS
00178 NtOpenIoCompletion (
00179 OUT PHANDLE IoCompletionHandle,
00180 IN ACCESS_MASK DesiredAccess,
00181 IN POBJECT_ATTRIBUTES ObjectAttributes
00182 )
00183
00184 /*++
00185
00186 Routine Description:
00187
00188 This function opens a handle to an I/O completion object with the
00189 specified desired access.
00190
00191 Arguments:
00192
00193 IoCompletionHandle - Supplies a pointer to a variable that receives
00194 the completion object handle.
00195
00196 DesiredAccess - Supplies the desired types of access for the I/O
00197 completion object.
00198
00199 ObjectAttributes - Supplies a pointer to an object attributes structure.
00200
00201 Return Value:
00202
00203 STATUS_SUCCESS is returned if the function is success. Otherwise, an
00204 error status is returned.
00205
00206 --*/
00207
00208 {
00209
00210 HANDLE Handle;
00211 KPROCESSOR_MODE PreviousMode;
00212 NTSTATUS Status;
00213
00214 //
00215 // Establish an exception handler, probe the output handle address,
00216 // and attempt to open an I/O completion object. If the probe fails,
00217 // then return the exception code as the service status. Otherwise,
00218 // return the status value returned by the object open routine.
00219 //
00220
00221 try {
00222
00223 //
00224 // Get previous processor mode and probe output handle address if
00225 // necessary.
00226 //
00227
00228 PreviousMode = KeGetPreviousMode();
00229 if (PreviousMode != KernelMode) {
00230 ProbeForWriteHandle(IoCompletionHandle);
00231 }
00232
00233 //
00234 // Open handle to the completion object with the specified desired
00235 // access.
00236 //
00237
00238 Status = ObOpenObjectByName(ObjectAttributes,
00239 IoCompletionObjectType,
00240 PreviousMode,
00241 NULL,
00242 DesiredAccess,
00243 NULL,
00244 &Handle);
00245
00246 //
00247 // If the open was successful, then attempt to write the I/O
00248 // completion object handle value. If the write attempt fails,
00249 // then do not report an error. When the caller attempts to
00250 // access the handle value, an access violation will occur.
00251 //
00252
00253 if (NT_SUCCESS(Status)) {
00254 try {
00255 *IoCompletionHandle = Handle;
00256
00257 } except(ExSystemExceptionFilter()) {
00258 NOTHING;
00259 }
00260 }
00261
00262 //
00263 // If an exception occurs during the probe of the output handle address,
00264 // then always handle the exception and return the exception code as the
00265 // status value.
00266 //
00267
00268 } except(ExSystemExceptionFilter()) {
00269 Status = GetExceptionCode();
00270 }
00271
00272
00273 //
00274 // Return service status.
00275 //
00276
00277 return Status;
00278 }
00279
00280
00281 NTSTATUS
00282 NtQueryIoCompletion (
00283 IN HANDLE IoCompletionHandle,
00284 IN IO_COMPLETION_INFORMATION_CLASS IoCompletionInformationClass,
00285 OUT PVOID IoCompletionInformation,
00286 IN ULONG IoCompletionInformationLength,
00287 OUT PULONG ReturnLength OPTIONAL
00288 )
00289
00290 /*++
00291
00292 Routine Description:
00293
00294 This function queries the state of an I/O completion object and returns
00295 the requested information in the specified record structure.
00296
00297 Arguments:
00298
00299 IoCompletionHandle - Supplies a handle to an I/O completion object.
00300
00301 IoCompletionInformationClass - Supplies the class of information being
00302 requested.
00303
00304 IoCompletionInformation - Supplies a pointer to a record that receives
00305 the requested information.
00306
00307 IoCompletionInformationLength - Supplies the length of the record that
00308 receives the requested information.
00309
00310 ReturnLength - Supplies an optional pointer to a variable that receives
00311 the actual length of the information that is returned.
00312
00313 Return Value:
00314
00315 STATUS_SUCCESS is returned if the function is success. Otherwise, an
00316 error status is returned.
00317
00318 --*/
00319
00320 {
00321
00322 PVOID IoCompletion;
00323 LONG Depth;
00324 KPROCESSOR_MODE PreviousMode;
00325 NTSTATUS Status;
00326
00327 //
00328 // Establish an exception handler, probe the output arguments, reference
00329 // the I/O completion object, and return the specified information. If
00330 // the probe fails, then return the exception code as the service status.
00331 // Otherwise return the status value returned by the reference object by
00332 // handle routine.
00333 //
00334
00335 try {
00336
00337 //
00338 // Get previous processor mode and probe output arguments if necessary.
00339 //
00340
00341 PreviousMode = KeGetPreviousMode();
00342 if (PreviousMode != KernelMode) {
00343 ProbeForWrite(IoCompletionInformation,
00344 sizeof(IO_COMPLETION_BASIC_INFORMATION),
00345 sizeof(ULONG));
00346
00347 if (ARGUMENT_PRESENT(ReturnLength)) {
00348 ProbeForWriteUlong(ReturnLength);
00349 }
00350 }
00351
00352 //
00353 // Check argument validity.
00354 //
00355
00356 if (IoCompletionInformationClass != IoCompletionBasicInformation) {
00357 return STATUS_INVALID_INFO_CLASS;
00358 }
00359
00360 if (IoCompletionInformationLength != sizeof(IO_COMPLETION_BASIC_INFORMATION)) {
00361 return STATUS_INFO_LENGTH_MISMATCH;
00362 }
00363
00364 //
00365 // Reference the I/O completion object by handle.
00366 //
00367
00368 Status = ObReferenceObjectByHandle(IoCompletionHandle,
00369 IO_COMPLETION_QUERY_STATE,
00370 IoCompletionObjectType,
00371 PreviousMode,
00372 &IoCompletion,
00373 NULL);
00374
00375 //
00376 // If the reference was successful, then read the current state of
00377 // the I/O completion object, dereference the I/O completion object,
00378 // fill in the information structure, and return the structure length
00379 // if specified. If the write of the I/O completion information or
00380 // the return length fails, then do not report an error. When the
00381 // caller accesses the information structure or length an access
00382 // violation will occur.
00383 //
00384
00385 if (NT_SUCCESS(Status)) {
00386 Depth = KeReadStateQueue((PKQUEUE)IoCompletion);
00387 ObDereferenceObject(IoCompletion);
00388 try {
00389 ((PIO_COMPLETION_BASIC_INFORMATION)IoCompletionInformation)->Depth = Depth;
00390 if (ARGUMENT_PRESENT(ReturnLength)) {
00391 *ReturnLength = sizeof(IO_COMPLETION_BASIC_INFORMATION);
00392 }
00393
00394 } except(ExSystemExceptionFilter()) {
00395 NOTHING;
00396 }
00397 }
00398
00399 //
00400 // If an exception occurs during the probe of the output arguments, then
00401 // always handle the exception and return the exception code as the status
00402 // value.
00403 //
00404
00405 } except(ExSystemExceptionFilter()) {
00406 Status = GetExceptionCode();
00407 }
00408
00409 //
00410 // Return service status.
00411 //
00412
00413 return Status;
00414 }
00415
00416 NTSTATUS
00417 NtSetIoCompletion (
00418 IN HANDLE IoCompletionHandle,
00419 IN PVOID KeyContext,
00420 IN PVOID ApcContext,
00421 IN NTSTATUS IoStatus,
00422 IN ULONG_PTR IoStatusInformation
00423 )
00424 /*++
00425
00426 Routine Description:
00427
00428 This function allows the caller to queue an Irp to an I/O completion
00429 port and specify all of the information that is returned out the other
00430 end using NtRemoveIoCompletion.
00431
00432 Arguments:
00433
00434 IoCompletionHandle - Supplies a handle to the io completion port
00435 that the caller intends to queue a completion packet to
00436
00437 KeyContext - Supplies the key context that is returned during a call
00438 to NtRemoveIoCompletion
00439
00440 ApcContext - Supplies the apc context that is returned during a call
00441 to NtRemoveIoCompletion
00442
00443 IoStatus - Supplies the IoStatus->Status data that is returned during
00444 a call to NtRemoveIoCompletion
00445
00446 IoStatusInformation - Supplies the IoStatus->Information data that
00447 is returned during a call to NtRemoveIoCompletion
00448
00449 Return Value:
00450
00451 STATUS_SUCCESS is returned if the function is success. Otherwise, an
00452 error status is returned.
00453
00454 --*/
00455
00456 {
00457 PVOID IoCompletion;
00458 PIOP_MINI_COMPLETION_PACKET MiniPacket;
00459 NTSTATUS Status;
00460
00461 PAGED_CODE();
00462
00463 Status = ObReferenceObjectByHandle(IoCompletionHandle,
00464 IO_COMPLETION_MODIFY_STATE,
00465 IoCompletionObjectType,
00466 KeGetPreviousMode(),
00467 &IoCompletion,
00468 NULL);
00469
00470 if (NT_SUCCESS(Status)) {
00471 Status = IoSetIoCompletion(IoCompletion,
00472 KeyContext,
00473 ApcContext,
00474 IoStatus,
00475 IoStatusInformation,
00476 TRUE);
00477
00478 ObDereferenceObject(IoCompletion);
00479 }
00480 return Status;
00481
00482 }
00483
00484 NTSTATUS
00485 NtRemoveIoCompletion (
00486 IN HANDLE IoCompletionHandle,
00487 OUT PVOID *KeyContext,
00488 OUT PVOID *ApcContext,
00489 OUT PIO_STATUS_BLOCK IoStatusBlock,
00490 IN PLARGE_INTEGER Timeout OPTIONAL
00491 )
00492
00493 /*++
00494
00495 Routine Description:
00496
00497 This function removes an entry from an I/O completion object. If there
00498 are currently no entries available, then the calling thread waits for
00499 an entry.
00500
00501 Arguments:
00502
00503 Completion - Supplies a handle to an I/O completion object.
00504
00505 KeyContext - Supplies a pointer to a variable that receives the key
00506 context that was specified when the I/O completion object was
00507 assoicated with a file object.
00508
00509 ApcContext - Supplies a pointer to a variable that receives the
00510 context that was specified when the I/O operation was issued.
00511
00512 IoStatus - Supplies a pointer to a variable that receives the
00513 I/O completion status.
00514
00515 Timeout - Supplies a pointer to an optional time out value.
00516
00517 Return Value:
00518
00519 STATUS_SUCCESS is returned if the function is success. Otherwise, an
00520 error status is returned.
00521
00522 --*/
00523
00524 {
00525
00526 PLARGE_INTEGER CapturedTimeout;
00527 PLIST_ENTRY Entry;
00528 PVOID IoCompletion;
00529 PIRP Irp;
00530 KPROCESSOR_MODE PreviousMode;
00531 NTSTATUS Status;
00532 LARGE_INTEGER TimeoutValue;
00533 PVOID LocalApcContext;
00534 PVOID LocalKeyContext;
00535 IO_STATUS_BLOCK LocalIoStatusBlock;
00536 PIOP_MINI_COMPLETION_PACKET MiniPacket;
00537
00538 //
00539 // Establish an exception handler, probe the I/O context, the I/O
00540 // status, and the optional timeout value if specified, reference
00541 // the I/O completion object, and attempt to remove an entry from
00542 // the I/O completion object. If the probe fails, then return the
00543 // exception code as the service status. Otherwise, return a value
00544 // dependent on the outcome of the queue removal.
00545 //
00546
00547 try {
00548
00549 //
00550 // Get previous processor mode and probe the I/O context, status,
00551 // and timeout if necessary.
00552 //
00553
00554 CapturedTimeout = NULL;
00555 PreviousMode = KeGetPreviousMode();
00556 if (PreviousMode != KernelMode) {
00557 ProbeForWriteUlong_ptr((PULONG_PTR)ApcContext);
00558 ProbeForWriteUlong_ptr((PULONG_PTR)KeyContext);
00559 ProbeForWriteIoStatus(IoStatusBlock);
00560 if (ARGUMENT_PRESENT(Timeout)) {
00561 CapturedTimeout = &TimeoutValue;
00562 TimeoutValue = ProbeAndReadLargeInteger(Timeout);
00563 }
00564
00565 } else{
00566 if (ARGUMENT_PRESENT(Timeout)) {
00567 CapturedTimeout = Timeout;
00568 }
00569 }
00570
00571 //
00572 // Reference the I/O completion object by handle.
00573 //
00574
00575 Status = ObReferenceObjectByHandle(IoCompletionHandle,
00576 IO_COMPLETION_MODIFY_STATE,
00577 IoCompletionObjectType,
00578 PreviousMode,
00579 &IoCompletion,
00580 NULL);
00581
00582 //
00583 // If the reference was successful, then attempt to remove an entry
00584 // from the I/O completion object. If an entry is removed from the
00585 // I/O completion object, then capture the completion information,
00586 // release the associated IRP, and attempt to write the completion
00587 // inforamtion. If the write of the completion infomation fails,
00588 // then do not report an error. When the caller attempts to access
00589 // the completion information, an access violation will occur.
00590 //
00591
00592 if (NT_SUCCESS(Status)) {
00593 Entry = KeRemoveQueue((PKQUEUE)IoCompletion,
00594 PreviousMode,
00595 CapturedTimeout);
00596
00597 //
00598 // N.B. The entry value returned can be the address of a list
00599 // entry, STATUS_USER_APC, or STATUS_TIMEOUT.
00600 //
00601
00602 if (((LONG_PTR)Entry == STATUS_TIMEOUT) ||
00603 ((LONG_PTR)Entry == STATUS_USER_APC)) {
00604 Status = (NTSTATUS)((LONG_PTR)Entry);
00605
00606 } else {
00607
00608 //
00609 // Set the completion status, capture the completion
00610 // information, deallocate the associated IRP, and
00611 // attempt to write the completion information.
00612 //
00613
00614 Status = STATUS_SUCCESS;
00615 try {
00616 MiniPacket = CONTAINING_RECORD(Entry,
00617 IOP_MINI_COMPLETION_PACKET,
00618 ListEntry);
00619
00620 if ( MiniPacket->PacketType == IopCompletionPacketIrp ) {
00621 Irp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.ListEntry);
00622 LocalApcContext = Irp->Overlay.AsynchronousParameters.UserApcContext;
00623 LocalKeyContext = (PVOID)Irp->Tail.CompletionKey;
00624 LocalIoStatusBlock = Irp->IoStatus;
00625 IoFreeIrp(Irp);
00626
00627 } else {
00628
00629 LocalApcContext = MiniPacket->ApcContext;
00630 LocalKeyContext = (PVOID)MiniPacket->KeyContext;
00631 LocalIoStatusBlock.Status = MiniPacket->IoStatus;
00632 LocalIoStatusBlock.Information = MiniPacket->IoStatusInformation;
00633 IopFreeMiniPacket(MiniPacket);
00634 }
00635
00636 *ApcContext = LocalApcContext;
00637 *KeyContext = LocalKeyContext;
00638 *IoStatusBlock = LocalIoStatusBlock;
00639
00640 } except(ExSystemExceptionFilter()) {
00641 NOTHING;
00642 }
00643 }
00644
00645 //
00646 // Deference I/O completion object.
00647 //
00648
00649 ObDereferenceObject(IoCompletion);
00650 }
00651
00652 //
00653 // If an exception occurs during the probe of the previous count, then
00654 // always handle the exception and return the exception code as the status
00655 // value.
00656 //
00657
00658 } except(ExSystemExceptionFilter()) {
00659 Status = GetExceptionCode();
00660 }
00661
00662 //
00663 // Return service status.
00664 //
00665
00666 return Status;
00667 }
 
VOID
00036 KeInitializeQueue (
00037 IN PRKQUEUE Queue,
00038 IN ULONG Count OPTIONAL
00039 )
00040
00041 /*++
00042
00043 Routine Description:
00044
00045 This function initializes a kernel queue object.
00046
00047 Arguments:
00048
00049 Queue - Supplies a pointer to a dispatcher object of type event.
00050
00051 Count - Supplies the target maximum number of threads that should
00052 be concurrently active. If this parameter is not specified,
00053 then the number of processors is used.
00054
00055 Return Value:
00056
00057 None.
00058
00059 --*/
00060
00061 {
00062
00063 //
00064 // Initialize standard dispatcher object header and set initial
00065 // state of queue object.
00066 //
00067
00068 Queue->Header.Type = QueueObject;
00069 Queue->Header.Size = sizeof(KQUEUE) / sizeof(LONG);
00070 Queue->Header.SignalState = 0;
00071 InitializeListHead(&Queue->Header.WaitListHead);
00072
00073 //
00074 // Initialize queue listhead, the thread list head, the current number
00075 // of threads, and the target maximum number of threads.
00076 //
00077
00078 InitializeListHead(&Queue->EntryListHead);
00079 InitializeListHead(&Queue->ThreadListHead);
00080 Queue->CurrentCount = 0;
00081 if (ARGUMENT_PRESENT((PVOID)(ULONG_PTR)Count)) {
00082 Queue->MaximumCount = Count;
00083
00084 } else {
00085 Queue->MaximumCount = KeNumberProcessors;
00086 }
00087
00088 return;
00089 }

完成端口是用来管理异步过程调用的,在Wait等待事件函数中存在数量限制,而完成端口不存在这一限制。 只给完成端口启动2倍CPU的线程,这是因为线程也耗系统资源,在一个时间片内一个CPU上只会处理一个线程,大量的线程上下文切换也很耗时间,设定2倍的线程,是因为线程处理例程可能会处理比较耗时的操作,这时如果完成端口又来了请求,系统就会唤醒线程池中的空闲线程及时响应,所以设定为2倍。
 
顺便应该参考一下:
private/ntos/ke/queueobj.c
private/ntos/io/internal.c的IopXxxControlFile函数(DeviceIoControl基本上会调用到这里来的)
对照着看,应该很清楚原理了。iocp就是一消息队列而已。

BTW:
TO qydgood:你的习惯好像跟我差不多,doxygen it!
 
win和linux的对抗在网络部分体现的最直接,linux在图像方面也不敢和win对抗。linux从2.4内核bottom half中断升级改为2.6内核的soft中断,嘿嘿,俺觉得在追随微软APC的脚步。

其实看了内核代码,大学所学习的链表,数组,队列,堆栈,Hash表,函数指针大量的应用,思想上也没有跑出我们学习的范围,基本上很少用技巧,老老实实的用最基础的编程技巧来实现。

会不会让你觉得不过如此的感觉呢?先用精神胜利法开心一下,reactos这个操作系统是国外的程序员休闲的时候写一个完全模仿NT的系统,上面都能跑Office,Quake了,而且代码是全部开源的。

不知道beisoft对intel的apic中断研究如何?另外你在哪里上班,有空我们切磋一下。
 
我对硬件没什么研究,以前对这些东东比较好奇的时候找资料学习过。

我目前在上海一家小公司混口饭吃。偶尔还要帮人事部的小妹妹装机,经常还要给他们手工杀流氓软件。
 
reactos这个项目我大概跟踪了一年左右了。我个人认为他其实是脱胎于nt4的原代码(组织结构跟那个一样的),所以还搞了个审计。但函数都是自己写的,里面有好几个人很NB的,特别是写网络NDIS的那个家伙很年轻,但我觉得他里面代码的稳定性健壮性不如WIN的好。做为学习WIN的还可以(当然真正可能还是NT4原码和DDK头文件更好些)
 
啊,跟踪了一年左右,也是一个大侠啊,幸会幸会,我是跟爱大侠打工的时候学习研究内核开发的,大家看来兴趣也很相似啊,我也喜欢用winhex杀毒杀木马啊,为了给人事部的小妹妹装机方便,我开发了一键还原产品,嘿嘿,竟然好多品牌机找我OEM
 
qydgood,爱元员,王府井原来都是一个人啊,呵呵,都是做还原的。总算露馅了,哈哈
 
哎,怎么感觉现在有些年轻的小伙子,怎么就这么浮躁呢,也就特喜欢张贴别人大篇幅的源码!
在这里对骂,还不如做些免费实用软件吧!
 
to 张无忌:爱元元的哥哥是我的老板,你说的可不对,终于见识到你的水平了。
to Ridolph:您老说的对,我们这出口12万份的单子作完之后就以制作免费软件为业。
 
好像爱元元才毕业四年,做你的老板,真是让人佩服啊!
不服不行!
 
才三年,我还说错了,牛人啊!

问题:散分:毕业3年整,入行6年整,跨越人生的24岁本命年 ( 积分:300, 回复:61, 阅读:455 )
分类:Internet/TCPIP ( 版主:luyear, robertcool )
来自:爱元元的哥哥, 时间:2006-8-23 16:07:00, ID:3543016
 
后退
顶部