1 krisbash 1.1 /*
2 **==============================================================================
3 **
4 ** Open Management Infrastructure (OMI)
5 **
6 ** Copyright (c) Microsoft Corporation
7 **
8 ** Licensed under the Apache License, Version 2.0 (the "License"); you may not
9 ** use this file except in compliance with the License. You may obtain a copy
10 ** of the License at
11 **
12 ** http://www.apache.org/licenses/LICENSE-2.0
13 **
14 ** THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 ** KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
16 ** WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
17 ** MERCHANTABLITY OR NON-INFRINGEMENT.
18 **
19 ** See the Apache 2 License for the specific language governing permissions
20 ** and limitations under the License.
21 **
22 krisbash 1.1 **==============================================================================
23 */
24 #include <base/Strand.h>
25 #include <base/log.h>
26 #include <omi_error/errorutil.h>
27
28 //------------------------------------------------------------------------------------------------------------
29 // Debugging aid
30 //------------------------------------------------------------------------------------------------------------
31
32 #if defined(STRAND_ENABLE_DEBUG)
33 StrandBaseDebugInfo _Strand_BaseNameDebugInfo[Strand_NumMethods+5] = {
34 {"<unnamed>", '@' },
35 {"S", '*' },
36 {"CompleteOpenAsync", '$' },
37 {"Timer", '&' },
38 {"Cancel", 'N' },
39 {"CancelSelf", 'n' },
40 {"PostControl", 'T' },
41 {"Post", 'P' },
42 {"PostOther", 'p' },
43 krisbash 1.1 {"Ack", 'A' },
44 {"AckOther", 'a' },
45 {"Close", 'C' },
46 {"CloseOther", 'c' },
47 {"<Aux0>", '0' },
48 {"<Aux1>", '1' },
49 {"<Aux2>", '2' },
50 {"<Aux3>", '3' },
51 {"<Aux4>", '4' },
52 {"ERROR!", '!' },
53 {"ERROR!", '!' },
54 {"ERROR!", '!' } };
55 StrandBaseDebugInfo _StrandBoth_BaseNameDebugInfo[StrandBoth_NumMethods+5] = {
56 {"<unnamed(both)>", '@' },
57 {"SB", '*' },
58 {"CompleteOpenAsync", '$' },
59 {"Timer", '&' },
60 {"Cancel_Left", 'N' },
61 {"Cancel_Right", 'E' },
62 {"CancelSelf_Both", 'n' },
63 {"PostControl_Left", 'T' },
64 krisbash 1.1 {"PostControl_Right", 'R' },
65 {"Post_Left", 'P' },
66 {"Post_Right", 'S' },
67 {"PostOther_Left", 'p' },
68 {"PostOther_Right", 's' },
69 {"Ack_Left", 'A' },
70 {"Ack_Right", 'K' },
71 {"AckOther_Left", 'a' },
72 {"AckOther_Right", 'k' },
73 {"Close_Left", 'C' },
74 {"Close_Right", 'L' },
75 {"CloseOther_Left", 'c' },
76 {"CloseOther_Right", 'l' },
77 {"<Aux0_Left>", '0' },
78 {"<Aux1_Left>", '1' },
79 {"<Aux2_Left>", '2' },
80 {"<Aux3_Left>", '3' },
81 {"<Aux4_Left>", '4' },
82 {"<Aux0_Right>", '5' },
83 {"<Aux1_Right>", '6' },
84 {"<Aux2_Right>", '7' },
85 krisbash 1.1 {"<Aux3_Right>", '8' },
86 {"<Aux4_Right>", '9' },
87 {"ERROR!", '!' },
88 {"ERROR!", '!' },
89 {"ERROR!", '!' } };
90 StrandBaseDebugInfo _StrandMany_BaseNameDebugInfo[StrandMany_NumMethods+5] = {
91 {"<unnamed(many)>", '@' },
92 {"SM", '*' },
93 {"CompleteOpenAsync", '$' },
94 {"Timer", '&' },
95 {"Cancel(M)", 'N' },
96 {"CancelSelf(M)", 'n' },
97 {"CancelInternal", 'E' },
98 {"PostControl(M)", 'T' },
99 {"PostControlInternal", 't' },
100 {"Post(M)", 'P' },
101 {"PostOther(M)", 'p' },
102 {"PostInternal", 'S' },
103 {"Ack(M)", 'A' },
104 {"AckOther(M)", 'a' },
105 {"AckInternal", 'K' },
106 krisbash 1.1 {"EntryOperation", '#' },
107 {"Close(M)", 'C' },
108 {"CloseOther(M)", 'c' },
109 {"CloseInternal", 'L' },
110 {"<Aux0(M)>", '0' },
111 {"<Aux1(M)>", '1' },
112 {"<Aux2(M)>", '2' },
113 {"<Aux3(M)>", '3' },
114 {"<Aux4(M)>", '4' },
115 {"ERROR!", '!' },
116 {"ERROR!", '!' },
117 {"ERROR!", '!' } };
118 char * _StrandMany_BaseEntryOperationDebugInfo[StrandMany_NumEntryOperations+3] = {
119 "Add",
120 "Cancel",
121 "PostControl",
122 "Post",
123 "Close",
124 "<Aux0>",
125 "<Aux1>",
126 "<Aux2>",
127 krisbash 1.1 "<Aux3>",
128 "<Aux4>",
129 "Deleted",
130 "ERROR!",
131 "ERROR!",
132 "ERROR!" };
133
134 #if defined(CONFIG_OS_WINDOWS)
135 #define SPRINTF_FUNC sprintf_s
136 #define STRCPY_FUNC(orig, size, dest) strcpy_s( (orig), (size), (dest) )
137 #else
138 #define SPRINTF_FUNC snprintf
139 #define STRCPY_FUNC(orig, size, dest) strncpy( (orig), (dest), (size) )
140 #endif
141
142
143 static char * _StrandLogScheduledState(
144 _In_ ptrdiff_t state,
145 _In_ StrandBaseDebugInfo const * baseDebugInfo,
146 size_t size,
147 _Out_writes_(size+4) char * buffer )
148 krisbash 1.1 {
149 ptrdiff_t mask = 1;
150 size_t pos = 0;
151 size_t bufferPos = 0;
152
153 buffer[bufferPos++] = baseDebugInfo[1].name[0];
154 if( '\0' != baseDebugInfo[1].name[1] )
155 {
156 buffer[bufferPos++] = baseDebugInfo[1].name[1];
157 }
158 buffer[bufferPos++] = ':';
159
160 while( pos < size )
161 {
162 if( ( mask & state ) != 0 )
163 {
164 buffer[bufferPos++] = baseDebugInfo[pos+1].letter;
165 }
166 mask <<= 1;
167 ++pos;
168 }
169 krisbash 1.1 buffer[bufferPos] = '\0';
170
171 return buffer;
172 }
173
174 #define _STRANDLOGINFOSTATE_SIZE 33 // 15 + 16 digits(pointer) + possible 0x prefix
175 #define _STRANDLOGINFOSTATE_MAXSIZE ((_STRANDLOGINFOSTATE_SIZE*2)+13) // + two state characters + 10 digits(parent) + terminator
176
177 MI_INLINE int _StrandLogInfoState( _In_ InteractionInfo * info, _Out_writes_z_(_STRANDLOGINFOSTATE_SIZE+1) char * buffer )
178 {
179 return SPRINTF_FUNC( buffer, _STRANDLOGINFOSTATE_SIZE, ", %c t:%c%c%co:%c%c %p",
180 info->opened ? 'O' : '-',
181 info->thisClosedOther ? 'C' : '-',
182 info->thisAckPending ? 'A' : '-',
183 info->ackPassthru ? 'P' : ' ',
184 info->otherClosedThis ? 'C' : '-',
185 info->otherAckPending ? 'A' : '-',
186 info->interaction.other );
187 }
188
189 MI_INLINE int _StrandLogStrandState( _In_ Strand* self, _Out_writes_(2) char * buffer )
190 krisbash 1.1 {
191 int written = 0;
192 if( self->canceled )
193 {
194 buffer[written++] = 'N';
195 }
196 if( self->delayFinish )
197 {
198 buffer[written++] = 'D';
199 }
200 if( 0 == written )
201 {
202 buffer[written++] = '-';
203 }
204
205 return written;
206 }
207
208 MI_INLINE int _StrandLogStrandStateParent( _In_ StrandMany* self, _Out_writes_(10) char * buffer )
209 {
210 return SPRINTF_FUNC( buffer, 10, "%d", (unsigned int)self->numEntries );
211 krisbash 1.1 }
212
213 MI_INLINE int _StrandLogInfoStateSingle( _In_ Strand* self, _Out_writes_z_(_STRANDLOGINFOSTATE_MAXSIZE) char * buffer )
214 {
215 int written = _StrandLogStrandState( self, buffer );
216 DEBUG_ASSERT( written > 0 && written <= 2 );
217 return _StrandLogInfoState( &self->info, buffer+written ) + written;
218 }
219
220 MI_INLINE int _StrandLogInfoStateBoth( _In_ StrandBoth* self, _Out_writes_z_(_STRANDLOGINFOSTATE_MAXSIZE) char * buffer )
221 {
222 int written = _StrandLogStrandState( &self->base, buffer );
223 DEBUG_ASSERT( written > 0 && written <= 2 );
224 written += _StrandLogInfoState( &self->base.info, buffer+written );
225 DEBUG_ASSERT( written > 1 && written <= _STRANDLOGINFOSTATE_SIZE+2 );
226 return _StrandLogInfoState( &self->infoRight, buffer+written ) + written;
227 }
228
229 MI_INLINE int _StrandLogInfoStateParent( _In_ StrandMany* self, _Out_writes_z_(_STRANDLOGINFOSTATE_MAXSIZE) char * buffer )
230 {
231 int written = _StrandLogStrandStateParent( self, buffer );
232 krisbash 1.1 DEBUG_ASSERT( written > 0 && written <= 10 );
233 written += _StrandLogStrandState( &self->strand, buffer+written );
234 DEBUG_ASSERT( written > 1 && written <= 12 );
235 return _StrandLogInfoState( &self->strand.info, buffer+written ) + written;
236 }
237
238 MI_INLINE void _StrandLogInfoState_Store( _In_ Strand* strand, _Out_writes_z_(_STRANDLOGINFOSTATE_MAXSIZE) char * buffer )
239 {
240 if( STRAND_TYPE_MIDDLE == (strand)->strandType )
241 {
242 _StrandLogInfoStateBoth( (StrandBoth*)(strand), buffer);
243 }
244 else if( STRAND_ISTYPE_PARENT( strand ) )
245 {
246 _StrandLogInfoStateParent( FromOffset(StrandMany,strand,strand), buffer );
247 }
248 else
249 {
250 _StrandLogInfoStateSingle( strand, buffer );
251 }
252 }
253 krisbash 1.1
254 void _StrandLogWithName( _In_ Strand* self, _In_ const char * operation )
255 {
256 trace_Strand_Action( self, STRAND_DEBUG_GETNAME(self), operation );
257 }
258
259 void _Strand_AssertOnStrand( _In_ Strand* strand )
260 {
261 ThreadID threadId = Thread_ID();
262 if( !Thread_Equal(&threadId,&((strand)->testThreadId)) )
263 {
264 DEBUG_ASSERT( Thread_Equal(&threadId,&((strand)->threadId)) );
265 STRAND_ASSERTEXECUTING( strand ); \
266 }
267 }
268 #endif
269
270 #if defined(STRAND_ENABLE_DEBUG)
271 #define STRAND_DEBUG_GETSTATE_USED \
272 char _buffer_STRAND_DEBUG_GETSTATE[StrandBoth_NumMethods+6]
273 #define STRAND_DEBUG_GETSTATE( strand, state ) \
274 krisbash 1.1 _StrandLogScheduledState( state, STRAND_DEBUG_GETBASEINFO(strand), STRAND_DEBUG_GETINFOSIZE(strand)+1, _buffer_STRAND_DEBUG_GETSTATE )
275 #define STRAND_DEBUG_GETINFOSTATE_USED \
276 char _buffer_STRAND_DEBUG_GETINFOSTATE[_STRANDLOGINFOSTATE_MAXSIZE]
277 #define STRAND_DEBUG_GETINFOSTATE_STORE(strand) \
278 _StrandLogInfoState_Store( strand,_buffer_STRAND_DEBUG_GETINFOSTATE)
279 #define STRAND_DEBUG_GETINFOSTATE_STORED (_buffer_STRAND_DEBUG_GETINFOSTATE)
280 // Note that this uses same buffer as STRAND_DEBUG_GETSTATE
281 #define STRAND_DEBUG_GETNAME_STORE( strand ) \
282 STRCPY_FUNC( _buffer_STRAND_DEBUG_GETSTATE, StrandBoth_NumMethods+6, STRAND_DEBUG_GETNAME(strand) )
283 #define STRAND_DEBUG_GETNAME_STORED (_buffer_STRAND_DEBUG_GETSTATE)
284
285 MI_INLINE
286 void _Strand_TracePostMsg( _In_ Strand* self, _In_ Message* msg, _In_ const char * info )
287 {
288 DEBUG_ASSERT( NULL != self );
289 DEBUG_ASSERT( NULL != msg );
290 // TODO why is linux crashing when passing info into the trace function on x86?
291 MI_UNUSED(info);
292 if( PostResultMsgTag == msg->tag )
293 {
294 PostResultMsg* msgResult = (PostResultMsg*)msg;
295 krisbash 1.1 trace_Strand_TracePostResult(self, msg, msg->tag, msg->operationId, msgResult->result);
296 }
297 else
298 {
299 trace_Strand_TracePost(self, msg, msg->tag, MessageName(msg->tag), msg->operationId);
300 }
301 }
302
303 #else
304 #define STRAND_DEBUG_GETSTATE_USED
305 #define STRAND_DEBUG_GETSTATE( strand, state ) ""
306 #define STRAND_DEBUG_GETINFOSTATE_USED
307 #define STRAND_DEBUG_GETINFOSTATE_STORE(strand)
308 #define STRAND_DEBUG_GETINFOSTATE_STORED ""
309 #define STRAND_DEBUG_GETNAME_STORE( strand )
310 #define STRAND_DEBUG_GETNAME_STORED ""
311
312 MI_INLINE
313 void _Strand_TracePostMsg( _In_ Strand* self, _In_ Message* msg, _In_ const char * info )
314 {
315 }
316 krisbash 1.1
317 #endif
318
319 #if defined(STRAND_ENABLE_DEBUG)
320 #define STRAND_SETDEBUG( strand, strandDebugInfo ) (strand)->debug = strandDebugInfo; STRAND_LOGWITHNAME( strand, "Initialize Itself" )
321 #else
322 #define STRAND_SETDEBUG( strand, strandDebugInfo )
323 #endif
324
325 #if STRAND_ENABLE_DEBUG == 2
326 static void _StrandLogState( _In_ Strand* self, _In_ const char * infoName, _In_ InteractionInfo * info )
327 {
328 trace_StrandFlags(
329 self,
330 STRAND_DEBUG_GETNAME(self),
331 infoName,
332 info->interaction.other,
333 info->opened,
334 info->thisClosedOther,
335 info->thisAckPending,
336 info->otherClosedThis,
337 krisbash 1.1 info->otherAckPending,
338 info->ackPassthru );
339 }
340
341 #define STRAND_DEBUGSTATE( strand ) _StrandLogState( (strand), "S.:", &((strand)->info) )
342 #define STRAND_DEBUGSTATE_LEFT( strand ) _StrandLogState( &((strand)->base), "S.Left", &((strand)->base.info) ); \
343 _StrandLogState( &((strand)->base), "S.(Right)", &((strand)->infoRight) )
344 #define STRAND_DEBUGSTATE_RIGHT( strand ) _StrandLogState( &((strand)->base), "S.Right", &((strand)->infoRight) ); \
345 _StrandLogState( &((strand)->base), "S.(Left)", &((strand)->base.info) )
346 #else
347 #define STRAND_DEBUGSTATE( strand )
348 #define STRAND_DEBUGSTATE_LEFT( strand )
349 #define STRAND_DEBUGSTATE_RIGHT( strand )
350 #endif
351
352 //------------------------------------------------------------------------------------------------------------
353 #define _GetMethodBit( bitIndex ) ((ptrdiff_t)1 << ((bitIndex)-1))
354
355 //------------------------------------------------------------------------------------------------------------
356 void _StrandInteraction_Cancel( _In_ Interaction* interaction )
357 {
358 krisbash 1.1 Strand* self = Strand_FromInteraction( interaction );
359 _Strand_Schedule( self, BitCancel );
360 }
361
362 //------------------------------------------------------------------------------------------------------------
363 void _StrandInteraction_PostControl( _In_ Interaction* interaction, _In_ Message* msg )
364 {
365 Strand* self = Strand_FromInteraction( interaction );
366 Message_AddRef( msg ); // since the actual message use can be delayed
367 self->info.stored.controlMsg = msg;
368 _Strand_Schedule( self, BitPostControl );
369 }
370
371 //------------------------------------------------------------------------------------------------------------
372 void _StrandInteraction_Post( _In_ Interaction* interaction, _In_ Message* msg )
373 {
374 Strand* self = Strand_FromInteraction( interaction );
375 Message_AddRef( msg ); // since the actual message use can be delayed
376 self->info.stored.msg = msg;
377 _Strand_Schedule( self, BitPost );
378 }
379 krisbash 1.1
380 //------------------------------------------------------------------------------------------------------------
381 void _StrandInteraction_Ack( _In_ Interaction* interaction )
382 {
383 Strand* self = Strand_FromInteraction( interaction );
384 _Strand_Schedule( self, BitAck );
385 }
386
387 //------------------------------------------------------------------------------------------------------------
388 void _StrandInteraction_Close( _In_ Interaction* interaction )
389 {
390 Strand* self = Strand_FromInteraction( interaction );
391 _Strand_Schedule( self, BitClose );
392 }
393
394 //------------------------------------------------------------------------------------------------------------
395 void _StrandInteraction_Left_Cancel( _In_ Interaction* interaction )
396 {
397 Strand* self = Strand_FromInteraction( interaction );
398 _Strand_Schedule( self, BitCancel_Left );
399 }
400 krisbash 1.1
401 //------------------------------------------------------------------------------------------------------------
402 void _StrandInteraction_Left_PostControl( _In_ Interaction* interaction, _In_ Message* msg )
403 {
404 Strand* self = Strand_FromInteraction( interaction );
405 Message_AddRef( msg ); // since the actual message use can be delayed
406 self->info.stored.controlMsg = msg;
407 _Strand_Schedule( self, BitPostControl_Left );
408 }
409
410 //------------------------------------------------------------------------------------------------------------
411 void _StrandInteraction_Left_Post( _In_ Interaction* interaction, _In_ Message* msg )
412 {
413 Strand* self = Strand_FromInteraction( interaction );
414 Message_AddRef( msg ); // since the actual message use can be delayed
415 self->info.stored.msg = msg;
416 _Strand_Schedule( self, BitPost_Left );
417 }
418
419 //------------------------------------------------------------------------------------------------------------
420 void _StrandInteraction_Left_Ack( _In_ Interaction* interaction )
421 krisbash 1.1 {
422 Strand* self = Strand_FromInteraction( interaction );
423 _Strand_Schedule( self, BitAck_Left );
424 }
425
426 //------------------------------------------------------------------------------------------------------------
427 void _StrandInteraction_Left_Close( _In_ Interaction* interaction )
428 {
429 Strand* self = Strand_FromInteraction( interaction );
430 _Strand_Schedule( self, BitClose_Left );
431 }
432
433 //------------------------------------------------------------------------------------------------------------
434 void _StrandInteraction_Right_Cancel( _In_ Interaction* interaction )
435 {
436 StrandBoth* self = Strand_FromInteractionRight( interaction );
437 _Strand_Schedule( (Strand*)self, BitCancel_Right );
438 }
439
440 //------------------------------------------------------------------------------------------------------------
441 void _StrandInteraction_Right_PostControl( _In_ Interaction* interaction, _In_ Message* msg )
442 krisbash 1.1 {
443 StrandBoth* self = Strand_FromInteractionRight( interaction );
444 Message_AddRef( msg ); // since the actual message use can be delayed
445 self->infoRight.stored.controlMsg = msg;
446 _Strand_Schedule( (Strand*)self, BitPostControl_Right );
447 }
448
449 //------------------------------------------------------------------------------------------------------------
450 void _StrandInteraction_Right_Post( _In_ Interaction* interaction, _In_ Message* msg )
451 {
452 StrandBoth* self = Strand_FromInteractionRight( interaction );
453 Message_AddRef( msg ); // since the actual message use can be delayed
454 self->infoRight.stored.msg = msg;
455 _Strand_Schedule( (Strand*)self, BitPost_Right );
456 }
457
458 //------------------------------------------------------------------------------------------------------------
459 void _StrandInteraction_Right_Ack( _In_ Interaction* interaction )
460 {
461 StrandBoth* self = Strand_FromInteractionRight( interaction );
462 _Strand_Schedule( (Strand*)self, BitAck_Right );
463 krisbash 1.1 }
464
465 //------------------------------------------------------------------------------------------------------------
466 void _StrandInteraction_Right_Close( _In_ Interaction* interaction )
467 {
468 StrandBoth* self = Strand_FromInteractionRight( interaction );
469 _Strand_Schedule( (Strand*)self, BitClose_Right );
470 }
471
472 //------------------------------------------------------------------------------------------------------------
473 void _StrandInteraction_Many_Cancel( _In_ Interaction* interaction )
474 {
475 Strand* self = Strand_FromInteraction( interaction );
476 _Strand_Schedule( self, BitCancel_Many );
477 }
478
479 //------------------------------------------------------------------------------------------------------------
480 void _StrandInteraction_Many_PostControl( _In_ Interaction* interaction, _In_ Message* msg )
481 {
482 Strand* self = Strand_FromInteraction( interaction );
483 Message_AddRef( msg ); // since the actual message use can be delayed
484 krisbash 1.1 self->info.stored.controlMsg = msg;
485 _Strand_Schedule( self, BitPostControl_Many );
486 }
487
488 //------------------------------------------------------------------------------------------------------------
489 void _StrandInteraction_Many_Post( _In_ Interaction* interaction, _In_ Message* msg )
490 {
491 Strand* self = Strand_FromInteraction( interaction );
492 Message_AddRef( msg ); // since the actual message use can be delayed
493 self->info.stored.msg = msg;
494 _Strand_Schedule( self, BitPost_Many );
495 }
496
497 //------------------------------------------------------------------------------------------------------------
498 void _StrandInteraction_Many_Ack( _In_ Interaction* interaction )
499 {
500 Strand* self = Strand_FromInteraction( interaction );
501 _Strand_Schedule( self, BitAck_Many );
502 }
503
504 //------------------------------------------------------------------------------------------------------------
505 krisbash 1.1 void _StrandInteraction_Many_Close( _In_ Interaction* interaction )
506 {
507 Strand* self = Strand_FromInteraction( interaction );
508 _Strand_Schedule( self, BitClose_Many );
509 }
510
511 //------------------------------------------------------------------------------------------------------------
512 MI_INLINE
513 MI_Boolean _StrandMethodImp_CheckFinished( _In_ InteractionInfo* info )
514 {
515 return
516 info->thisClosedOther
517 && !info->thisAckPending
518 && info->otherClosedThis
519 && !info->otherAckPending;
520 }
521
522 //------------------------------------------------------------------------------------------------------------
523 MI_INLINE
524 MI_Boolean _StrandMethodImp_Cancel( _In_ Strand* self, _In_ InteractionInfo* info)
525 {
526 krisbash 1.1 DEBUG_ASSERT( !self->canceled );
527
528 self->canceled = MI_TRUE;
529
530 if( NULL != info->userFT->Cancel )
531 {
532 (*info->userFT->Cancel)(self);
533 }
534
535 return MI_FALSE;
536 }
537
538 //------------------------------------------------------------------------------------------------------------
539 MI_INLINE
540 MI_Boolean _StrandMethodImp_PostControl( _In_ Strand* self, _In_ InteractionInfo* info)
541 {
542 DEBUG_ASSERT( info->opened );
543 DEBUG_ASSERT( !info->otherClosedThis );
544 DEBUG_ASSERT( NULL != info->userFT->PostControl );
545 DEBUG_ASSERT( NULL != info->stored.controlMsg );
546
547 krisbash 1.1 info->userFT->PostControl( self, info->stored.controlMsg );
548 Message_Release( info->stored.controlMsg ); // now we can remove the reference added on _StrandInteraction_*
549
550 return MI_FALSE;
551 }
552
553 //------------------------------------------------------------------------------------------------------------
554 MI_INLINE
555 MI_Boolean _StrandMethodImp_Post( _In_ Strand* self, _In_ InteractionInfo* info)
556 {
557 DEBUG_ASSERT( info->opened );
558 DEBUG_ASSERT( !info->otherClosedThis );
559 DEBUG_ASSERT( NULL != info->userFT->Post );
560 DEBUG_ASSERT( NULL != info->stored.msg );
561 DEBUG_ASSERT( !info->otherAckPending );
562
563 info->otherAckPending = MI_TRUE;
564 info->userFT->Post( self, info->stored.msg );
565 Message_Release( info->stored.msg ); // now we can remove the reference added on _StrandInteraction_*
566
567 return MI_FALSE;
568 krisbash 1.1 }
569
570 //------------------------------------------------------------------------------------------------------------
571 MI_INLINE
572 MI_Boolean _StrandMethodImp_Ack( _In_ Strand* self, _In_ InteractionInfo* info)
573 {
574 // note that info->otherClosedThis may be true here
575 DEBUG_ASSERT( info->thisAckPending );
576 DEBUG_ASSERT( info->opened );
577
578 info->thisAckPending = MI_FALSE;
579
580 if( NULL != info->userFT->Ack )
581 {
582 info->userFT->Ack( self );
583 }
584
585 return MI_FALSE;
586 }
587
588 //------------------------------------------------------------------------------------------------------------
589 krisbash 1.1 MI_INLINE
590 MI_Boolean _StrandMethodImp_Close( _In_ Strand* self, _In_ InteractionInfo* info)
591 {
592 DEBUG_ASSERT( info->opened );
593 DEBUG_ASSERT( !info->otherClosedThis );
594
595 info->otherClosedThis = MI_TRUE;
596
597 if( NULL != info->userFT->Close )
598 {
599 (*info->userFT->Close)(self);
600 }
601
602 return MI_FALSE;
603 }
604
605 //------------------------------------------------------------------------------------------------------------
606 MI_INLINE
607 MI_Boolean _StrandMethodImp_PostOther( _In_ InteractionInfo* info)
608 {
609 _Strand_Post_Imp( info, info->otherMsg );
610 krisbash 1.1 Message_Release( info->otherMsg ); // now we can remove the reference added on Strand_SchedulePost*
611 info->otherMsg = NULL;
612 return MI_FALSE;
613 }
614
615 //------------------------------------------------------------------------------------------------------------
616 MI_Boolean _StrandMethod_CheckFinished( _In_ Strand* self )
617 {
618 return _StrandMethodImp_CheckFinished( &self->info ) && !self->delayFinish;
619 }
620
621 //------------------------------------------------------------------------------------------------------------
622 MI_Boolean _StrandMethod_Timer( _In_ Strand* self)
623 {
624 TimerReason reason;
625
626 DEBUG_ASSERT( NULL != self->timer );
627 DEBUG_ASSERT( NULL != self->info.userFT->Timer );
628
629 STRAND_DEBUGSTATE( self );
630
631 krisbash 1.1 reason = self->timer->reason;
632
633 Timer_Close(self->timer);
634 self->timer = NULL;
635 (*self->info.userFT->Timer)(self, reason);
636
637 // A canceled timer shouldn't be re-started
638 DEBUG_ASSERT( NULL == self->timer || reason != TimerReason_Canceled );
639
640 return MI_FALSE;
641 }
642
643 //------------------------------------------------------------------------------------------------------------
644 // Internal use
645 void _Strand_CancelPropagate(
646 _In_ Strand * self);
647
648 // Internal use
649 MI_INLINE
650 void _Strand_CompleteOpenAsyncImp(
651 _In_ Strand * self,
652 krisbash 1.1 _In_ InteractionInfo* info )
653 {
654 STRAND_ASSERTONSTRAND(self);
655 DEBUG_ASSERT( !info->opened );
656
657 info->opened = MI_TRUE;
658
659 if( self->canceled )
660 {
661 _Strand_CancelPropagate( self );
662 }
663 }
664
665 MI_Boolean _StrandMethod_CompleteOpenAsync( _In_ Strand* self)
666 {
667 STRAND_DEBUGSTATE( self );
668
669 _Strand_CompleteOpenAsyncImp( self, &self->info );
670 return MI_FALSE;
671 }
672
673 krisbash 1.1 //------------------------------------------------------------------------------------------------------------
674 MI_Boolean _StrandMethod_Cancel( _In_ Strand* self)
675 {
676 STRAND_DEBUGSTATE( self );
677
678 if( !self->canceled )
679 {
680 if( STRAND_TYPE_RIGHTMOST == self->strandType && self->info.opened && !self->info.thisClosedOther )
681 {
682 // return it to the other side
683 self->info.interaction.other->ft->Cancel( self->info.interaction.other );
684 }
685
686 _StrandMethodImp_Cancel(self, &self->info );
687 }
688 return MI_FALSE;
689 }
690
691 //------------------------------------------------------------------------------------------------------------
692 MI_Boolean _StrandMethod_PostControl( _In_ Strand* self)
693 {
694 krisbash 1.1 _Strand_TracePostMsg(self, self->info.stored.controlMsg, "(Control)");
695 STRAND_DEBUGSTATE( self );
696
697 return _StrandMethodImp_PostControl(self, &self->info );
698 }
699
700 //------------------------------------------------------------------------------------------------------------
701 MI_Boolean _StrandMethod_Post( _In_ Strand* self)
702 {
703 _Strand_TracePostMsg(self, self->info.stored.msg, "");
704 STRAND_DEBUGSTATE( self );
705
706 return _StrandMethodImp_Post(self, &self->info );
707 }
708
709 //------------------------------------------------------------------------------------------------------------
710 MI_Boolean _StrandMethod_Ack( _In_ Strand* self)
711 {
712 STRAND_DEBUGSTATE( self );
713
714 return _StrandMethodImp_Ack(self, &self->info );
715 krisbash 1.1 }
716
717 //------------------------------------------------------------------------------------------------------------
718 MI_Boolean _StrandMethod_Close( _In_ Strand* self)
719 {
720 STRAND_DEBUGSTATE( self );
721
722 return _StrandMethodImp_Close(self, &self->info );
723 }
724
725 //------------------------------------------------------------------------------------------------------------
726 MI_Boolean _StrandMethod_PostOther( _In_ Strand* self)
727 {
728 MI_Boolean res = _StrandMethodImp_PostOther( &self->info );
729 STRAND_LOGWITHNAME( self, "Returning from PostOther" );
730 return res;
731 }
732
733 //------------------------------------------------------------------------------------------------------------
734 MI_Boolean _StrandMethod_AckOther( _In_ Strand* self)
735 {
736 krisbash 1.1 _Strand_Ack_Imp( &self->info );
737 STRAND_LOGWITHNAME( self, "Returning from AckOther" );
738 return MI_FALSE;
739 }
740
741 //------------------------------------------------------------------------------------------------------------
742 MI_Boolean _StrandMethod_CloseOther( _In_ Strand* self)
743 {
744 _Strand_Close_Imp( &self->info );
745 STRAND_LOGWITHNAME( self, "Returning from CloseOther" );
746 return MI_FALSE;
747 }
748
749 //------------------------------------------------------------------------------------------------------------
750 MI_Boolean _StrandMethod_CancelSelf( _In_ Strand* self)
751 {
752 Strand_Cancel( self );
753 STRAND_LOGWITHNAME( self, "Returning from CancelSelf" );
754 return MI_FALSE;
755 }
756
757 krisbash 1.1 //------------------------------------------------------------------------------------------------------------
758 MI_Boolean _StrandMethod_Aux0( _In_ Strand* self)
759 {
760 DEBUG_ASSERT( NULL != self->info.userFT->Aux0 );
761 self->info.userFT->Aux0( self );
762 return MI_FALSE;
763 }
764
765 //------------------------------------------------------------------------------------------------------------
766 MI_Boolean _StrandMethod_Aux1( _In_ Strand* self)
767 {
768 DEBUG_ASSERT( NULL != self->info.userFT->Aux1 );
769 self->info.userFT->Aux1( self );
770 return MI_FALSE;
771 }
772
773 //------------------------------------------------------------------------------------------------------------
774 MI_Boolean _StrandMethod_Aux2( _In_ Strand* self)
775 {
776 DEBUG_ASSERT( NULL != self->info.userFT->Aux2 );
777 self->info.userFT->Aux2( self );
778 krisbash 1.1 return MI_FALSE;
779 }
780
781 //------------------------------------------------------------------------------------------------------------
782 MI_Boolean _StrandMethod_Aux3( _In_ Strand* self)
783 {
784 DEBUG_ASSERT( NULL != self->info.userFT->Aux3 );
785 self->info.userFT->Aux3( self );
786 return MI_FALSE;
787 }
788
789 //------------------------------------------------------------------------------------------------------------
790 MI_Boolean _StrandMethod_Aux4( _In_ Strand* self)
791 {
792 DEBUG_ASSERT( NULL != self->info.userFT->Aux4 );
793 self->info.userFT->Aux4( self );
794 return MI_FALSE;
795 }
796
797 //------------------------------------------------------------------------------------------------------------
798 MI_Boolean _StrandMethod_Both_CheckFinished( _In_ Strand* self_)
799 krisbash 1.1 {
800 StrandBoth* self = (StrandBoth*)self_;
801
802 if (self->asyncOpenInProgress)
803 return MI_FALSE;
804
805 return _StrandMethodImp_CheckFinished( &self->base.info )
806 && ((!self->infoRight.opened) || _StrandMethodImp_CheckFinished( &self->infoRight )) //check right interation state only if its opeened
807 && !self->base.delayFinish;
808 }
809
810 //------------------------------------------------------------------------------------------------------------
811 MI_Boolean _StrandMethod_Both_CompleteOpenAsync( _In_ Strand* self_)
812 {
813 StrandBoth* self = (StrandBoth*)self_;
814 STRAND_DEBUGSTATE( self );
815
816 _Strand_CompleteOpenAsyncImp( &self->base, &self->infoRight );
817 self->asyncOpenInProgress = MI_FALSE;
818 return MI_FALSE;
819 }
820 krisbash 1.1
821 //------------------------------------------------------------------------------------------------------------
822 MI_Boolean _StrandMethod_Left_Cancel( _In_ Strand* self_)
823 {
824 StrandBoth* self = (StrandBoth*)self_;
825
826 STRAND_DEBUGSTATE_LEFT( self );
827
828 if( !self->base.canceled )
829 {
830 // We pass to the right only if we have not been cancel already becase in that case it has go to the right already
831 // (cancelations always flow to the right first)
832 // Note that we need to check this first as the canceled below may close the interaction with the right side
833 if( self->infoRight.opened && !self->infoRight.thisClosedOther )
834 {
835 self->infoRight.interaction.other->ft->Cancel( self->infoRight.interaction.other );
836 }
837
838 _StrandMethodImp_Cancel(self_, &self->base.info );
839 }
840 return MI_FALSE;
841 krisbash 1.1 }
842
843 //------------------------------------------------------------------------------------------------------------
844 MI_Boolean _StrandMethod_Left_PostControl( _In_ Strand* self_)
845 {
846 StrandBoth* self = (StrandBoth*)self_;
847
848 _Strand_TracePostMsg(self_, self->base.info.stored.controlMsg, "(Control Left)");
849 STRAND_DEBUGSTATE_LEFT( self );
850
851 if( NULL == self->base.info.userFT->PostControl && self->infoRight.opened )
852 {
853 DEBUG_ASSERT( !self->infoRight.thisClosedOther );
854 // post passing thru to the other side
855 StrandBoth_PostControlRight( self, self->base.info.stored.controlMsg );
856 Message_Release( self->base.info.stored.controlMsg ); // now we can remove the reference added on _StrandInteraction_*
857 return MI_FALSE;
858 }
859 else
860 {
861 return _StrandMethodImp_PostControl(self_, &self->base.info );
862 krisbash 1.1 }
863 }
864
865 //------------------------------------------------------------------------------------------------------------
866 MI_Boolean _StrandMethod_Left_Post( _In_ Strand* self_)
867 {
868 StrandBoth* self = (StrandBoth*)self_;
869
870 _Strand_TracePostMsg(self_, self->base.info.stored.msg, "Left");
871 STRAND_DEBUGSTATE_LEFT( self );
872
873 if( NULL == self->base.info.userFT->Post && self->infoRight.opened )
874 {
875 DEBUG_ASSERT( !self->infoRight.thisClosedOther );
876 // post passing thru to the other side
877 StrandBoth_PostPassthruRight( self, self->base.info.stored.msg );
878 Message_Release( self->base.info.stored.msg ); // now we can remove the reference added on _StrandInteraction_*
879 return MI_FALSE;
880 }
881 else
882 {
883 krisbash 1.1 return _StrandMethodImp_Post(self_, &self->base.info );
884 }
885 }
886
887 //------------------------------------------------------------------------------------------------------------
888 MI_Boolean _StrandMethod_Left_Ack( _In_ Strand* self_)
889 {
890 StrandBoth* self = (StrandBoth*)self_;
891
892 STRAND_DEBUGSTATE_LEFT( self );
893 DEBUG_ASSERT( self->base.info.opened );
894
895 if( self->base.info.ackPassthru || NULL == self->base.info.userFT->Ack )
896 {
897 DEBUG_ASSERT( self->base.info.thisAckPending );
898 self->base.info.thisAckPending = MI_FALSE;
899
900 if( self->infoRight.otherAckPending )
901 {
902 self->base.info.ackPassthru = MI_FALSE;
903 StrandBoth_AckRight( self );
904 krisbash 1.1 }
905 else
906 {
907 DEBUG_ASSERT( !self->base.info.ackPassthru );
908 }
909
910 return MI_FALSE;
911 }
912 else
913 {
914 return _StrandMethodImp_Ack(self_, &self->base.info );
915 }
916 }
917
918 //------------------------------------------------------------------------------------------------------------
919 MI_Boolean _StrandMethod_Left_Close( _In_ Strand* self_)
920 {
921 StrandBoth* self = (StrandBoth*)self_;
922
923 STRAND_DEBUGSTATE_LEFT( self );
924
925 krisbash 1.1 if( NULL == self->base.info.userFT->Close )
926 {
927 // we take care of sending the close as passthru
928 if( self->infoRight.opened && !self->infoRight.thisClosedOther )
929 {
930 StrandBoth_CloseRight( self );
931 }
932 }
933
934 return _StrandMethodImp_Close(self_, &self->base.info );
935 }
936
937 //------------------------------------------------------------------------------------------------------------
938 MI_Boolean _StrandMethod_Right_Cancel( _In_ Strand* self_)
939 {
940 StrandBoth* self = (StrandBoth*)self_;
941
942 STRAND_DEBUGSTATE_RIGHT( self );
943
944 // We need to check this first as the canceled below may close the interaction with the left side
945 if( self->base.info.opened && !self->base.info.thisClosedOther && !self->leftCanceled )
946 krisbash 1.1 {
947 self->leftCanceled = MI_TRUE;
948 // We pass to the left even if we have been cancel already becase thet should be the cancelation coming back from the right
949 self->base.info.interaction.other->ft->Cancel( self->base.info.interaction.other );
950 }
951
952 if( !self->base.canceled )
953 {
954 _StrandMethodImp_Cancel(self_, &self->infoRight );
955 }
956 return MI_FALSE;
957 }
958
959 //------------------------------------------------------------------------------------------------------------
960 MI_Boolean _StrandMethod_Right_PostControl( _In_ Strand* self_)
961 {
962 StrandBoth* self = (StrandBoth*)self_;
963
964 _Strand_TracePostMsg(self_, self->infoRight.stored.controlMsg, "(Control Right)");
965 STRAND_DEBUGSTATE_RIGHT( self );
966
967 krisbash 1.1 if( NULL == self->infoRight.userFT->PostControl && self->base.info.opened )
968 {
969 DEBUG_ASSERT( !self->base.info.thisClosedOther );
970 // post passing thru to the other side
971 StrandBoth_PostControlLeft( self, self->infoRight.stored.controlMsg );
972 Message_Release( self->infoRight.stored.controlMsg ); // now we can remove the reference added on _StrandInteraction_*
973 return MI_FALSE;
974 }
975 else
976 {
977 return _StrandMethodImp_PostControl(self_, &self->infoRight );
978 }
979 }
980
981 //------------------------------------------------------------------------------------------------------------
982 MI_Boolean _StrandMethod_Right_Post( _In_ Strand* self_)
983 {
984 StrandBoth* self = (StrandBoth*)self_;
985
986 _Strand_TracePostMsg(self_, self->infoRight.stored.msg, "Right");
987 STRAND_DEBUGSTATE_RIGHT( self );
988 krisbash 1.1
989 if( NULL == self->infoRight.userFT->Post && self->base.info.opened )
990 {
991 DEBUG_ASSERT( !self->base.info.thisClosedOther );
992 // post passing thru to the other side
993 StrandBoth_PostPassthruLeft( self, self->infoRight.stored.msg );
994 Message_Release( self->infoRight.stored.msg ); // now we can remove the reference added on _StrandInteraction_*
995 return MI_FALSE;
996 }
997 else
998 {
999 return _StrandMethodImp_Post(self_, &self->infoRight );
1000 }
1001 }
1002
1003 //------------------------------------------------------------------------------------------------------------
1004 MI_Boolean _StrandMethod_Right_Ack( _In_ Strand* self_)
1005 {
1006 StrandBoth* self = (StrandBoth*)self_;
1007
1008 STRAND_DEBUGSTATE_RIGHT( self );
1009 krisbash 1.1 DEBUG_ASSERT( self->infoRight.opened );
1010
1011 if( self->infoRight.ackPassthru || NULL == self->infoRight.userFT->Ack )
1012 {
1013 DEBUG_ASSERT( self->infoRight.thisAckPending );
1014
1015 self->infoRight.thisAckPending = MI_FALSE;
1016
1017 if( self->base.info.otherAckPending )
1018 {
1019 self->infoRight.ackPassthru = MI_FALSE;
1020 StrandBoth_AckLeft( self );
1021 }
1022 else
1023 {
1024 DEBUG_ASSERT( !self->infoRight.ackPassthru );
1025 }
1026
1027 return MI_FALSE;
1028 }
1029 else
1030 krisbash 1.1 {
1031 return _StrandMethodImp_Ack(self_, &self->infoRight );
1032 }
1033 }
1034
1035 //------------------------------------------------------------------------------------------------------------
1036 MI_Boolean _StrandMethod_Right_Close( _In_ Strand* self_)
1037 {
1038 StrandBoth* self = (StrandBoth*)self_;
1039
1040 STRAND_DEBUGSTATE_RIGHT( self );
1041
1042 if( NULL == self->infoRight.userFT->Close )
1043 {
1044 // we take care of sending the close as passthru
1045 if( self->base.info.opened && !self->base.info.thisClosedOther )
1046 {
1047 StrandBoth_CloseLeft( self );
1048 }
1049 }
1050
1051 krisbash 1.1 return _StrandMethodImp_Close(self_, &self->infoRight );
1052 }
1053
1054 //------------------------------------------------------------------------------------------------------------
1055 MI_Boolean _StrandMethod_Right_PostOther( _In_ Strand* self_)
1056 {
1057 StrandBoth* self = (StrandBoth*)self_;
1058
1059 MI_Boolean res = _StrandMethodImp_PostOther( &self->infoRight );
1060 STRAND_LOGWITHNAME( self_, "Returning from PostOther(Right)" );
1061 return res;
1062 }
1063
1064 //------------------------------------------------------------------------------------------------------------
1065 MI_Boolean _StrandMethod_Right_AckOther( _In_ Strand* self_)
1066 {
1067 StrandBoth* self = (StrandBoth*)self_;
1068
1069 _Strand_Ack_Imp( &self->infoRight );
1070 STRAND_LOGWITHNAME( self_, "Returning from AckOther(Right)" );
1071 return MI_FALSE;
1072 krisbash 1.1 }
1073
1074 //------------------------------------------------------------------------------------------------------------
1075 MI_Boolean _StrandMethod_Right_CloseOther( _In_ Strand* self_)
1076 {
1077 StrandBoth* self = (StrandBoth*)self_;
1078
1079 _Strand_Close_Imp( &self->infoRight );
1080 STRAND_LOGWITHNAME( self_, "Returning from CloseOther(Right)" );
1081 return MI_FALSE;
1082 }
1083
1084 //------------------------------------------------------------------------------------------------------------
1085 MI_Boolean _StrandMethod_Both_CancelSelf( _In_ Strand* self_)
1086 {
1087 StrandBoth* self = (StrandBoth*)self_;
1088
1089 Strand_Cancel( &self->base );
1090 STRAND_LOGWITHNAME( self_, "Returning from CancelSelf(Both)" );
1091 return MI_FALSE;
1092 }
1093 krisbash 1.1
1094 //------------------------------------------------------------------------------------------------------------
1095 MI_Boolean _StrandMethod_Right_Aux0( _In_ Strand* self_)
1096 {
1097 StrandBoth* self = (StrandBoth*)self_;
1098 DEBUG_ASSERT( NULL != self->infoRight.userFT->Aux0 );
1099
1100 self->infoRight.userFT->Aux0( self_ );
1101 return MI_FALSE;
1102 }
1103
1104 MI_Boolean _StrandMethod_Right_Aux1( _In_ Strand* self_)
1105 {
1106 StrandBoth* self = (StrandBoth*)self_;
1107 DEBUG_ASSERT( NULL != self->infoRight.userFT->Aux1 );
1108
1109 self->infoRight.userFT->Aux1( self_ );
1110 return MI_FALSE;
1111 }
1112
1113 MI_Boolean _StrandMethod_Right_Aux2( _In_ Strand* self_)
1114 krisbash 1.1 {
1115 StrandBoth* self = (StrandBoth*)self_;
1116 DEBUG_ASSERT( NULL != self->infoRight.userFT->Aux2 );
1117
1118 self->infoRight.userFT->Aux2( self_ );
1119 return MI_FALSE;
1120 }
1121
1122 MI_Boolean _StrandMethod_Right_Aux3( _In_ Strand* self_)
1123 {
1124 StrandBoth* self = (StrandBoth*)self_;
1125 DEBUG_ASSERT( NULL != self->infoRight.userFT->Aux3 );
1126
1127 self->infoRight.userFT->Aux3( self_ );
1128 return MI_FALSE;
1129 }
1130
1131 MI_Boolean _StrandMethod_Right_Aux4( _In_ Strand* self_)
1132 {
1133 StrandBoth* self = (StrandBoth*)self_;
1134 DEBUG_ASSERT( NULL != self->infoRight.userFT->Aux4 );
1135 krisbash 1.1
1136 self->infoRight.userFT->Aux4( self_ );
1137 return MI_FALSE;
1138 }
1139
1140 //------------------------------------------------------------------------------------------------------------
1141 typedef enum _EntryOperationAction
1142 {
1143 EOContinue,
1144 EORetry,
1145 EODeleted
1146 } EntryOperationAction;
1147
1148 typedef EntryOperationAction (*StrandEntryOperation)( _In_ StrandMany* );
1149
1150 EntryOperationAction _StrandEntryOperation_Add( _In_ StrandMany* self )
1151 {
1152 MI_Boolean failed = MI_FALSE;
1153 MI_Boolean added = MI_FALSE;
1154 Message * msg = self->currentEntry->strand.info.stored.msg;
1155
1156 krisbash 1.1 DEBUG_ASSERT( NULL != self->userInternalFT->NewEntry );
1157
1158 if( self->strand.canceled )
1159 {
1160 trace_StrandEntryOperation_AddCanceled(
1161 (unsigned int)self->numEntries,
1162 self,
1163 STRAND_DEBUG_GETNAME(&self->strand),
1164 &self->currentEntry->strand,
1165 STRAND_DEBUG_GETNAME(&self->currentEntry->strand) );
1166 failed = MI_TRUE;
1167 // we dont even call the user method in this case
1168 }
1169 else
1170 {
1171 if( HashMap_Insert( &self->many, &self->currentEntry->bucket ) )
1172 {
1173 trace_StrandEntryOperation_AddFailed(
1174 (unsigned int)self->numEntries,
1175 self,
1176 STRAND_DEBUG_GETNAME(&self->strand),
1177 krisbash 1.1 &self->currentEntry->strand,
1178 STRAND_DEBUG_GETNAME(&self->currentEntry->strand) );
1179 failed = MI_TRUE;
1180 }
1181 else
1182 {
1183 ++(self->numEntries);
1184
1185 trace_StrandEntryOperation_Add(
1186 (unsigned int)self->numEntries,
1187 self,
1188 STRAND_DEBUG_GETNAME(&self->strand),
1189 &self->currentEntry->strand,
1190 STRAND_DEBUG_GETNAME(&self->currentEntry->strand) );
1191
1192 added = MI_TRUE;
1193 }
1194
1195 if( NULL != self->userInternalFT && NULL != self->userInternalFT->NewEntry )
1196 {
1197 self->userInternalFT->NewEntry( self, self->currentEntry, msg, &failed );
1198 krisbash 1.1 }
1199 }
1200
1201 if( NULL != msg )
1202 {
1203 if( failed || NULL == self->userInternalFT || NULL == self->userInternalFT->AddedToParent )
1204 {
1205 self->currentEntry->strand.info.stored.msg = NULL;
1206 Message_Release(msg);
1207 }
1208 // Else: We dont release the message in this case (we keep it on 'stored')
1209 // It will be deleted once the AddedToParent method is executed
1210 }
1211
1212 if( failed )
1213 {
1214 if( added )
1215 {
1216 StrandMany_DeleteEntry( self->currentEntry );
1217 }
1218 else
1219 krisbash 1.1 {
1220 SList_Free( self->currentEntry );
1221 }
1222 return EODeleted;
1223 }
1224
1225 return EOContinue;
1226 }
1227
1228 EntryOperationAction _StrandEntryOperation_Cancel( _In_ StrandMany* self )
1229 {
1230 trace_StrandEntryOperation_Cancel( self, STRAND_DEBUG_GETNAME(&self->strand),self->strand.canceled );
1231
1232 if( !self->strand.canceled )
1233 {
1234 // since we are in the middle, always forward to the other side
1235 self->strand.info.interaction.other->ft->Cancel( self->strand.info.interaction.other );
1236 _StrandMethodImp_Cancel( &self->strand, &self->strand.info );
1237 }
1238 else if( self->strand.strandType == STRAND_TYPE_PARENTLEFT )
1239 {
1240 krisbash 1.1 // since we are in the left-middle this can be cancelation coming back from right,
1241 // so pass back to the left
1242 self->strand.info.interaction.other->ft->Cancel( self->strand.info.interaction.other );
1243 }
1244
1245 return EOContinue;
1246 }
1247
1248 EntryOperationAction _StrandEntryOperation_PostControl( _In_ StrandMany* self )
1249 {
1250 DEBUG_ASSERT( NULL != self->currentEntry->toParent.controlMsg );
1251
1252 if( self->strand.info.thisClosedOther )
1253 {
1254 trace_StrandEntryOperation_PostControl_PostIgnored(
1255 self,
1256 STRAND_DEBUG_GETNAME(&self->strand),
1257 self->currentEntry->toParent.controlMsg);
1258 }
1259 else
1260 {
1261 krisbash 1.1 trace_StrandEntryOperation_PostControl_ToParent(
1262 self,
1263 STRAND_DEBUG_GETNAME(&self->strand),
1264 self->currentEntry->toParent.controlMsg);
1265
1266 if( NULL != self->userInternalFT && NULL != self->userInternalFT->EntryPostControl )
1267 {
1268 self->userInternalFT->EntryPostControl( self, self->currentEntry->toParent.controlMsg );
1269 }
1270 else
1271 {
1272 Strand_Post( &self->strand, self->currentEntry->toParent.controlMsg );
1273 }
1274 }
1275 Message_Release( self->currentEntry->toParent.controlMsg ); // ref added on StrandEntry_PostControlParent
1276 self->currentEntry->toParent.controlMsg = NULL;
1277 return EOContinue;
1278 }
1279
1280 EntryOperationAction _StrandEntryOperation_Post( _In_ StrandMany* self )
1281 {
1282 krisbash 1.1 DEBUG_ASSERT( NULL != self->currentEntry->toParent.msg );
1283
1284 if( self->strand.info.thisClosedOther )
1285 {
1286 trace_StrandEntryOperation_Post_IgnoredAfterClose(
1287 self,
1288 STRAND_DEBUG_GETNAME(&self->strand),
1289 self->currentEntry->toParent.msg);
1290 Message_Release( self->currentEntry->toParent.msg ); // ref added on StrandEntry_PostParent
1291 self->currentEntry->toParent.msg = NULL;
1292 return EOContinue;
1293 }
1294
1295 if( !self->strand.info.thisAckPending )
1296 {
1297 trace_StrandEntryOperation_Post_ToParent(
1298 self,
1299 STRAND_DEBUG_GETNAME(&self->strand),
1300 self->currentEntry->toParent.msg);
1301
1302 if( NULL != self->userInternalFT && NULL != self->userInternalFT->EntryPost )
1303 krisbash 1.1 {
1304 self->userInternalFT->EntryPost( self, self->currentEntry->toParent.msg );
1305 }
1306 else
1307 {
1308 Strand_Post( &self->strand, self->currentEntry->toParent.msg );
1309 }
1310 Message_Release( self->currentEntry->toParent.msg ); // ref added on StrandEntry_PostParent
1311 self->currentEntry->toParent.msg = NULL;
1312 return EOContinue;
1313 }
1314 else
1315 {
1316 // trace_StrandEntryOperation_Post_CannotPostWaitingOnAck(
1317 // self,
1318 // STRAND_DEBUG_GETNAME(&self->strand),
1319 // self->currentEntry->toParent.msg);
1320 return EORetry;
1321 }
1322 }
1323
1324 krisbash 1.1 EntryOperationAction _StrandEntryOperation_Close( _In_ StrandMany* self )
1325 {
1326 trace_StrandEntryOperation_Close(
1327 self,
1328 STRAND_DEBUG_GETNAME(&self->strand),
1329 self->strand.info.thisClosedOther );
1330
1331 if( !self->strand.info.thisClosedOther )
1332 {
1333 if( NULL != self->userInternalFT && NULL != self->userInternalFT->EntryClose )
1334 {
1335 self->userInternalFT->EntryClose( self );
1336 }
1337 else
1338 {
1339 Strand_Close( &self->strand );
1340 }
1341 }
1342
1343 return EOContinue;
1344 }
1345 krisbash 1.1
1346 EntryOperationAction _StrandEntryOperation_Deleted( _In_ StrandMany* self )
1347 {
1348 trace_StrandEntryOperation_Deleted(
1349 self,
1350 STRAND_DEBUG_GETNAME(&self->strand),
1351 self->currentEntry,
1352 STRAND_DEBUG_GETNAME(&self->currentEntry->strand) );
1353
1354 StrandMany_DeleteEntry(self->currentEntry);
1355
1356 if( NULL != self->userInternalFT && NULL != self->userInternalFT->EntryDeleted )
1357 {
1358 self->userInternalFT->EntryDeleted( self );
1359 }
1360
1361 return EODeleted;
1362 }
1363
1364 EntryOperationAction _StrandEntryOperation_Aux0( _In_ StrandMany* self )
1365 {
1366 krisbash 1.1 DEBUG_ASSERT( NULL != self->strand.info.userFT->Aux0 );
1367 self->strand.info.userFT->Aux0( &self->strand );
1368 return EOContinue;
1369 }
1370
1371 EntryOperationAction _StrandEntryOperation_Aux1( _In_ StrandMany* self )
1372 {
1373 DEBUG_ASSERT( NULL != self->strand.info.userFT->Aux1 );
1374 self->strand.info.userFT->Aux1( &self->strand );
1375 return EOContinue;
1376 }
1377
1378 EntryOperationAction _StrandEntryOperation_Aux2( _In_ StrandMany* self )
1379 {
1380 DEBUG_ASSERT( NULL != self->strand.info.userFT->Aux2 );
1381 self->strand.info.userFT->Aux2( &self->strand );
1382 return EOContinue;
1383 }
1384
1385 EntryOperationAction _StrandEntryOperation_Aux3( _In_ StrandMany* self )
1386 {
1387 krisbash 1.1 DEBUG_ASSERT( NULL != self->strand.info.userFT->Aux3 );
1388 self->strand.info.userFT->Aux3( &self->strand );
1389 return EOContinue;
1390 }
1391
1392 EntryOperationAction _StrandEntryOperation_Aux4( _In_ StrandMany* self )
1393 {
1394 DEBUG_ASSERT( NULL != self->strand.info.userFT->Aux4 );
1395 self->strand.info.userFT->Aux4( &self->strand );
1396 return EOContinue;
1397 }
1398
1399 //------------------------------------------------------------------------------------------------------------
1400 static StrandEntryOperation _StrandEntryOperations_FT[] = {
1401 _StrandEntryOperation_Add,
1402 _StrandEntryOperation_Cancel,
1403 _StrandEntryOperation_PostControl,
1404 _StrandEntryOperation_Post,
1405 _StrandEntryOperation_Close,
1406 _StrandEntryOperation_Aux0,
1407 _StrandEntryOperation_Aux1,
1408 krisbash 1.1 _StrandEntryOperation_Aux2,
1409 _StrandEntryOperation_Aux3,
1410 _StrandEntryOperation_Aux4,
1411 _StrandEntryOperation_Deleted,
1412 NULL, // just give some overflow NULL methods for safety
1413 NULL,
1414 NULL };
1415
1416 //------------------------------------------------------------------------------------------------------------
1417 size_t _StrandMany_HashMapHashProc(const HashBucket* bucket)
1418 {
1419 return (size_t)bucket;
1420 }
1421
1422 int _StrandMany_HashMapEqualProc(_In_ const HashBucket* bucket1, _In_ const HashBucket* bucket2)
1423 {
1424 return bucket1 == bucket2;
1425 }
1426
1427 void _StrandMany_HashMapReleaseProc(_In_ HashBucket* bucket1)
1428 {
1429 krisbash 1.1 // nothing to do here (entry is deleted on _StrandMethod_RunPendingOperations)
1430 }
1431
1432 //------------------------------------------------------------------------------------------------------------
1433 void StrandMany_CancelAllEntries( _In_ StrandMany* self )
1434 {
1435 StrandEntry* entry;
1436 STRAND_ASSERTONSTRAND( &self->strand );
1437
1438 StrandMany_BeginIteration( self );
1439 while( NULL != (entry = StrandMany_Iterate( self )) )
1440 {
1441 StrandMany_CancelEntry( entry );
1442 }
1443 }
1444
1445 void StrandMany_CloseAllEntries( _In_ StrandMany* self )
1446 {
1447 StrandEntry* entry;
1448 STRAND_ASSERTONSTRAND( &self->strand );
1449
1450 krisbash 1.1 StrandMany_BeginIteration( self );
1451 while( NULL != (entry = StrandMany_Iterate( self )) )
1452 {
1453 StrandMany_CloseEntry( entry );
1454 }
1455 }
1456
1457 void StrandMany_PostEntry( _In_ StrandEntry* entry, _In_ Message* msg )
1458 {
1459 STRAND_ASSERTONSTRAND( &entry->parent->strand );
1460
1461 Message_AddRef( msg ); // add ref before assigning and scheduling
1462 entry->fromParent.msg = msg;
1463 _Strand_Schedule( &entry->strand, BitPostInternal );
1464 }
1465
1466 void StrandMany_PostAll( _In_ StrandMany* self, _In_ Message* msg )
1467 {
1468 StrandEntry* entry;
1469
1470 STRAND_ASSERTONSTRAND( &self->strand );
1471 krisbash 1.1
1472 StrandMany_BeginIteration( self );
1473 while( NULL != (entry = StrandMany_Iterate( self )) )
1474 {
1475 StrandMany_PostEntry( entry, msg );
1476 }
1477 }
1478
1479 MI_Boolean StrandMany_PostFindEntry( _In_ StrandMany* self, _In_ Message* msg )
1480 {
1481 StrandEntry* entry;
1482
1483 STRAND_ASSERTONSTRAND( &self->strand );
1484 DEBUG_ASSERT( NULL != self->findEntryProc );
1485
1486 entry = self->findEntryProc( self, msg );
1487 if( NULL != entry )
1488 {
1489 StrandMany_PostEntry( entry, msg );
1490 return MI_TRUE;
1491 }
1492 krisbash 1.1 else
1493 {
1494 return MI_FALSE;
1495 }
1496 }
1497
1498 void StrandMany_PostControlEntry( _In_ StrandEntry* entry, _In_ Message* msg )
1499 {
1500 STRAND_ASSERTONSTRAND( &entry->parent->strand );
1501
1502 Message_AddRef( msg ); // add ref before assigning and scheduling
1503 entry->fromParent.controlMsg = msg;
1504 _Strand_Schedule( &entry->strand, BitPostControlInternal );
1505 }
1506
1507 void StrandMany_PostControlAll( _In_ StrandMany* self, _In_ Message* msg )
1508 {
1509 StrandEntry* entry;
1510
1511 STRAND_ASSERTONSTRAND( &self->strand );
1512
1513 krisbash 1.1 StrandMany_BeginIteration( self );
1514 while( NULL != (entry = StrandMany_Iterate( self )) )
1515 {
1516 StrandMany_PostControlEntry( entry, msg );
1517 }
1518 }
1519
1520 MI_Boolean StrandMany_PostControlFindEntry( _In_ StrandMany* self, _In_ Message* msg )
1521 {
1522 StrandEntry* entry;
1523
1524 STRAND_ASSERTONSTRAND( &self->strand );
1525 DEBUG_ASSERT( NULL != self->findEntryProc );
1526
1527 entry = self->findEntryProc( self, msg );
1528 if( NULL != entry )
1529 {
1530 StrandMany_PostControlEntry( entry, msg );
1531 return MI_TRUE;
1532 }
1533 else
1534 krisbash 1.1 {
1535 return MI_FALSE;
1536 }
1537 }
1538
1539 //------------------------------------------------------------------------------------------------------------
1540 void _StrandEntry_ScheduleParent( _In_ StrandEntry* self, EntryOperationMaskType entryOperationBit )
1541 {
1542 // this can be called during creation (StrandEntry_ScheduleAdd) so we cannot call STRAND_ASSERTONSTRAND( &self->strand );
1543 if( 0 == self->operationScheduled )
1544 {
1545 self->operationScheduled = entryOperationBit;
1546 SList_PushAtomic( &self->parent->pending, &self->entry );
1547 _Strand_ScheduleEntryOperation( &self->parent->strand, MI_TRUE, &self->strand, entryOperationBit );
1548 }
1549 else
1550 {
1551 DEBUG_ASSERT( 0 == (self->operationsPending & entryOperationBit) );
1552 self->operationsPending |= entryOperationBit;
1553 }
1554 }
1555 krisbash 1.1
1556 void StrandEntry_PostParent( _In_ StrandEntry* self, _In_ Message* msg )
1557 {
1558 STRAND_ASSERTONSTRAND( &self->strand );
1559 DEBUG_ASSERT( NULL == self->toParent.msg );
1560 Message_AddRef( msg );
1561 self->toParent.msg = msg;
1562 _StrandEntry_ScheduleParent( self, BitEntryPost );
1563 }
1564
1565 void StrandEntry_PostParentPassthru( _In_ StrandEntry* self, _In_ Message* msg )
1566 {
1567 DEBUG_ASSERT( !self->ackPassthru );
1568 self->ackPassthru = MI_TRUE;
1569 StrandEntry_PostParent( self, msg );
1570 }
1571
1572 void StrandEntry_PostControlParent( _In_ StrandEntry* self, _In_ Message* msg )
1573 {
1574 STRAND_ASSERTONSTRAND( &self->strand );
1575 DEBUG_ASSERT( NULL == self->toParent.controlMsg );
1576 krisbash 1.1 Message_AddRef( msg );
1577 self->toParent.controlMsg = msg;
1578 _StrandEntry_ScheduleParent( self, BitEntryPostControl );
1579 }
1580
1581 //------------------------------------------------------------------------------------------------------------
1582 #ifdef _PREFAST_
1583 #pragma prefast (push)
1584 #pragma prefast (disable: 26001) // bogus "we know the strand points to the middle of the StrandMany struct" and Linux sal parser doesnt recognize something like _Readable_elements_(_Inexpressible_(StrandMany))
1585 #endif /* _PREFAST_ */
1586
1587 MI_Boolean _StrandMethod_Parent_CheckFinished( _In_ Strand* self_ )
1588 {
1589 StrandMany* self = StrandMany_FromStrand(self_);
1590
1591 return ( 0 == self->numEntries ) && _StrandMethodImp_CheckFinished( &self->strand.info ) && !self->strand.delayFinish;
1592 }
1593
1594 MI_Boolean _StrandMethod_Parent_Cancel( _In_ Strand* self_)
1595 {
1596 StrandMany* self = StrandMany_FromStrand(self_);
1597 krisbash 1.1
1598 STRAND_DEBUGSTATE( self_ );
1599
1600 if( !self->strand.canceled )
1601 {
1602 // if it is on the right, we dont need to pass cancel to the right
1603 // if it is on the left, canceling entries passes cancel to the right
1604
1605 // now cancel all entries
1606 StrandMany_CancelAllEntries( self );
1607
1608 _StrandMethodImp_Cancel( &self->strand, &self->strand.info );
1609 }
1610
1611 return MI_FALSE;
1612 }
1613
1614 MI_Boolean _StrandMethod_Parent_PostControl( _In_ Strand* self_)
1615 {
1616 StrandMany* self = StrandMany_FromStrand(self_);
1617
1618 krisbash 1.1 _Strand_TracePostMsg(self_, self->strand.info.stored.controlMsg, "(Control Parent)");
1619 STRAND_DEBUGSTATE( self_ );
1620 DEBUG_ASSERT( NULL != self->strand.info.stored.controlMsg );
1621
1622 if( NULL != self->strand.info.userFT->PostControl )
1623 {
1624 self->strand.info.userFT->PostControl( &self->strand, self->strand.info.stored.controlMsg );
1625 }
1626 else
1627 {
1628 if( NULL == self->findEntryProc )
1629 {
1630 // Since we dont have true searching capabilities sent to all entries
1631 StrandMany_PostControlAll( self, self->strand.info.stored.controlMsg );
1632 }
1633 else
1634 {
1635 MI_Boolean ret = StrandMany_PostControlFindEntry( self, self->strand.info.stored.controlMsg );
1636 if (!ret)
1637 {
1638 DEBUG_ASSERT( ret );
1639 krisbash 1.1 }
1640 }
1641 }
1642
1643 Message_Release( self->strand.info.stored.controlMsg ); // now we can remove the reference added on _StrandInteraction_*
1644 self->strand.info.stored.controlMsg = NULL;
1645
1646 return MI_FALSE;
1647 }
1648
1649 MI_Boolean _StrandMethod_Parent_Post( _In_ Strand* self_)
1650 {
1651 StrandMany* self = StrandMany_FromStrand( self_);
1652 Message* storedmsg = self->strand.info.stored.msg;
1653 _Strand_TracePostMsg(self_, storedmsg, "(Parent)");
1654 STRAND_DEBUGSTATE( self_ );
1655 DEBUG_ASSERT( !self->strand.info.otherAckPending );
1656 DEBUG_ASSERT( NULL != storedmsg );
1657
1658 self->strand.info.stored.msg = NULL;
1659 self->strand.info.otherAckPending = MI_TRUE;
1660 krisbash 1.1
1661 if( NULL != self->strand.info.userFT->Post )
1662 {
1663 self->strand.info.userFT->Post( &self->strand, storedmsg );
1664 }
1665 else
1666 {
1667 if( NULL == self->findEntryProc )
1668 {
1669 // Since we dont have true searching capabilities sent to all entries
1670 StrandMany_PostAll( self, storedmsg );
1671 }
1672 else
1673 {
1674 MI_Boolean ret = StrandMany_PostFindEntry( self, storedmsg );
1675 if (!ret)
1676 {
1677 DEBUG_ASSERT( ret );
1678 }
1679 }
1680
1681 krisbash 1.1 Strand_Ack( &self->strand );
1682 }
1683
1684 Message_Release( storedmsg ); // now we can remove the reference added on _StrandInteraction_*
1685
1686 return MI_FALSE;
1687 }
1688
1689 #ifdef _PREFAST_
1690 #pragma prefast (pop)
1691 #endif /* _PREFAST_ */
1692
1693 void _StrandMethod_Parent_RunPendingOperations( _In_ StrandMany * self )
1694 {
1695 unsigned long bitIndex;
1696 SListHead retryList;
1697 SListEntry * retryEntry;
1698
1699 DEBUG_ASSERT( NULL == self->currentEntry );
1700
1701 SList_Init( &retryList );
1702 krisbash 1.1 self->pendingRetry = MI_FALSE;
1703
1704 while( NULL != ( self->currentEntry = (StrandEntry*)SList_PopAtomic( &self->pending ) ) )
1705 {
1706 bitIndex = GetFirstSetLSB( self->currentEntry->operationScheduled );
1707 DEBUG_ASSERT( bitIndex );
1708
1709 // trace_Strand_RunPendingOp(
1710 // &self->strand,
1711 // STRAND_DEBUG_GETNAME(&self->strand),
1712 // bitIndex,
1713 // STRAND_DEBUG_GETOPERATIONINDEX(&self->strand,bitIndex) );
1714
1715 switch( (*_StrandEntryOperations_FT[ bitIndex-1 ])(self) )
1716 {
1717 case EORetry:
1718 // trace_Strand_RunPendingOp_CannotComplete(
1719 // &self->strand,
1720 // STRAND_DEBUG_GETNAME(&self->strand),
1721 // bitIndex,
1722 // STRAND_DEBUG_GETOPERATIONINDEX(&self->strand,bitIndex) );
1723 krisbash 1.1
1724 // We will retry when ack arrives
1725 self->pendingRetry = MI_TRUE;
1726 SList_PushAtomic( &retryList, &self->currentEntry->entry );
1727 break;
1728 case EODeleted:
1729 // Special case, we delete the entry here and we do not send back any completion to the entry
1730 trace_Strand_RunPendingOp_EntryDeleted(
1731 &self->strand,
1732 STRAND_DEBUG_GETNAME(&self->strand),
1733 bitIndex,
1734 STRAND_DEBUG_GETOPERATIONINDEX(&self->strand,bitIndex) );
1735 break;
1736 case EOContinue:
1737 // schedule completion to entry
1738 _Strand_ScheduleEntryOperation( &self->currentEntry->strand, MI_FALSE, &self->strand, self->currentEntry->operationScheduled );
1739 break;
1740 default:
1741 DEBUG_ASSERT( MI_FALSE );
1742 }
1743 }
1744 krisbash 1.1
1745 // push back into the list the ones we couldn't execute
1746 while( NULL != ( retryEntry = SList_PopAtomic( &retryList ) ) )
1747 {
1748 SList_PushAtomic( &self->pending, retryEntry );
1749 }
1750
1751 self->currentEntry = NULL;
1752 }
1753
1754 MI_Boolean _StrandMethod_Parent_Ack( _In_ Strand* self_)
1755 {
1756 StrandMany* self = StrandMany_FromStrand(self_);
1757
1758 STRAND_DEBUGSTATE( self_ );
1759
1760 _StrandMethodImp_Ack( &self->strand, &self->strand.info );
1761
1762 // Check if there is any entry waiting to be processed
1763 if( self->pendingRetry )
1764 {
1765 krisbash 1.1 // Can't run _StrandMethod_RunPendingOperations directly,
1766 // because otherwise that can do a Post and then
1767 // the Ack to that post may come while we have not leave
1768 // the current Ack (and therefore schedule will assert
1769 // because it would try to schedule an Ack while other is
1770 // already running)
1771 _Strand_ScheduleEntryOperation(&self->strand, MI_TRUE, NULL, 0 );
1772 }
1773 // Note that there is no problem if some entry race to insert something in the list
1774 // after the check, as that entry will also schedule the EntryOperation itself
1775
1776 return MI_FALSE;
1777 }
1778
1779 MI_Boolean _StrandMethod_Parent_EntryOperation( _In_ Strand* self_)
1780 {
1781 StrandMany* self = StrandMany_FromStrand(self_);
1782
1783 _StrandMethod_Parent_RunPendingOperations( self );
1784
1785 return MI_FALSE;
1786 krisbash 1.1 }
1787
1788 MI_Boolean _StrandMethod_Parent_Close( _In_ Strand* self_)
1789 {
1790 StrandMany* self = StrandMany_FromStrand(self_);
1791
1792 STRAND_DEBUGSTATE( self_ );
1793
1794 _StrandMethodImp_Close( &self->strand, &self->strand.info );
1795
1796 // now if there is no method close all entries
1797 if( NULL == self->strand.info.userFT->Close )
1798 {
1799 StrandMany_CloseAllEntries( self );
1800 }
1801
1802 return MI_FALSE;
1803 }
1804
1805 MI_Boolean _StrandMethod_Parent_CancelInternal( _In_ Strand* self_)
1806 {
1807 krisbash 1.1 DEBUG_ASSERT( MI_FALSE ); // this should never be scheduled on the parent but a EntryOperation should be used instead
1808 return MI_FALSE;
1809 }
1810
1811 MI_Boolean _StrandMethod_Parent_PostControlInternal( _In_ Strand* self_)
1812 {
1813 DEBUG_ASSERT( MI_FALSE ); // this should never be scheduled on the parent but a EntryOperation should be used instead
1814 return MI_FALSE;
1815 }
1816
1817 MI_Boolean _StrandMethod_Parent_PostInternal( _In_ Strand* self_)
1818 {
1819 DEBUG_ASSERT( MI_FALSE ); // this should never be scheduled on the parent but a EntryOperation should be used instead
1820 return MI_FALSE;
1821 }
1822
1823 MI_Boolean _StrandMethod_Parent_AckInternal( _In_ Strand* self_)
1824 {
1825 DEBUG_ASSERT( MI_FALSE ); // this should never be scheduled on the parent (EntryOperation cannot be used either)
1826 return MI_FALSE;
1827 }
1828 krisbash 1.1
1829 MI_Boolean _StrandMethod_Parent_CloseInternal( _In_ Strand* self_)
1830 {
1831 DEBUG_ASSERT( MI_FALSE ); // this should never be scheduled on the parent but a EntryOperation should be used instead
1832 return MI_FALSE;
1833 }
1834
1835 //------------------------------------------------------------------------------------------------------------
1836 MI_Boolean _StrandMethod_Entry_CheckFinished( _In_ Strand* self_ )
1837 {
1838 StrandEntry* self = StrandEntry_FromStrand(self_);
1839
1840 return ( 0 == self->operationScheduled ) && ( 0 == self->operationsPending ) && _StrandMethodImp_CheckFinished( &self->strand.info ) && !self->strand.delayFinish;
1841 }
1842
1843 MI_Boolean _StrandMethod_Entry_Cancel( _In_ Strand* self_)
1844 {
1845 StrandEntry* self = StrandEntry_FromStrand(self_);
1846
1847 STRAND_DEBUGSTATE( self_ );
1848
1849 krisbash 1.1 if( !self->strand.canceled )
1850 {
1851 self->strand.canceled = MI_TRUE;
1852
1853 // if it is on the right, we dont need to pass cancel to the right
1854 // if it is on the left, canceling parent passes cancel to the right
1855
1856 if( NULL != self->strand.info.userFT->Cancel )
1857 {
1858 (*self->strand.info.userFT->Cancel)(self_);
1859 }
1860 else
1861 {
1862 StrandEntry_CancelParent(self);
1863 }
1864 }
1865
1866 return MI_FALSE;
1867 }
1868
1869 MI_Boolean _StrandMethod_Entry_PostControl( _In_ Strand* self_)
1870 krisbash 1.1 {
1871 StrandEntry* self = StrandEntry_FromStrand(self_);
1872
1873 _Strand_TracePostMsg(self_, self->strand.info.stored.controlMsg, "(Control Entry)");
1874 STRAND_DEBUGSTATE( self_ );
1875 DEBUG_ASSERT( NULL != self->strand.info.stored.controlMsg );
1876
1877 if( NULL != self->strand.info.userFT->PostControl )
1878 {
1879 self->strand.info.userFT->PostControl( &self->strand, self->strand.info.stored.controlMsg );
1880 }
1881 else
1882 {
1883 StrandEntry_PostControlParent( self, self->strand.info.stored.controlMsg );
1884 }
1885
1886 Message_Release( self->strand.info.stored.controlMsg ); // now we can remove the reference added on _StrandInteraction_*
1887 self->strand.info.stored.controlMsg = NULL;
1888
1889 return MI_FALSE;
1890 }
1891 krisbash 1.1
1892 MI_Boolean _StrandMethod_Entry_Post( _In_ Strand* self_)
1893 {
1894 StrandEntry* self = StrandEntry_FromStrand(self_);
1895 Message* storedmsg = self->strand.info.stored.msg;
1896 _Strand_TracePostMsg(self_, storedmsg, "(Entry)");
1897 STRAND_DEBUGSTATE( self_ );
1898 DEBUG_ASSERT( !self->strand.info.otherAckPending );
1899 DEBUG_ASSERT( NULL != storedmsg );
1900 self->strand.info.stored.msg = NULL;
1901 self->strand.info.otherAckPending = MI_TRUE;
1902
1903 if( NULL != self->strand.info.userFT->Post )
1904 {
1905 self->strand.info.userFT->Post( &self->strand, storedmsg );
1906 }
1907 else
1908 {
1909 StrandEntry_PostParentPassthru( self, storedmsg );
1910 }
1911
1912 krisbash 1.1 Message_Release( storedmsg ); // now we can remove the reference added on _StrandInteraction_*
1913
1914 return MI_FALSE;
1915 }
1916
1917 MI_Boolean _StrandMethod_Entry_Ack( _In_ Strand* self_)
1918 {
1919 STRAND_DEBUGSTATE( self_ );
1920
1921 _StrandMethodImp_Ack( self_, &self_->info );
1922
1923 return MI_FALSE;
1924 }
1925
1926 #ifdef _PREFAST_
1927 #pragma prefast (push)
1928 #pragma prefast (disable: 26001) // bogus "we know the strand points to the middle of the StrandEntry struct" and Linux sal parser doesnt recognize something like _Readable_elements_(_Inexpressible_(StrandEntry))
1929 #endif /* _PREFAST_ */
1930
1931 MI_Boolean _StrandMethod_Entry_EntryOperation( _In_ Strand* self_)
1932 {
1933 krisbash 1.1 StrandEntry* self = StrandEntry_FromStrand(self_);
1934 EntryOperationMaskType operationLastScheduled = self->operationScheduled;
1935
1936 if( 0 != self->operationsPending )
1937 {
1938 // schedule the next one
1939 unsigned long bitIndex;
1940 EntryOperationMaskType entryOperationBit;
1941
1942 bitIndex = GetFirstSetLSB( self->operationsPending );
1943 DEBUG_ASSERT( bitIndex );
1944 entryOperationBit = (EntryOperationMaskType)_GetMethodBit( bitIndex );
1945
1946 self->operationScheduled = entryOperationBit;
1947 self->operationsPending &= (~entryOperationBit);
1948
1949 SList_PushAtomic( &self->parent->pending, &self->entry );
1950 _Strand_ScheduleEntryOperation( &self->parent->strand, MI_TRUE, &self->strand, entryOperationBit );
1951 }
1952 else
1953 {
1954 krisbash 1.1 self->operationScheduled = 0;
1955 }
1956
1957 if( BitEntryPost == operationLastScheduled )
1958 {
1959 if( NULL != self->parent->userInternalFT && NULL != self->parent->userInternalFT->ParentAck )
1960 {
1961 self->parent->userInternalFT->ParentAck( self );
1962 }
1963 else if( self->ackPassthru )
1964 {
1965 // Now we can send the Ack to the interaction
1966 Strand_Ack(self_);
1967 }
1968 self->ackPassthru = MI_FALSE;
1969 }
1970 else if( BitEntryAdd == operationLastScheduled && NULL != self->parent->userInternalFT && NULL != self->parent->userInternalFT->AddedToParent )
1971 {
1972 Message* storedmsg = self->strand.info.stored.msg;
1973 self->strand.info.stored.msg = NULL;
1974 self->parent->userInternalFT->AddedToParent( self, storedmsg );
1975 krisbash 1.1 if( NULL != storedmsg )
1976 {
1977 _Strand_TracePostMsg(self_, storedmsg, "(EntryAddedToParent)");
1978 Message_Release( storedmsg ); // now we can finally remove the reference added on ScheduleAdd
1979 }
1980 }
1981
1982 return MI_FALSE;
1983 }
1984
1985 MI_Boolean _StrandMethod_Entry_Close( _In_ Strand* self_)
1986 {
1987 STRAND_DEBUGSTATE( self_ );
1988
1989 _StrandMethodImp_Close( self_, &self_->info );
1990
1991 return MI_FALSE;
1992 }
1993
1994 MI_Boolean _StrandMethod_Entry_CancelInternal( _In_ Strand* self_)
1995 {
1996 krisbash 1.1 StrandEntry* self = StrandEntry_FromStrand(self_);
1997
1998 trace_StrandMethod_Entry_CancelInternal( self_, STRAND_DEBUG_GETNAME(self_) );
1999
2000 if( !self_->canceled )
2001 {
2002 if( self_->info.opened )
2003 {
2004 if( !self_->info.thisClosedOther )
2005 {
2006 // since we are in the middle, forward to the other side
2007 self_->info.interaction.other->ft->Cancel( self_->info.interaction.other );
2008 }
2009 _StrandMethodImp_Cancel( self_, &self_->info );
2010 }
2011 else
2012 {
2013 // If it was not even opened we dont even call the cancel method
2014 self_->canceled = MI_TRUE;
2015 }
2016 }
2017 krisbash 1.1 else if( self->parent->strand.strandType == STRAND_TYPE_PARENTRIGHT && self_->info.opened && !self_->info.thisClosedOther )
2018 {
2019 // since we are in the left-middle this can be cancelation coming back from right,
2020 // so pass back to the left
2021 self_->info.interaction.other->ft->Cancel( self_->info.interaction.other );
2022 }
2023 return MI_FALSE;
2024 }
2025
2026 MI_Boolean _StrandMethod_Entry_PostControlInternal( _In_ Strand* self_)
2027 {
2028 StrandEntry* self = StrandEntry_FromStrand(self_);
2029
2030 DEBUG_ASSERT( NULL != self->fromParent.controlMsg );
2031
2032 trace_StrandMethod_Entry_PostControlInternal(self_, STRAND_DEBUG_GETNAME(self_), self->fromParent.controlMsg);
2033
2034 if( NULL != self->parent->userInternalFT && NULL != self->parent->userInternalFT->ParentPostControl )
2035 {
2036 self->parent->userInternalFT->ParentPostControl( self, self->fromParent.controlMsg );
2037 }
2038 krisbash 1.1 else
2039 {
2040 Strand_PostControl( self_, self->fromParent.controlMsg );
2041 }
2042
2043 Message_Release( self->fromParent.controlMsg ); // ref added on StrandMany_PostControlEntry
2044 self->fromParent.controlMsg = NULL;
2045
2046 return MI_FALSE;
2047 }
2048
2049 MI_Boolean _StrandMethod_Entry_PostInternal( _In_ Strand* self_)
2050 {
2051 StrandEntry* self = StrandEntry_FromStrand( self_);
2052
2053 DEBUG_ASSERT( NULL != self->fromParent.msg );
2054 DEBUG_ASSERT( !self->strand.info.thisAckPending ); // user is responsible to manage flow control if there are secondary messages
2055
2056 trace_StrandMethod_Entry_PostInternal(self_, STRAND_DEBUG_GETNAME(self_), self->fromParent.msg);
2057
2058 if( NULL != self->parent->userInternalFT && NULL != self->parent->userInternalFT->ParentPost )
2059 krisbash 1.1 {
2060 self->parent->userInternalFT->ParentPost( self, self->fromParent.msg );
2061 }
2062 else
2063 {
2064 Strand_Post( self_, self->fromParent.msg );
2065 }
2066
2067 Message_Release( self->fromParent.msg ); // ref added on StrandMany_PostEntry
2068 self->fromParent.msg = NULL;
2069
2070 return MI_FALSE;
2071 }
2072
2073 #ifdef _PREFAST_
2074 #pragma prefast (pop)
2075 #endif /* _PREFAST_ */
2076
2077 MI_Boolean _StrandMethod_Entry_AckInternal( _In_ Strand* self_)
2078 {
2079 trace_StrandMethod_Entry_AckInternal( self_, STRAND_DEBUG_GETNAME(self_) );
2080 krisbash 1.1
2081 Strand_Ack( self_ );
2082
2083 return MI_FALSE;
2084 }
2085
2086 MI_Boolean _StrandMethod_Entry_CloseInternal( _In_ Strand* self_)
2087 {
2088 StrandEntry* self = StrandEntry_FromStrand(self_);
2089
2090 trace_StrandMethod_Entry_CloseInternal(
2091 self_,
2092 STRAND_DEBUG_GETNAME(self_),
2093 self_->info.opened,
2094 self_->info.thisClosedOther );
2095
2096 if( NULL != self->parent->userInternalFT && NULL != self->parent->userInternalFT->ParentClose )
2097 {
2098 self->parent->userInternalFT->ParentClose( self );
2099 }
2100 else if( self_->info.opened && !self_->info.thisClosedOther )
2101 krisbash 1.1 {
2102 Strand_Close( self_ );
2103 }
2104
2105 return MI_FALSE;
2106 }
2107
2108 //------------------------------------------------------------------------------------------------------------
2109 static InteractionFT _StrandInteraction_FT = {
2110 _StrandInteraction_Post,
2111 _StrandInteraction_PostControl,
2112 _StrandInteraction_Ack,
2113 _StrandInteraction_Cancel,
2114 _StrandInteraction_Close };
2115
2116 //------------------------------------------------------------------------------------------------------------
2117 static InteractionFT _StrandInteraction_Left_FT = {
2118 _StrandInteraction_Left_Post,
2119 _StrandInteraction_Left_PostControl,
2120 _StrandInteraction_Left_Ack,
2121 _StrandInteraction_Left_Cancel,
2122 krisbash 1.1 _StrandInteraction_Left_Close };
2123
2124 //------------------------------------------------------------------------------------------------------------
2125 static InteractionFT _StrandInteraction_Right_FT = {
2126 _StrandInteraction_Right_Post,
2127 _StrandInteraction_Right_PostControl,
2128 _StrandInteraction_Right_Ack,
2129 _StrandInteraction_Right_Cancel,
2130 _StrandInteraction_Right_Close };
2131
2132 //------------------------------------------------------------------------------------------------------------
2133 static InteractionFT _StrandInteraction_Many_FT = {
2134 _StrandInteraction_Many_Post,
2135 _StrandInteraction_Many_PostControl,
2136 _StrandInteraction_Many_Ack,
2137 _StrandInteraction_Many_Cancel,
2138 _StrandInteraction_Many_Close };
2139
2140 //------------------------------------------------------------------------------------------------------------
2141 static StrandMethod _StrandMethods_FT[] = {
2142 _StrandMethod_CheckFinished,
2143 krisbash 1.1 _StrandMethod_CompleteOpenAsync,
2144 _StrandMethod_Timer,
2145 _StrandMethod_Cancel,
2146 _StrandMethod_CancelSelf,
2147 _StrandMethod_PostControl,
2148 _StrandMethod_Post,
2149 _StrandMethod_PostOther,
2150 _StrandMethod_Ack,
2151 _StrandMethod_AckOther,
2152 _StrandMethod_Close,
2153 _StrandMethod_CloseOther,
2154 _StrandMethod_Aux0,
2155 _StrandMethod_Aux1,
2156 _StrandMethod_Aux2,
2157 _StrandMethod_Aux3,
2158 _StrandMethod_Aux4,
2159 NULL, // just give some overflow NULL methods for safety
2160 NULL,
2161 NULL };
2162
2163 //------------------------------------------------------------------------------------------------------------
2164 krisbash 1.1 static StrandMethod _StrandMethods_Both_FT[] = {
2165 _StrandMethod_Both_CheckFinished,
2166 _StrandMethod_Both_CompleteOpenAsync,
2167 _StrandMethod_Timer,
2168 _StrandMethod_Left_Cancel,
2169 _StrandMethod_Right_Cancel,
2170 _StrandMethod_Both_CancelSelf,
2171 _StrandMethod_Left_PostControl,
2172 _StrandMethod_Right_PostControl,
2173 _StrandMethod_Left_Post,
2174 _StrandMethod_Right_Post,
2175 _StrandMethod_PostOther,
2176 _StrandMethod_Right_PostOther,
2177 _StrandMethod_Left_Ack,
2178 _StrandMethod_Right_Ack,
2179 _StrandMethod_AckOther,
2180 _StrandMethod_Right_AckOther,
2181 _StrandMethod_Left_Close,
2182 _StrandMethod_Right_Close,
2183 _StrandMethod_CloseOther,
2184 _StrandMethod_Right_CloseOther,
2185 krisbash 1.1 _StrandMethod_Aux0,
2186 _StrandMethod_Aux1,
2187 _StrandMethod_Aux2,
2188 _StrandMethod_Aux3,
2189 _StrandMethod_Aux4,
2190 _StrandMethod_Right_Aux0,
2191 _StrandMethod_Right_Aux1,
2192 _StrandMethod_Right_Aux2,
2193 _StrandMethod_Right_Aux3,
2194 _StrandMethod_Right_Aux4,
2195 NULL, // just give some overflow NULL methods for safety
2196 NULL,
2197 NULL };
2198
2199 //------------------------------------------------------------------------------------------------------------
2200 static StrandMethod _StrandMethods_Parent_FT[] = {
2201 _StrandMethod_Parent_CheckFinished,
2202 _StrandMethod_CompleteOpenAsync,
2203 _StrandMethod_Timer,
2204 _StrandMethod_Parent_Cancel,
2205 _StrandMethod_CancelSelf,
2206 krisbash 1.1 _StrandMethod_Parent_CancelInternal,
2207 _StrandMethod_Parent_PostControl,
2208 _StrandMethod_Parent_PostControlInternal,
2209 _StrandMethod_Parent_Post,
2210 _StrandMethod_PostOther,
2211 _StrandMethod_Parent_PostInternal,
2212 _StrandMethod_Parent_Ack,
2213 _StrandMethod_AckOther,
2214 _StrandMethod_Parent_AckInternal,
2215 _StrandMethod_Parent_EntryOperation,
2216 _StrandMethod_Parent_Close,
2217 _StrandMethod_CloseOther,
2218 _StrandMethod_Parent_CloseInternal,
2219 _StrandMethod_Aux0,
2220 _StrandMethod_Aux1,
2221 _StrandMethod_Aux2,
2222 _StrandMethod_Aux3,
2223 _StrandMethod_Aux4,
2224 NULL, // just give some overflow NULL methods for safety
2225 NULL,
2226 NULL };
2227 krisbash 1.1
2228 //------------------------------------------------------------------------------------------------------------
2229 static StrandMethod _StrandMethods_Entry_FT[] = {
2230 _StrandMethod_Entry_CheckFinished,
2231 _StrandMethod_CompleteOpenAsync,
2232 _StrandMethod_Timer,
2233 _StrandMethod_Entry_Cancel,
2234 _StrandMethod_CancelSelf,
2235 _StrandMethod_Entry_CancelInternal,
2236 _StrandMethod_Entry_PostControl,
2237 _StrandMethod_Entry_PostControlInternal,
2238 _StrandMethod_Entry_Post,
2239 _StrandMethod_PostOther,
2240 _StrandMethod_Entry_PostInternal,
2241 _StrandMethod_Entry_Ack,
2242 _StrandMethod_AckOther,
2243 _StrandMethod_Entry_AckInternal,
2244 _StrandMethod_Entry_EntryOperation,
2245 _StrandMethod_Entry_Close,
2246 _StrandMethod_CloseOther,
2247 _StrandMethod_Entry_CloseInternal,
2248 krisbash 1.1 _StrandMethod_Aux0,
2249 _StrandMethod_Aux1,
2250 _StrandMethod_Aux2,
2251 _StrandMethod_Aux3,
2252 _StrandMethod_Aux4,
2253 NULL, // just give some overflow NULL methods for safety
2254 NULL,
2255 NULL };
2256
2257 //------------------------------------------------------------------------------------------------------------
2258 MI_INLINE
2259 void _Strand_EnterStrand( _In_ Strand* self )
2260 {
2261 trace_Strand_EnterStrand( self, STRAND_DEBUG_GETNAME(self) );
2262
2263 DEBUG_ASSERT( NULL == self->strandStealedFlag );
2264 DEBUG_ASSERT( 0 == self->stateScheduled );
2265 self->stateScheduled = BitExecuting;
2266
2267 _Strand_SetCurrentStrandThread( self );
2268 }
2269 krisbash 1.1
2270 // Only used internally
2271 MI_INLINE
2272 void _Strand_ExitStrand( _In_ Strand* self )
2273 {
2274 trace_Strand_ExitStrand( self, STRAND_DEBUG_GETNAME(self) );
2275
2276 DEBUG_ASSERT( NULL == self->strandStealedFlag );
2277 DEBUG_ASSERT( BitExecuting == self->stateScheduled );
2278 self->stateScheduled = 0;
2279
2280 _Strand_ExitCurrentStrandThread( self );
2281 }
2282
2283 MI_INLINE
2284 Strand* _Strand_Create(
2285 size_t structSize,
2286 _Inout_ StrandFlags* flags )
2287 {
2288 Strand* self;
2289
2290 krisbash 1.1 DEBUG_ASSERT( structSize >= sizeof(Strand) );
2291
2292 /* Allocate heap space for Strand */
2293 if( 0 != (*flags & STRAND_FLAG_NOZEROALLOCATED) )
2294 {
2295 *flags &= (~STRAND_FLAG_NOZEROALLOCATED); // To indicate Strand*_Init that it does need to zero the strand fields
2296 self = PAL_Malloc( structSize );
2297 }
2298 else
2299 {
2300 *flags |= STRAND_FLAG_NOZEROALLOCATED; // To indicate Strand*_Init that it doesnt need to zero the strand fields
2301 self = PAL_Calloc( 1, structSize );
2302 }
2303
2304 return self;
2305 }
2306
2307 MI_INLINE
2308 void _Strand_CreateEnterStrand(
2309 #if defined(STRAND_ENABLE_DEBUG)
2310 _In_ StrandDebugInfo debug,
2311 krisbash 1.1 #endif
2312 _In_ Strand* self)
2313 {
2314 STRAND_SETDEBUG( self, debug );
2315
2316 _Strand_EnterStrand(self);
2317 }
2318
2319 MI_INLINE
2320 void _Strand_CreateExitStrand(
2321 _In_ Strand* self)
2322 {
2323 if( 0 == (self->flags & STRAND_FLAG_ENTERSTRAND) )
2324 {
2325 _Strand_ExitStrand(self);
2326 }
2327 }
2328
2329 //------------------------------------------------------------------------------------------------------------
2330 Strand* Strand_New(
2331 #if defined(STRAND_ENABLE_DEBUG)
2332 krisbash 1.1 _In_ StrandDebugInfo debug,
2333 #endif
2334 _In_ StrandFT * userFT,
2335 size_t structSize,
2336 StrandFlags flags,
2337 _In_opt_ InteractionOpenParams* interactionOpenParams )
2338 {
2339 Strand* self;
2340
2341 if( 0 == structSize )
2342 structSize = sizeof( Strand );
2343
2344 self = _Strand_Create( structSize, &flags );
2345
2346 if( self )
2347 {
2348 Strand_Init( STRAND_PASSDEBUG(debug) self, userFT, flags, interactionOpenParams );
2349 }
2350
2351 return self;
2352 }
2353 krisbash 1.1
2354 void Strand_Init(
2355 #if defined(STRAND_ENABLE_DEBUG)
2356 _In_ StrandDebugInfo debug,
2357 #endif
2358 _Out_ Strand* self,
2359 _In_ StrandFT* userFT,
2360 StrandFlags flags,
2361 _In_opt_ InteractionOpenParams* interactionOpenParams )
2362 {
2363 DEBUG_ASSERT(self);
2364 DEBUG_ASSERT(userFT);
2365
2366 if( 0 == (flags & STRAND_FLAG_NOZEROALLOCATED) )
2367 {
2368 // Clear all fields in case previously they have not been cleared
2369 memset(self, 0, sizeof(Strand) );
2370 }
2371
2372 self->strandMethods = _StrandMethods_FT;
2373 self->flags = flags;
2374 krisbash 1.1 self->info.interaction.ft = &_StrandInteraction_FT;
2375 self->info.userFT = userFT;
2376
2377 _Strand_CreateEnterStrand( STRAND_PASSDEBUG(debug) self );
2378
2379 if( NULL != interactionOpenParams || 0 != (flags & STRAND_FLAG_DELAYACCEPTOPEN) )
2380 {
2381 // we are being opened on the right most
2382 self->strandType = STRAND_TYPE_RIGHTMOST;
2383 if( 0 == (flags & STRAND_FLAG_DELAYACCEPTOPEN) )
2384 {
2385 Strand_AcceptOpen( self, interactionOpenParams );
2386 }
2387 }
2388 else
2389 {
2390 if( ( flags & STRAND_FLAG_NOINTERACTION ) != 0 )
2391 {
2392 self->strandType = STRAND_TYPE_NOINTERACTION;
2393 self->info.thisClosedOther = self->info.otherClosedThis = MI_TRUE;
2394 }
2395 krisbash 1.1 else
2396 {
2397 self->strandType = STRAND_TYPE_LEFTMOST;
2398 }
2399 }
2400
2401 _Strand_CreateExitStrand( self );
2402 }
2403
2404 //------------------------------------------------------------------------------------------------------------
2405 StrandBoth* StrandBoth_New(
2406 #if defined(STRAND_ENABLE_DEBUG)
2407 _In_ StrandDebugInfo debug,
2408 #endif
2409 _In_ StrandFT* userLeftFT,
2410 _In_ StrandFT* userRightFT,
2411 size_t structSize,
2412 StrandFlags flags,
2413 _In_opt_ InteractionOpenParams* interactionOpenParams )
2414 {
2415 StrandBoth* self;
2416 krisbash 1.1
2417 if( 0 == structSize )
2418 structSize = sizeof( StrandBoth );
2419
2420 DEBUG_ASSERT( structSize >= sizeof(StrandBoth) );
2421
2422 self = (StrandBoth*) _Strand_Create( structSize, &flags );
2423
2424 if( NULL != self )
2425 {
2426 StrandBoth_Init( STRAND_PASSDEBUG(debug) self, userLeftFT, userRightFT, flags, interactionOpenParams );
2427 }
2428
2429 return self;
2430 }
2431
2432 //------------------------------------------------------------------------------------------------------------
2433 void StrandBoth_Init(
2434 #if defined(STRAND_ENABLE_DEBUG)
2435 _In_ StrandDebugInfo debug,
2436 #endif
2437 krisbash 1.1 _Out_ StrandBoth* self,
2438 _In_ StrandFT* userLeftFT,
2439 _In_ StrandFT* userRightFT,
2440 StrandFlags flags,
2441 _In_opt_ InteractionOpenParams* interactionOpenParams )
2442 {
2443 DEBUG_ASSERT(userLeftFT);
2444 DEBUG_ASSERT(userRightFT);
2445 // close should be the same for both
2446 DEBUG_ASSERT( userLeftFT->Finish == userRightFT->Finish || NULL == userRightFT->Finish );
2447 DEBUG_ASSERT( NULL != interactionOpenParams || 0 != (flags & STRAND_FLAG_DELAYACCEPTOPEN) );
2448
2449 if( 0 == (flags & STRAND_FLAG_NOZEROALLOCATED) )
2450 {
2451 // Clear all fields in case previously they have not been cleared
2452 memset(self, 0, sizeof(StrandBoth) );
2453 }
2454
2455 self->base.strandType = STRAND_TYPE_MIDDLE;
2456 self->base.strandMethods = _StrandMethods_Both_FT;
2457 self->base.flags = flags;
2458 krisbash 1.1
2459 self->base.info.interaction.ft = &_StrandInteraction_Left_FT;
2460 self->base.info.userFT = userLeftFT;
2461
2462 self->infoRight.interaction.ft = &_StrandInteraction_Right_FT;
2463 self->infoRight.userFT = userRightFT;
2464
2465 _Strand_CreateEnterStrand( STRAND_PASSDEBUG(debug) &self->base );
2466
2467 if( 0 == (flags & STRAND_FLAG_DELAYACCEPTOPEN) )
2468 {
2469 DEBUG_ASSERT( NULL != interactionOpenParams );
2470 Strand_AcceptOpen( &self->base, interactionOpenParams );
2471 }
2472
2473 _Strand_CreateExitStrand( &self->base );
2474 }
2475
2476 //------------------------------------------------------------------------------------------------------------
2477 StrandMany* StrandMany_New(
2478 #if defined(STRAND_ENABLE_DEBUG)
2479 krisbash 1.1 _In_ StrandDebugInfo debug,
2480 #endif
2481 _In_ StrandFT* userParentFT,
2482 _In_opt_ StrandManyInternalFT* userInternalFT,
2483 size_t structSize,
2484 StrandFlags flags,
2485 _In_opt_ InteractionOpenParams* interactionOpenParams, // if STRAND_FLAG_NOINTERACTION is not used and interactionOpenParams is NULL it is assumed it will open an interaction on the right
2486 size_t numLists, // numlist for the underlying Hash table, use 1 if it is not going to be searched
2487 _In_opt_ HashMapHashProc hash, // hashing func for the underlying Hash table, if NULL will use the StrandEntry pointer
2488 _In_opt_ HashMapEqualProc equal, // equal func for the underlying Hash table, can be NULL if it is not going to be searched or entry ptr comparison is ok
2489 _In_opt_ FindEntryProc findEntryProc ) // finds a entry based on a message, can be NULL if msg should not be automatically redirected to entries
2490 {
2491 StrandMany* self;
2492
2493 DEBUG_ASSERT(userParentFT);
2494
2495 if( 0 == structSize )
2496 structSize = sizeof( StrandMany );
2497
2498 DEBUG_ASSERT( structSize >= sizeof(StrandMany) );
2499
2500 krisbash 1.1 self = (StrandMany*) SList_Alloc( structSize );
2501
2502 if( NULL != self )
2503 {
2504 if( 0 != (flags & STRAND_FLAG_NOZEROALLOCATED) )
2505 {
2506 // Clear only strand fields
2507 memset(self, 0, sizeof(StrandMany) );
2508 }
2509 else
2510 {
2511 // Clear all allocated fields
2512 memset(self, 0, structSize );
2513 }
2514
2515 if( NULL == hash )
2516 hash = _StrandMany_HashMapHashProc;
2517 if( NULL == equal )
2518 equal = _StrandMany_HashMapEqualProc;
2519
2520 if( HashMap_Init( &self->many, numLists, hash, equal, _StrandMany_HashMapReleaseProc ) )
2521 krisbash 1.1 {
2522 SList_Free( self );
2523 return NULL;
2524 }
2525
2526 SList_Init( &self->pending );
2527 self->findEntryProc = findEntryProc;
2528
2529 self->userInternalFT = userInternalFT;
2530 self->strand.flags = flags;
2531 self->strand.strandMethods = _StrandMethods_Parent_FT;
2532 self->strand.info.interaction.ft = &_StrandInteraction_Many_FT;
2533 self->strand.info.userFT = userParentFT;
2534
2535 _Strand_CreateEnterStrand( STRAND_PASSDEBUG(debug) &self->strand );
2536
2537 if( 0 == (flags&STRAND_FLAG_NOINTERACTION) )
2538 {
2539 if( NULL != interactionOpenParams || 0 != (flags & STRAND_FLAG_DELAYACCEPTOPEN) )
2540 {
2541 // Parent is being opened (it is on the left)
2542 krisbash 1.1 self->strand.strandType = STRAND_TYPE_PARENTLEFT;
2543 if( 0 == (flags & STRAND_FLAG_DELAYACCEPTOPEN) )
2544 {
2545 Strand_AcceptOpen( &self->strand, interactionOpenParams );
2546 }
2547 }
2548 else
2549 {
2550 self->strand.strandType = STRAND_TYPE_PARENTRIGHT;
2551 }
2552 }
2553 else
2554 {
2555 DEBUG_ASSERT( NULL == interactionOpenParams );
2556 self->strand.strandType = STRAND_TYPE_PARENTNOINTERACTION;
2557 self->strand.info.thisClosedOther = self->strand.info.otherClosedThis = MI_TRUE;
2558 }
2559
2560 _Strand_CreateExitStrand( &self->strand );
2561 }
2562
2563 krisbash 1.1 return self;
2564 }
2565
2566 StrandEntry* StrandEntry_New(
2567 #if defined(STRAND_ENABLE_DEBUG)
2568 _In_ StrandDebugInfo debug,
2569 #endif
2570 _In_ StrandMany* parent,
2571 _In_ StrandFT* userEntryFT,
2572 size_t structSize,
2573 StrandFlags flags,
2574 _In_opt_ InteractionOpenParams* interactionOpenParams )
2575 {
2576 StrandEntry* self;
2577
2578 DEBUG_ASSERT( NULL != parent );
2579 DEBUG_ASSERT( NULL != userEntryFT );
2580
2581 if( 0 == structSize )
2582 structSize = sizeof( StrandEntry );
2583
2584 krisbash 1.1 DEBUG_ASSERT( structSize >= sizeof(StrandEntry) );
2585
2586 self = (StrandEntry*) SList_Alloc( structSize );
2587
2588 if( NULL != self )
2589 {
2590 if( 0 != (flags & STRAND_FLAG_NOZEROALLOCATED) )
2591 {
2592 // Clear only strand fields
2593 memset(self, 0, sizeof(StrandEntry) );
2594 }
2595 else
2596 {
2597 // Clear all allocated fields
2598 memset(self, 0, structSize );
2599 }
2600
2601 self->parent = parent;
2602
2603 self->strand.strandMethods = _StrandMethods_Entry_FT;
2604 self->strand.flags = flags;
2605 krisbash 1.1 self->strand.info.interaction.ft = &_StrandInteraction_Many_FT;
2606 self->strand.info.userFT = userEntryFT;
2607 self->strand.strandType = STRAND_TYPE_ENTRY;
2608
2609 _Strand_CreateEnterStrand( STRAND_PASSDEBUG(debug) &self->strand );
2610
2611 if( NULL != interactionOpenParams || 0 != (flags & STRAND_FLAG_DELAYACCEPTOPEN) )
2612 {
2613 // Entry is being opened (it is on the left)
2614 DEBUG_ASSERT( ( flags & STRAND_FLAG_NOINTERACTION ) == 0 );
2615 DEBUG_ASSERT( parent->strand.strandType == STRAND_TYPE_PARENTRIGHT || parent->strand.strandType == STRAND_TYPE_PARENTNOINTERACTION );
2616 if( 0 == (flags & STRAND_FLAG_DELAYACCEPTOPEN) )
2617 {
2618 Strand_AcceptOpen( &self->strand, interactionOpenParams );
2619 }
2620 }
2621 else
2622 {
2623 if( ( flags & STRAND_FLAG_NOINTERACTION ) != 0 )
2624 {
2625 self->strand.info.thisClosedOther = self->strand.info.otherClosedThis = MI_TRUE;
2626 krisbash 1.1 }
2627 else
2628 {
2629 DEBUG_ASSERT( parent->strand.strandType == STRAND_TYPE_PARENTLEFT || parent->strand.strandType == STRAND_TYPE_PARENTNOINTERACTION );
2630 }
2631 }
2632
2633 _Strand_CreateExitStrand( &self->strand );
2634 }
2635
2636 return self;
2637 }
2638
2639 MI_Result StrandMany_AddEntry(
2640 _In_ StrandEntry* self )
2641 {
2642 STRAND_ASSERTONSTRAND( &self->parent->strand );
2643 DEBUG_ASSERT( self->strand.info.stored.msg == NULL );
2644 if( HashMap_Insert( &self->parent->many, &self->bucket ) )
2645 {
2646 SList_Free( self );
2647 krisbash 1.1 return MI_RESULT_FAILED;
2648 }
2649
2650 ++(self->parent->numEntries);
2651
2652 if( NULL != self->parent->userInternalFT && NULL != self->parent->userInternalFT->AddedToParent )
2653 {
2654 STRAND_ASSERTONSTRAND( &self->strand );
2655 self->parent->userInternalFT->AddedToParent( self, NULL );
2656 }
2657
2658 return MI_RESULT_OK;
2659 }
2660
2661 void StrandEntry_ScheduleAdd(
2662 _In_ StrandEntry* self,
2663 _In_opt_ Message * msg ) // optional initial message
2664 {
2665 DEBUG_ASSERT( NULL != self );
2666
2667 if( NULL != msg )
2668 krisbash 1.1 {
2669 Message_AddRef(msg);
2670 self->strand.info.stored.msg = msg;
2671 }
2672 _StrandEntry_ScheduleParent(self,BitEntryAdd);
2673 }
2674
2675 void Strand_Delete( _In_ Strand* self )
2676 {
2677 if( STRAND_ISTYPE_ENTRY(self) )
2678 {
2679 StrandEntry_Delete( StrandEntry_FromStrand(self) );
2680 }
2681 else if( STRAND_ISTYPE_PARENT(self) )
2682 {
2683 StrandMany_Delete( StrandMany_FromStrand(self) );
2684 }
2685 else
2686 {
2687 STRAND_LOGWITHNAME( self, "Deleting Strand" );
2688 PAL_Free( self );
2689 krisbash 1.1 }
2690 }
2691
2692 void StrandMany_Delete( _In_ StrandMany* self )
2693 {
2694 SListEntry* entry;
2695
2696 STRAND_LOGWITHNAME( &self->strand, "Deleting StrandMany" );
2697
2698 DEBUG_ASSERT( 0 == self->numEntries );
2699 DEBUG_ASSERT( NULL == self->currentEntry );
2700
2701 HashMap_Destroy( &self->many );
2702
2703 entry = SList_FlushAtomic( &self->pending );
2704
2705 if (entry != NULL)
2706 {
2707 DEBUG_ASSERT( NULL == entry );
2708 }
2709
2710 krisbash 1.1 SList_Free( self );
2711 }
2712
2713 void StrandMany_DeleteEntry( _In_ StrandEntry* entry )
2714 {
2715 StrandMany* self = entry->parent;
2716
2717 STRAND_ASSERTONSTRAND( &self->strand );
2718
2719 trace_Strand_DeletedEntry( &self->strand, STRAND_DEBUG_GETNAME(&self->strand), &entry->strand, STRAND_DEBUG_GETNAME(&entry->strand) );
2720
2721 DEBUG_ASSERT( self->numEntries >= 1 );
2722 --(self->numEntries);
2723
2724 if( HashMap_Remove( &self->many, &entry->bucket ) )
2725 {
2726 trace_Strand_CannotDelete( &self->strand, STRAND_DEBUG_GETNAME(&self->strand), &entry->strand, STRAND_DEBUG_GETNAME(&entry->strand) );
2727 DEBUG_ASSERT( MI_FALSE ); // should not happen
2728 }
2729
2730 SList_Free( entry );
2731 krisbash 1.1 }
2732
2733 void StrandEntry_Delete( _In_ StrandEntry* self )
2734 {
2735 STRAND_LOGWITHNAME( &self->strand, "Scheduling deletion of StrandEntry" );
2736
2737 DEBUG_ASSERT( 0 == self->operationScheduled );
2738
2739 _StrandEntry_ScheduleParent( self, BitEntryDeleted );
2740 }
2741
2742 //------------------------------------------------------------------------------------------------------------
2743 void _Strand_CancelPropagate(
2744 _In_ Strand * self)
2745 {
2746 STRAND_ASSERTONSTRAND( self );
2747
2748 switch( self->strandType )
2749 {
2750 case STRAND_TYPE_MIDDLE:
2751 {
2752 krisbash 1.1 StrandBoth * selfBoth = (StrandBoth*)self;
2753
2754 if( selfBoth->infoRight.opened && !selfBoth->infoRight.thisClosedOther )
2755 {
2756 STRAND_LOGWITHNAME( self, "Canceling to the right" );
2757
2758 // first go to the right
2759 selfBoth->infoRight.interaction.other->ft->Cancel( selfBoth->infoRight.interaction.other );
2760 }
2761 }
2762 break;
2763 case STRAND_TYPE_LEFTMOST:
2764 case STRAND_TYPE_RIGHTMOST:
2765 case STRAND_TYPE_PARENTRIGHT:
2766 {
2767 if( self->info.opened && !self->info.thisClosedOther )
2768 {
2769 STRAND_LOGWITHNAME( self, "Canceling" );
2770
2771 // just go to the other side (start going right or initiate return to the left)
2772 self->info.interaction.other->ft->Cancel( self->info.interaction.other );
2773 krisbash 1.1 }
2774 }
2775 break;
2776 case STRAND_TYPE_PARENTLEFT:
2777 {
2778 StrandMany* stranMany = StrandMany_FromStrand(self);
2779
2780 STRAND_LOGWITHNAME( self, "Canceling all entries to the left" );
2781
2782 StrandMany_CancelAllEntries( stranMany );
2783 }
2784 case STRAND_TYPE_ENTRY:
2785 {
2786 StrandEntry* entry = StrandEntry_FromStrand(self);
2787
2788 if( entry->parent->strand.strandType == STRAND_TYPE_PARENTRIGHT )
2789 {
2790 if( NULL == self->info.userFT->Cancel )
2791 {
2792 STRAND_LOGWITHNAME( self, "Canceling parent from entry" );
2793
2794 krisbash 1.1 StrandEntry_CancelParent( entry );
2795 }
2796 }
2797 else
2798 {
2799 if( self->info.opened && !self->info.thisClosedOther )
2800 {
2801 STRAND_LOGWITHNAME( self, "Canceling interaction from entry" );
2802
2803 // start going right
2804 self->info.interaction.other->ft->Cancel( self->info.interaction.other );
2805 }
2806 }
2807 }
2808 break;
2809 case STRAND_TYPE_PARENTNOINTERACTION:
2810 default:
2811 DEBUG_ASSERT(MI_FALSE);
2812 }
2813 STRAND_LOGWITHNAME( self, "Returning from Canceling other (would cancel method if existent) " );
2814 }
2815 krisbash 1.1
2816 void Strand_Cancel(
2817 _In_ Strand * self)
2818 {
2819 STRAND_ASSERTONSTRAND( self );
2820
2821 if( !self->canceled )
2822 {
2823 _Strand_CancelPropagate( self );
2824
2825 _StrandMethodImp_Cancel(self, &self->info );
2826 }
2827 }
2828
2829 //------------------------------------------------------------------------------------------------------------
2830 ptrdiff_t _EnableMethodBit( _In_ Strand* self, ptrdiff_t methodBit )
2831 {
2832 ptrdiff_t initialState, newState = ReadWithFence( &self->stateScheduled );
2833
2834 do
2835 {
2836 krisbash 1.1 initialState = newState;
2837
2838 // check if bit already set
2839 DEBUG_ASSERT( (initialState & methodBit) == 0 );
2840 }
2841 while( (newState = Atomic_CompareAndSwap( &self->stateScheduled, initialState, initialState|methodBit )) != initialState );
2842
2843 return initialState|methodBit;
2844 }
2845
2846 //------------------------------------------------------------------------------------------------------------
2847 MI_INLINE ptrdiff_t _DisableMethodBit( _In_ Strand* self, ptrdiff_t methodBit )
2848 {
2849 return Atomic_And( &self->stateScheduled, ~methodBit ) & (~methodBit);
2850 }
2851
2852 //------------------------------------------------------------------------------------------------------------
2853 void _Strand_ExecuteLoop( _In_ Strand* self, ptrdiff_t state )
2854 {
2855 unsigned long bitIndex;
2856 MI_Boolean strandStealedFlag;
2857 krisbash 1.1 STRAND_DEBUG_GETSTATE_USED;
2858 STRAND_DEBUG_GETINFOSTATE_USED;
2859
2860 _Strand_SetCurrentStrandThread( self );
2861
2862 for(;;) // check new state loop
2863 {
2864 DEBUG_ASSERT( ( state & BitExecuting ) != 0 );
2865
2866 // we dont want to check on BitExecuting
2867 bitIndex = GetFirstSetLSB( state & (~BitExecuting) );
2868 if( bitIndex )
2869 {
2870 ptrdiff_t methodBit = _GetMethodBit( bitIndex );
2871
2872 strandStealedFlag = MI_FALSE;
2873 self->strandStealedFlag = &strandStealedFlag;
2874 self->currentMethodBit = methodBit;
2875
2876 DEBUG_ASSERT( bitIndex > FirstRealMethodBit );
2877
2878 krisbash 1.1 STRAND_DEBUG_GETINFOSTATE_STORE(self);
2879 trace_Strand_ExecLoop(
2880 self,
2881 STRAND_DEBUG_GETNAME(self),
2882 state,
2883 STRAND_DEBUG_GETSTATE(self, state ),
2884 bitIndex,
2885 STRAND_DEBUG_GETMETHODINDEX(self,bitIndex),
2886 STRAND_DEBUG_GETINFOSTATE_STORED );
2887
2888 (*self->strandMethods[ bitIndex-FirstRealMethodBit ])(self);
2889
2890 if( strandStealedFlag )
2891 {
2892 // if someone stealed the strand synchronously (Strand_Leave)
2893 // while the function was being executed then just bail out
2894 trace_Strand_ExecLoop_Leave(
2895 self,
2896 state,
2897 bitIndex,
2898 methodBit);
2899 krisbash 1.1 return;
2900 }
2901 else
2902 {
2903 state = _DisableMethodBit( self, methodBit );
2904 if( BitTimer == methodBit && NULL != self->timer )
2905 {
2906 // timer was restarted inside the timer method, start it now
2907 Timer_Start( self->timer, self );
2908 }
2909 else if( STRAND_ISTYPE_PARENT( self ) && BitEntryOperation == methodBit )
2910 {
2911 _StrandMethod_Parent_RunPendingOperations( StrandMany_FromStrand(self) );
2912 }
2913 }
2914 }
2915 else
2916 {
2917 ptrdiff_t newState;
2918
2919 // Nothing else scheduled, we are going to stop executing (if nothing else has changed)
2920 krisbash 1.1
2921 MI_Boolean aboutToFinish = _Strand_ShouldFinish(self);
2922
2923 DEBUG_ASSERT( BitExecuting == state );
2924
2925 /* trace_Strand_ExecLoop( self, state, aboutToFinish ); */
2926
2927 _Strand_ExitCurrentStrandThread( self );
2928
2929 // Get these two before the Atomic_CompareAndSwap (strand may be deleted after that)
2930 STRAND_DEBUG_GETNAME_STORE(self);
2931 STRAND_DEBUG_GETINFOSTATE_STORE(self);
2932
2933 newState = Atomic_CompareAndSwap( &self->stateScheduled, state, 0 );
2934 // If the state has not changed (no new method was scheduled) we can stop now
2935 if( newState == state )
2936 {
2937 trace_Strand_ExecLoop_Exits(
2938 self,
2939 STRAND_DEBUG_GETNAME_STORED,
2940 state,
2941 krisbash 1.1 aboutToFinish,
2942 STRAND_DEBUG_GETINFOSTATE_STORED );
2943 if( aboutToFinish )
2944 {
2945 _Strand_Finish( self );
2946 }
2947 return;
2948 }
2949 else
2950 {
2951 trace_Strand_ExecLoop_DoesntExit(
2952 self,
2953 STRAND_DEBUG_GETNAME(self),
2954 state,
2955 newState,
2956 STRAND_DEBUG_GETSTATE(self, newState),
2957 aboutToFinish,
2958 STRAND_DEBUG_GETINFOSTATE_STORED );
2959 state = newState;
2960
2961 // revert this
2962 krisbash 1.1 _Strand_SetCurrentStrandThread( self );
2963 }
2964 }
2965 }
2966 }
2967
2968 //------------------------------------------------------------------------------------------------------------
2969 // Schedules a method in the strand
2970 //------------------------------------------------------------------------------------------------------------
2971 #if defined(STRAND_ENABLE_DEBUG)
2972 void _Strand_ScheduleImp(
2973 _In_ Strand* self,
2974 unsigned int methodBit,
2975 MI_Boolean allowMultiSchedule,
2976 _In_opt_ Strand* fromStrand,
2977 EntryOperationMaskType entryOperationBit )
2978 #else
2979 void _Strand_ScheduleImp(
2980 _In_ Strand* self,
2981 unsigned int methodBit )
2982 #endif
2983 krisbash 1.1 {
2984 ptrdiff_t initialState, newState = ReadWithFence( &self->stateScheduled );
2985 STRAND_DEBUG_GETSTATE_USED;
2986
2987 DEBUG_ASSERT( methodBit > 0 );
2988
2989 #if defined(STRAND_ENABLE_DEBUG)
2990 if( allowMultiSchedule && BitTimer != methodBit )
2991 {
2992 trace_Strand_ScheduleParent(
2993 self,
2994 STRAND_DEBUG_GETNAME(self),
2995 newState,
2996 STRAND_DEBUG_GETSTATE(self, newState),
2997 entryOperationBit,
2998 0 == entryOperationBit ? "<re-scheduled>" : STRAND_DEBUG_GETOPERATION(self, entryOperationBit ),
2999 fromStrand,
3000 NULL == fromStrand ? "<self>" : STRAND_DEBUG_GETNAME(fromStrand),
3001 methodBit,
3002 STRAND_DEBUG_GETMETHOD(self,methodBit) );
3003 }
3004 krisbash 1.1 else if( NULL != fromStrand )
3005 {
3006 trace_Strand_ScheduleEntry(
3007 self,
3008 STRAND_DEBUG_GETNAME(self),
3009 newState,
3010 STRAND_DEBUG_GETSTATE(self, newState),
3011 entryOperationBit,
3012 STRAND_DEBUG_GETOPERATION(fromStrand, entryOperationBit ),
3013 fromStrand,
3014 STRAND_DEBUG_GETNAME(fromStrand),
3015 methodBit,
3016 STRAND_DEBUG_GETMETHOD(self,methodBit) );
3017 }
3018 else
3019 {
3020 trace_Strand_Schedule(
3021 self,
3022 STRAND_DEBUG_GETNAME(self),
3023 newState,
3024 STRAND_DEBUG_GETSTATE(self, newState),
3025 krisbash 1.1 methodBit,
3026 STRAND_DEBUG_GETMETHOD(self,methodBit) );
3027 }
3028 #else
3029 trace_Strand_Schedule2(
3030 self,
3031 newState,
3032 methodBit );
3033 #endif
3034
3035 do
3036 {
3037 initialState = newState;
3038
3039 #if defined(STRAND_ENABLE_DEBUG)
3040 // check if bit already set
3041 // otherwise Caller is violating the contract!
3042 DEBUG_ASSERT( allowMultiSchedule || (initialState & methodBit) == 0 );
3043 #endif
3044 }
3045 while( (newState = Atomic_CompareAndSwap( &self->stateScheduled, initialState, initialState|methodBit|BitExecuting )) != initialState );
3046 krisbash 1.1
3047 // Check if nobody was executing before now, then start executing
3048 if( ( initialState & BitExecuting ) == 0 )
3049 {
3050 _Strand_ExecuteLoop(self, initialState|methodBit|BitExecuting);
3051 }
3052 }
3053
3054 //------------------------------------------------------------------------------------------------------------
3055 void Strand_Leave( _In_ Strand* self )
3056 {
3057 STRAND_ASSERTONSTRAND( self );
3058
3059 trace_Strand_Leave( self, STRAND_DEBUG_GETNAME(self), self->strandStealedFlag );
3060
3061 // If there is an encompasing loop, then set this to false so it will bail out
3062 if( NULL != self->strandStealedFlag )
3063 {
3064 *(self->strandStealedFlag) = MI_TRUE;
3065 }
3066
3067 krisbash 1.1 _Strand_ExecuteLoop( self, _DisableMethodBit( self, self->currentMethodBit ) );
3068 }
3069
3070 //------------------------------------------------------------------------------------------------------------
3071 void Strand_StartTimer( _In_ Strand* self, _In_ Timer* timer, _In_ MI_Uint64 timeusecs )
3072 {
3073 STRAND_ASSERTONSTRAND( self );
3074 DEBUG_ASSERT( NULL == self->timer );
3075 DEBUG_ASSERT( timer );
3076
3077 self->timer = timer;
3078 Timer_SetTime( timer, timeusecs ); // doesnt start the actual timer
3079 if( BitTimer != self->currentMethodBit )
3080 {
3081 TimerResult result = Timer_Start( timer, self );
3082 if (TimerResult_Success != result)
3083 {
3084 // Cancel timer start request
3085 self->timer = NULL;
3086 trace_Strand_Cannot_Start_Timer( timer, self );
3087 }
3088 krisbash 1.1 }
3089 else
3090 {
3091 trace_Strand_Cannot_Start_Timer( timer, self );
3092 }
3093 }
3094
3095 void Strand_FireTimer( _In_ Strand* self )
3096 {
3097 STRAND_ASSERTONSTRAND( self );
3098
3099 if( NULL != self->timer )
3100 {
3101 Timer_Fire( self->timer, self, TimerReason_ManuallyFired );
3102 }
3103 else
3104 {
3105 trace_Strand_Cannot_Fire_Timer( self );
3106 }
3107 }
3108
3109 krisbash 1.1 MI_Boolean Strand_HaveTimer( _In_ Strand* self )
3110 {
3111 STRAND_ASSERTONSTRAND( self );
3112
3113 if ( self->timer )
3114 return MI_TRUE;
3115 else
3116 return MI_FALSE;
3117 }
3118
3119 //------------------------------------------------------------------------------------------------------------
3120 void _Strand_AcceptOpenCommon(
3121 _In_ Strand* self,
3122 _In_ Interaction* interaction )
3123 {
3124 STRAND_ASSERTONSTRAND( self );
3125
3126 DEBUG_ASSERT( !self->info.otherAckPending );
3127 DEBUG_ASSERT( !self->info.thisAckPending );
3128 DEBUG_ASSERT( !self->info.ackPassthru );
3129
3130 krisbash 1.1 self->info.interaction.other = interaction;
3131 interaction->other = &self->info.interaction;
3132 self->info.opened = MI_TRUE;
3133 self->info.thisClosedOther = MI_FALSE;
3134 self->info.otherClosedThis = MI_FALSE;
3135 }
3136
3137 void Strand_AcceptOpenAsync(
3138 _In_ Strand* self,
3139 _In_ Strand* otherStrand )
3140 {
3141 DEBUG_ASSERT( !STRAND_ISTYPE_MIDDLE( otherStrand ) );
3142 _Strand_AcceptOpenCommon( self, &otherStrand->info.interaction);
3143
3144 _Strand_Schedule( otherStrand, BitCompleteOpenAsync );
3145 }
3146
3147 void Strand_AcceptOpenAsyncFromStrandBoth(
3148 _In_ Strand* self,
3149 _In_ StrandBoth* otherStrand )
3150 {
3151 krisbash 1.1 DEBUG_ASSERT( STRAND_ISTYPE_MIDDLE( &otherStrand->base ) );
3152 _Strand_AcceptOpenCommon( self, &otherStrand->infoRight.interaction );
3153 otherStrand->asyncOpenInProgress = MI_TRUE;
3154 _Strand_Schedule( &otherStrand->base, BitCompleteOpenAsync );
3155 }
3156
3157 void Strand_AcceptOpen(
3158 _In_ Strand* self,
3159 _In_ InteractionOpenParams* params )
3160 {
3161 _Strand_AcceptOpenCommon( self, params->interaction );
3162
3163 if( NULL != params->msg )
3164 {
3165 self->info.otherAckPending = MI_TRUE;
3166 }
3167 if( NULL != params->origin )
3168 {
3169 Strand_Leave( params->origin );
3170 }
3171 }
3172 krisbash 1.1
3173 static void _DoNothingPost( _In_ Interaction* self, _In_ Message* msg )
3174 {
3175 MI_UNUSED( self );
3176 MI_UNUSED( msg );
3177 }
3178
3179 static void _DoNothingOther( _In_ Interaction* self )
3180 {
3181 MI_UNUSED( self );
3182 }
3183
3184 static InteractionFT _failOpenInteractionFT = {
3185 _DoNothingPost,
3186 _DoNothingPost,
3187 _DoNothingOther,
3188 _DoNothingOther,
3189 _DoNothingOther };
3190
3191 static Interaction _failOpenInteraction = { &_failOpenInteractionFT, NULL };
3192
3193 krisbash 1.1 void Strand_FailOpenWithMsg(
3194 _In_ InteractionOpenParams* params,
3195 _In_opt_ Message* msg)
3196 {
3197 params->interaction->other = &_failOpenInteraction;
3198
3199 if( NULL != params->origin )
3200 {
3201 Strand_Leave( params->origin );
3202 }
3203
3204 if( NULL != msg )
3205 {
3206 params->interaction->ft->Post( params->interaction, msg );
3207 }
3208 else
3209 {
3210 if( NULL != params->msg )
3211 {
3212 DEBUG_ASSERT( Message_IsRequest( params->msg ) );
3213 //TODO convert the original request to ResultMsg and post it back
3214 krisbash 1.1 //params->interaction->ft->Post( params->interaction, params->msg );
3215 // Cancel in the meantime:
3216 }
3217 //TODO else
3218 {
3219 params->interaction->ft->Cancel( params->interaction );
3220 }
3221 }
3222 if( NULL != params->msg )
3223 {
3224 params->interaction->ft->Ack( params->interaction );
3225 }
3226 params->interaction->ft->Close( params->interaction );
3227 }
3228
3229 void Strand_FailOpenWithResult(
3230 _In_ InteractionOpenParams* params,
3231 MI_Result result,
3232 _In_ MakeResultMessageCallback callback)
3233 {
3234 PostResultMsg* resultMsg;
3235 krisbash 1.1
3236 resultMsg = (*callback)( params->msg, NULL, NULL, MI_RESULT_TYPE_MI, result);
3237
3238 if( NULL != resultMsg )
3239 {
3240 Strand_FailOpenWithMsg( params, &resultMsg->base );
3241 PostResultMsg_Release(resultMsg);
3242 }
3243 else
3244 {
3245 Strand_FailOpen( params );
3246 }
3247 }
|