📄 scs_event.c
字号:
* sb - System Block pointer * lk_scadb - SCA database lock structure * scs_listeners - Listening SYSAP queue head * * Outputs: * * IPL_SCS - Interrupt processor level * * SMP: The SCA database is locked to postpone potential modifications * to the queue of listening SYSAPs while it is being traversed. * * The CB is locked to synchronize access and to prevent deletion. * It is indirectly locked through its CBVTE. Locking the CB also * prevents premature PB deletion as required by scs_init_cmsb(). * * The CBVTE semaphore is incremented prior to SYSAP notification * of new path existence. This prevents connection termination * while call backs are in progress. The semaphore is decremented * after SYSAP notification completes. * * The validity of the PB address must be guaranteed EXTERNALLY. * * NO EXTERNAL locks may be held when this routine is invoked. */voidscs_new_path( sb, pb ) SB *sb; PB *pb;{ CMSB cmsb; register cbq *cb; register CBVTE *cbvte; register void ( *control )(); register u_long dirid = 0; /* Iteratively scan the queue of listening SYSAPs. Each scan: * * 1. Locks the SCA database. * 2. Positions and locks the "next" CB within the queue( now the "current" * CB ). * 3. Increments the CBVTE semaphore. * 4. Unlocks the CB. * 5. Unlocks the SCA database. * 6. Notifies the SYSAP corresponding to the "current" CB of the existence * of a path to a previously unknown system. * 7. Decrements the CBVTE semaphore. * * Incrementing the appropriate CBVTE semaphore protects the connection * against termination for the duration of SYSAP notification of new path * existence and while any call backs on the connection are in progress. * Such protection is necessary because termination of listening * connections is synchronous and immediate which would allow SYSAPs to * receive notifications on connections which no longer exist if such * protection was not provided. * * Positioning to the "next" CB is accomplished by means of the "current" * CB's directory identification number. This allows positioning to be * relative and accomplished even when the "current" CB is deleted from the * the queue between iterative scans. */ do { Lock_scadb() for( cb = scs_listeners.flink; cb != &scs_listeners && Cb->cinfo.Dirid <= dirid; cb = cb->flink ) {} if( cb != &scs_listeners ) { if( Cb->cinfo.cstate != CS_LISTEN ) { ( void )panic( SCSPANIC_LQUEUE ); } cbvte = Get_cbvte( Cb->cinfo.lconnid ); Lock_cbvte( cbvte ) ( void )scs_init_cmsb( CRE_NEW_PATH, ADR_SUCCESS, &cmsb, cb, pb, 0 ); control = Cb->control; dirid = Cb->cinfo.Dirid; Incr_cbvte_sem( cbvte ) Unlock_cbvte( cbvte ) } else { control = NULL; } Unlock_scadb() if( control ) { ( void )( *control )( CRE_NEW_PATH, &cmsb ); Decr_cbvte_sem( cbvte ) } } while( cb != &scs_listeners );}/* Name: scs_path_crash - Path to System Crashed * * Abstract: This SCS event notification routine is asynchronously invoked * by PDs following path failure, disablement, and invalidation of * the appropriate port's translation cache( as required ). It * directs clean up the failed path with the ultimate goal of * removing the PB from the system-wide configuration database and * deleting it. It must only be invoked once for each path * incarnation. * * PBs passed to this routine are guaranteed to be valid because: * * 1. Path clean up is single threaded even in SMP environments. * 2. It is this routine which is responsible for directing clean * up and deallocation of PBs. * * NOTE: Once this routine is invoked the PD may only notify SCS * of the successful transmission and reception of datagrams * over this incarnation of the failed path. * * NOTE: The appropriate port drivers are always responsible for * the clean up of all port specific resources associated * with failed local ports including free datagram and * message buffers. SCS must never attempt to dispose of * such resources during clean up of the paths and * connections associated with such failed ports. * * Inputs: * * IPL_SCS - Interrupt processor level * pb - Path Block pointer * pinfo.state - PS_PATH_FAILURE * pinfo.reason - Reason for path failure * lk_scadb - SCA database lock structure * scs_cbvtdb - CB vector table database pointer * scs_timeoutq - SCS protocol sequence timeout queue head * * Outputs: * * IPL_SCS - Interrupt processor level * pb - Path Block pointer * pinfo.nconns - Number of connections * pinfo.status.sanity - 0 * * SMP: The SCA database is locked for traversing and removing CBs and * PBs( when necessary ) from the system-wide configuration * database, and deallocating CBVTEs. Locking the SCA database * also prevents premature PB deletion and allows their removal * from the SCS protocol sequence timeout queue when necessary. * * CBs are locked to synchronize access, for deletion in some * cases, to prevent premature deletion in others, and as required * by scs_log_event() in case logging becomes necessary. They are * indirectly locked through their CBVTEs. * * CBVTE semaphores are synchronized to in order to postpone * changes in connection state while call backs to the * corresponding SYSAPs are in progress. * * The PB is locked to synchronize access and whenever it is found * necessary to remove a CB from its SCS CB wait queue or the PB * from the SCS protocol sequence timeout queue. * * The validity of the PB address must be guaranteed EXTERNALLY. * * NO EXTERNAL locks may be held when this routine is invoked. */voidscs_path_crash( pb ) register PB *pb;{ CMSB cmsb; u_long sn; void ( *control )(); register cbq *cb; register CBVTE *cbvte; register u_long port_failure, event, status; /* Clean up of the failed path involves the following steps: * * 1. Lock the SCA database. * 2. Lock the PB. * 3. Abort the PB sanity timer if currently operational. * 4. Determine whether the path failed due to local port failure. * 5. Unlock the PB. * 6. Temporarily increment the count of CBs associated with the path. * 7. Initiate clean up of all CBs associated with the path. * 8. Decrement the count of CBs associated with the path restoring it to * its proper value. * 9. Invoke the appropriate PD routine to remove the PB from the * system-wide configuration database and deallocate it provided all * CBs have been cleaned up and there are none associated with the PB. * Otherwise, the PB is removed and deallocated when the last * connection across the path is terminated by SYSAP request. * 10. Unlock the SCA database. * * Temporarily incrementing the CB count( Step 6 ) prevents PB deletion and * simplifies path clean up while guaranteeing the validity of the cached * PB address. Locks are insufficient for this purpose because they must * be repeatedly released and re-established during path clean up. * * The clean up of each CB( Step 7 ) proceeds as follows: * * 1. Lock the CB. * 2. Synchronize to the CBVTE semaphore. * 3. Abort any scheduled SCS request. * 4. Remove the CB from all internal resource queues. * 5. Prohibit the removal of buffers from the local port's free pools * during CB clean up whenever path failure resulted from local port * failure. The buffers credited to the connection are retrieved and * disposed of during clean up of the failed port itself. * 6. Complete CB clean up according to its connection state. * 7. Unlock the CB. * * Synchronizing to the CBVTE semaphore( Step 2 ) postpones processing of * the connection and subsequent changes in its state while call backs to * the corresponding SYSAP are in progress. Failure to synchronize can * lead to numerous aberrant situations in SMP environments such as SYSAP * notification of application message reception FOLLOWING notification of * connection termination due to path failure. Synchronization is * achieved by releasing the SCA database and CB locks and re-obtaining * them in the proper order until all call backs have completed( CBVTE * semaphore == 0 ). * * Connection state dependent clean up( Step 6 ) of open connections and * those partially disconnected due to remote SYSAP action is asynchronous. * The local SYSAP is notified of path failure through asynchronous * invocation of the connection's control event routine and it must * explicitly request connection termination. It may do so at its leisure. * * Connection state dependent clean up( Step 6 ) of formative connections * initiated by the remote SYSAP but not yet responded to by the local * SYSAP is synchronous. The event is logged. The CB is removed from the * system-wide configuration database and is deallocated along with all * associated resources. The corresponding local SYSAP is not notified of * this occurrence but discover it when it attempts to respond to the * connection request. * * Connection state dependent clean up( Step 6 ) of connections in all * other states is asynchronous and proceeds as follows: * * 1. Termination of the fully established or formative SCS connection due * to path failure is logged. * 2. The CB is removed from the system-wide configuration database. * 3. The CB is deallocated along with all associated resources. * 4. The local SYSAP is notified of connection failure through * asynchronous invocation of the connection's control event routine. * * Which specific event the local SYSAP is notified of depends upon the * connection's former state. * * NOTE: All locks are released prior to local SYSAP notification to allow * it to respond to the event. The SCA database lock is * re-established following SYSAP notification but prior to obtaining * the next CB associated with the failed path. Cached PB addresses * are valid following re-establishment of the SCA database lock * because the number of CBs associated with them was artificially * increased to prevent PB removal from the system-wide configuration * database and deletion. * * NOTE: Cached CB addresses are valid after synchronization to the CBVTE * semaphore is achieved because once path failure is reported to SCS * the only way for CBs to be deallocated is for their SYSAPs to * request disconnection of their corresponding connections following * explicit notification of the path failure. */ Lock_scadb() Lock_pb( pb ) if( pb->pinfo.status.sanity ) { Remove_scs_timeoutq( pb ) } port_failure = Port_failure( pb->pinfo.reason ); Unlock_pb( pb ) ++pb->pinfo.nconns; for( cb = pb->cbs.flink; cb != &pb->cbs; ) { event = 0; cbvte = Get_cbvte( Cb->cinfo.lconnid ); Lock_cbvte( cbvte ) sn = cbvte->connid.seq_num; while( Test_cbvte_sem( cbvte )) { Unlock_cbvte( cbvte ) Unlock_scadb() Lock_scadb() Lock_cbvte( cbvte ) } if( sn != cbvte->connid.seq_num ) { ( void )panic( SCSPANIC_SCADB ); } Remove_pb_waitq( Cb ) Cb->cinfo.status.cwait = 0; if( port_failure ) { Cb->cinfo.rec_credit = 0, Cb->cinfo.pend_rec_credit = 0, Cb->cinfo.ntransfers = 0; Cb->cinfo.dg_credit = 0; } switch( Cb->cinfo.cstate ) { case CS_OPEN: case CS_DISCONN_REC: break; case CS_DISCONN_ACK: case CS_DISCONN_SNT: case CS_DISCONN_MTCH: event = W_FAIL_CONN; break; case CS_CONN_SNT: case CS_CONN_ACK: case CS_CONN_REC: case CS_ACCEPT_SNT: case CS_REJECT_SNT: event = W_FAIL_FCONN; break; default: ( void )panic( SCSPANIC_CSTATE ); } if( event ) { ( void )scs_log_event( Cb, event, CONN_EVENT ); event = 0; } switch( Cb->cinfo.cstate ) { case CS_OPEN: case CS_DISCONN_REC: Cb->cinfo.cstate = CS_PATH_FAILURE; status = pb->pinfo.reason; event = CRE_PATH_FAILURE; break; case CS_DISCONN_ACK: case CS_DISCONN_SNT: case CS_DISCONN_MTCH: Cb->cinfo.cstate = CS_CLOSED; status = ADR_PATH_FAILURE; event = CRE_DISCONN_DONE; break; case CS_CONN_SNT: case CS_CONN_ACK: Cb->cinfo.cstate = CS_CLOSED; status = ADR_PATH_FAILURE; event = CRE_CONN_DONE; /* Asynchronous local SYSAP notification triggered by * unilateral connection abortion is unscheduled. */ if( Cb->cinfo.status.abort_fork ) { ( void )unksched( &Cb->forkb ); Cb->cinfo.status.abort_fork = 0; } break; case CS_CONN_REC: { cbq *next_cb = cb->flink; Cb->cinfo.cstate = CS_CLOSED; Remove_cb( Cb, pb ) Unlock_cbvte( cbvte ) cb = next_cb; continue; } case CS_ACCEPT_SNT: case CS_REJECT_SNT: if( Cb->cinfo.cstate == CS_ACCEPT_SNT ) { event = CRE_ACCEPT_DONE; } else if( Cb->cinfo.status.disconnect ) { event = CRE_DISCONN_DONE; } else { event = CRE_REJECT_DONE; } status = ADR_PATH_FAILURE; Cb->cinfo.cstate = CS_CLOSED; break; default: ( void )panic( SCSPANIC_CSTATE ); } ( void )scs_init_cmsb( event, status, &cmsb, Cb, pb, 0 ); control = Cb->control; if( Cb->cinfo.cstate == CS_CLOSED ) { Remove_cb( Cb, pb ) } Unlock_cbvte( cbvte ) Unlock_scadb() ( void )( *control )( event, &cmsb ); Lock_scadb() for( cb = pb->cbs.flink; cb != &pb->cbs && Cb->cinfo.cstate == CS_PATH_FAILURE; cb = cb->flink ) {} } if( --pb->pinfo.nconns == 0 ) { ( void )( *pb->Remove_pb )( pb->pccb, pb ); } Unlock_scadb()}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -