Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

936 lines
28 KiB

  1. /*
  2. *
  3. * NOTES:
  4. *
  5. * REVISIONS:
  6. * ane09DEC92: fixed thread rundown problems
  7. * ane16DEC92: added semaphore to protect multi-threaded access to
  8. * current transaction group on protocol
  9. * jod29Dec92: Made SubmitList return an INT -> changed Get and Set
  10. * ane30Dec92: optimized polling
  11. * jod13Jan93: Added eventList to InterpretMessage() call and moved all
  12. * HandleEvent calls to the Poll loop
  13. * ane25Jan93: Added call to error logger when initialization of port
  14. * fails
  15. * ane03Feb93: Added checks to avoid crashes during rundown of polling
  16. * thread, also updated destructor
  17. * ane09Feb93: Use ExitWait when telling the poll thread to go away
  18. * pcy16Feb93: Explicitly check for COMM LOST on returning msgs
  19. * pcy18Feb93: Fixed typo Err_RETRYING_COMM to ErrRETRYING_COM
  20. * pcy21Apr93: OS2 FE merge
  21. * pcy14May93: Added Set(PTransactionGroup)
  22. * cad09Jul93: using exitwait, new semaphores
  23. * cad15Jul93: sleeping during no-comm to allow cpu to detect reconnect better
  24. * pcy16Jul93: Added NT semaphores
  25. * jod24Aug93: Added Unregister
  26. * cad08Sep93: Added handling of events during gets
  27. * pcy10Sep93: Set theCurrentTransaction to the top of the list on Unregister
  28. * cad14Sep93: Support for pausing polling
  29. * cad07Oct93: Plugging Memory Leaks
  30. * cad12Oct93: Not sending garbage down for gets
  31. * ajr18Oct93: Made changes to work with Process manager for SINGLETHREADED
  32. * cad17Nov93: more lost comm fixups
  33. * mwh19Nov93: changed EventID to INT
  34. * ajr28Dec93: Added types.h on unix platforms to resolve typing problems.
  35. * cad11Jan94: Changes for new process manager
  36. * cad13Jan94: fixed up/simplified interval time measurement
  37. * cad14Jan94: fixing polling time for single-threaded
  38. * mwh14Jan94: fix singlethreaded client skipping every other poll
  39. * cad18Jan94: cleaned up single-threaded poll
  40. * pcy28Jan94: Create poll events on stack
  41. * ajr16Feb94: Added default id to SubmitList.
  42. * ajr16Feb94: Added writeUpsOffFile() protected member function.
  43. * ram21Mar94: Included header files for Novell FE to work
  44. * ajr23Mar94: Made sure to close upsoff.cmd
  45. * pcy08Apr94: Trim size, use static iterators, dead code removal
  46. * pcy13Apr94: Use automatic variables decrease dynamic mem allocation
  47. * mwh05May94: #include file madness , part 2
  48. * mwh09May94: lose the auto. aggregate init. e.g CHAR foo[2] = "";
  49. * ajr20May94: SCO stuff
  50. * mwh23May94: port for NCR
  51. * ajr24May94: Uware includes....
  52. * ajr31May94: Saw to it that upsoff.cmd is erased after execution...
  53. * ajr31May94: Added stat.h for IRIX too....
  54. * mwh01Jun94: port for INTERACTIVE
  55. * cad01Jul94: fix for unix sleep problem and unregister crash
  56. * ajr29Aug94: reworked writeUpsOffFile to take Message *
  57. * ajr02May95: Need to stop carrying time in milliseconds
  58. * dml21Jun95: modify for general utility to get default pwrchute directory; req'd for Windows
  59. * dml24Aug95: removed conditional code for OS2 ver 1.3
  60. * ajr07Nov95: SINIX Port
  61. * poc28Sep96: Fixed SIR 4392.
  62. * jps17Oct96: Moved and added Access() and Release() calls, attempting to eliminate
  63. * application errors on exit
  64. * srt21Oct96: Replaced a timerManager wait with a timed semaphore wait
  65. * jps23Oct96: Added Access()/Release() to ~CommDevice(); commented out test for
  66. * TURN_ON_SMART_MODE in Set() so it always calls Access()/Release()
  67. * srt24Oct96: Added an abort semaphore
  68. * inf14Apr97: Loaded error string from resource file.
  69. * tjg09Jul97: Changed NT code to call getPwrchuteDirectory instead of getenv
  70. * awm21Oct97: Added initialization for performance monitor shared memory blocks
  71. * awm14Jan98: Removed initialization for performance monitor shared memory blocks
  72. * tjg26Jan98: Added Stop method
  73. * tjg02Mar98: Removed Stop method (dead code)
  74. *
  75. * v-stebe 29Jul2000 Fixed PREfix errors (bugs #46363-46365, #46367, #46368)
  76. * v-stebe 11Sep2000 Fixed additional PREfix errors
  77. */
  78. #include "cdefine.h"
  79. #include "stream.h"
  80. extern "C" {
  81. #include <stdlib.h>
  82. #include <malloc.h>
  83. #include <string.h>
  84. #include <time.h>
  85. }
  86. #include "_defs.h"
  87. #include "apcobj.h"
  88. #include "list.h"
  89. #include "dispatch.h"
  90. #include "event.h"
  91. #include "message.h"
  92. #include "proto.h"
  93. #include "trans.h"
  94. #include "cdevice.h"
  95. #include "err.h"
  96. #include "timerman.h"
  97. #include "thread.h"
  98. #include "contrlr.h"
  99. #include "errlogr.h"
  100. #include "utils.h"
  101. #include "protlist.h"
  102. #include "codes.h"
  103. #include "apcsemnt.h"
  104. #include "mutexnt.h"
  105. #define RETRY_FAILED 1
  106. #define RETRY_SUCCESS 0
  107. #define ASKUPS_FAILED 1
  108. #define ASKUPS_OK 0
  109. /*--------------------------------------------------------------------
  110. *
  111. * Function...: CommDevice
  112. *
  113. * Description: Constructor.
  114. *
  115. *-------------------------------------------------------------------*/
  116. CommDevice::CommDevice(Controller* control)
  117. : theController(control),
  118. thePollList((ProtectedList *)NULL),
  119. theCurrentTransaction((PTransactionGroup)NULL),
  120. pollStartTime(0),
  121. theSleepingFlag(0),
  122. thePollIsDone(0),
  123. theState(NORMAL_STATE),
  124. thePort((PStream)NULL),
  125. theProtocol((Protocol*)NULL),
  126. thePollIterator((PListIterator)NULL),
  127. thePollThread((PThread)NULL),
  128. thePollInterval(4L),
  129. theLostCommFlag(0)
  130. {
  131. theEventList = new ProtectedList();
  132. theEventIterator = (PListIterator) &(theEventList->InitIterator());
  133. theAskLock = new ApcMutexLock();
  134. theAbortSem = new ApcSemaphore();
  135. }
  136. /*--------------------------------------------------------------------
  137. *
  138. * Function...: CommDevice
  139. *
  140. * Description: Destructor.
  141. *
  142. *-------------------------------------------------------------------*/
  143. CommDevice::~CommDevice()
  144. {
  145. Access();
  146. theController->UnregisterEvent(EXIT_THREAD_NOW, this);
  147. theAbortSem->Post();
  148. if (theEventList)
  149. {
  150. theEventList->FlushAll();
  151. delete theEventList;
  152. theEventList = (PProtectedList)NULL;
  153. if (theEventIterator) {
  154. delete theEventIterator;
  155. theEventIterator = (PListIterator)NULL;
  156. }
  157. }
  158. if (thePollList)
  159. {
  160. thePollList->FlushAll();
  161. delete thePollList;
  162. thePollList = (ProtectedList *)NULL;
  163. }
  164. if (thePollIterator)
  165. {
  166. delete thePollIterator;
  167. thePollIterator = (PListIterator)NULL;
  168. }
  169. if (thePort)
  170. {
  171. delete thePort;
  172. thePort = (PStream)NULL;
  173. }
  174. if (theProtocol)
  175. {
  176. delete theProtocol;
  177. theProtocol = (PProtocol)NULL;
  178. }
  179. if (thePollThread)
  180. {
  181. // Use ExitWait to make sure that the poll thread is exited before
  182. // deleting the poll list, etc.
  183. //
  184. // NT workaround
  185. //
  186. thePollThread->TerminateThreadNow();
  187. delete thePollThread;
  188. thePollThread = (PThread)NULL;
  189. }
  190. Release();
  191. delete theAskLock;
  192. // theAskLock is a mutex lock. Everyone should have one. Dont us Semaphore
  193. // or NullMutexLock.
  194. theAskLock = (PMutexLock) NULL;
  195. delete theAbortSem;
  196. theAbortSem = NULL;
  197. }
  198. /*--------------------------------------------------------------------
  199. *
  200. * Function...: Initialize
  201. *
  202. * Description: .
  203. *
  204. *-------------------------------------------------------------------*/
  205. INT CommDevice::Initialize()
  206. {
  207. INT err = ErrNO_ERROR;
  208. if (thePort)
  209. {
  210. err = thePort->Initialize();
  211. }
  212. theObjectStatus = err;
  213. // Can't call this in the constructor since theController vtbl isn't set
  214. // up at that point...It'll crash
  215. theController->RegisterEvent(EXIT_THREAD_NOW, this);
  216. return err;
  217. }
  218. INT CommDevice::Update(PEvent anEvent)
  219. {
  220. switch (anEvent->GetCode())
  221. {
  222. case EXIT_THREAD_NOW:
  223. if(thePollThread)
  224. {
  225. thePollThread->ExitWait();
  226. delete thePollThread;
  227. thePollThread = (PThread)NULL;
  228. }
  229. break;
  230. default:
  231. break;
  232. }
  233. return ErrNO_ERROR;
  234. }
  235. /*--------------------------------------------------------------------
  236. *
  237. * Function...: Get
  238. *
  239. * Description:
  240. *
  241. *-------------------------------------------------------------------*/
  242. INT CommDevice::Get(INT id, CHAR* value)
  243. {
  244. INT err = ErrNO_ERROR;
  245. if (theLostCommFlag) {
  246. err = ErrCOMMUNICATION_LOST;
  247. }
  248. else {
  249. // Build the get transaction
  250. PTransactionGroup transaction_group = new TransactionGroup(GET);
  251. PTransactionItem transaction_item = new TransactionItem(GET, id, "");
  252. if ((transaction_group != NULL) && (transaction_item != NULL)) {
  253. transaction_group->AddTransactionItem(transaction_item);
  254. // Let the Protocol build the message. The messages to send will be
  255. // placed in msglist. There may be more than one message.
  256. if (theProtocol)
  257. err = theProtocol->BuildTransactionGroupMessages(transaction_group);
  258. else
  259. err = ErrRETRYING_COMM;
  260. if (!err && theProtocol)
  261. {
  262. Access();
  263. theProtocol->SetCurrentTransactionGroup(transaction_group);
  264. err = SubmitList(transaction_group->GetProtocolMessageList());
  265. Release();
  266. if (!(err))
  267. {
  268. err = transaction_group->GetErrorCode();
  269. }
  270. if (err == ErrNO_ERROR || err == ErrCONTINUE)
  271. {
  272. PList tiList = transaction_group->GetTransactionItemList();
  273. PTransactionItem tmpti = new TransactionItem(GET,id);
  274. PTransactionItem transitem = (PTransactionItem)tiList->Find(tmpti);
  275. strcpy(value, transitem->GetValue());
  276. delete tmpti;
  277. tmpti = NULL;
  278. }
  279. }
  280. delete transaction_group;
  281. transaction_group = NULL;
  282. }
  283. else {
  284. err = ErrMEMORY;
  285. // Cleanup allocations so that we don't leak
  286. delete transaction_item;
  287. transaction_item = NULL;
  288. delete transaction_group;
  289. transaction_group = NULL;
  290. }
  291. }
  292. return err;
  293. }
  294. /*--------------------------------------------------------------------
  295. *
  296. * Function...: Get with a Transaction Group
  297. *
  298. * Description:
  299. *
  300. *-------------------------------------------------------------------*/
  301. INT CommDevice::Get(PTransactionGroup transaction_group)
  302. {
  303. INT err = ErrNO_ERROR;
  304. if(theLostCommFlag) {
  305. err = ErrCOMMUNICATION_LOST;
  306. }
  307. else {
  308. // Let the Protocol build the message. The messages to send will be
  309. // placed in msglist. There may be more than one message.
  310. if (theProtocol)
  311. err = theProtocol->BuildTransactionGroupMessages(transaction_group);
  312. else
  313. err = ErrRETRYING_COMM;
  314. if (!err && theProtocol)
  315. {
  316. Access();
  317. theProtocol->SetCurrentTransactionGroup(transaction_group);
  318. INT getErr = SubmitList(transaction_group->GetProtocolMessageList());
  319. Release();
  320. if (!(getErr))
  321. {
  322. getErr = transaction_group->GetErrorCode();
  323. }
  324. return getErr;
  325. }
  326. }
  327. return err;
  328. }
  329. /*--------------------------------------------------------------------
  330. *
  331. * Function...: Set
  332. *
  333. * Description: .
  334. *
  335. *-------------------------------------------------------------------*/
  336. INT CommDevice::Set(INT id, CHAR* value)
  337. {
  338. INT err = ErrNO_ERROR;
  339. if ((id != TURN_ON_SMART_MODE) && theLostCommFlag) {
  340. err = ErrCOMMUNICATION_LOST;
  341. }
  342. else {
  343. // Build the set transaction
  344. //
  345. PTransactionGroup transaction_group = new TransactionGroup(SET);
  346. PTransactionItem transaction_item = new TransactionItem(SET, id, value);
  347. if ((transaction_group != NULL) && (transaction_item != NULL)) {
  348. transaction_group->AddTransactionItem(transaction_item);
  349. // Let the Protocol build the message. The messages to send will be
  350. // placed in msglist. There may be more than one message.
  351. if (theProtocol)
  352. err = theProtocol->BuildTransactionGroupMessages(transaction_group);
  353. else
  354. err = ErrRETRYING_COMM;
  355. if (!err && theProtocol)
  356. {
  357. // if(id != TURN_ON_SMART_MODE) {
  358. Access();
  359. // }
  360. theProtocol->SetCurrentTransactionGroup(transaction_group);
  361. err = SubmitList(transaction_group->GetProtocolMessageList(),id);
  362. // if(id != TURN_ON_SMART_MODE) {
  363. Release();
  364. // }
  365. if (!err) {
  366. err = transaction_group->GetErrorCode();
  367. }
  368. }
  369. if (!err) {
  370. err = transaction_item->GetErrorCode();
  371. }
  372. delete transaction_group;
  373. transaction_group = NULL;
  374. }
  375. else {
  376. err = ErrMEMORY;
  377. // Cleanup allocations so that we don't leak
  378. delete transaction_item;
  379. transaction_item = NULL;
  380. delete transaction_group;
  381. transaction_group = NULL;
  382. }
  383. }
  384. return err;
  385. }
  386. INT CommDevice::Set(PTransactionGroup transaction_group)
  387. {
  388. INT err = ErrNO_ERROR;
  389. if(theLostCommFlag) {
  390. err = ErrCOMMUNICATION_LOST;
  391. }
  392. else {
  393. // Let the Protocol build the message. The messages to send will be
  394. // placed in msglist. There may be more than one message.
  395. if (theProtocol)
  396. err = theProtocol->BuildTransactionGroupMessages(transaction_group);
  397. else
  398. err = ErrRETRYING_COMM;
  399. if (!err && theProtocol)
  400. {
  401. Access();
  402. theProtocol->SetCurrentTransactionGroup(transaction_group);
  403. INT setErr = SubmitList(transaction_group->GetProtocolMessageList());
  404. Release();
  405. if (!(setErr))
  406. {
  407. setErr = transaction_group->GetErrorCode();
  408. }
  409. return setErr;
  410. }
  411. }
  412. return err;
  413. }
  414. /*--------------------------------------------------------------------
  415. *
  416. * Function...: SubmitList
  417. *
  418. * Description: .
  419. *
  420. *-------------------------------------------------------------------*/
  421. INT CommDevice::SubmitList(List* msglist, INT id) // ***, ObjList* eventlist)
  422. {
  423. ListIterator iterator(*msglist);
  424. PMessage msg = (PMessage)&(iterator.Current());
  425. PMessage answer = (Message *)NULL;
  426. INT submitErr = 0;
  427. // #if !C_OS & C_WIN311
  428. // in windows we need to get to the ASKUP during the initialize retries
  429. if (theState==COMM_STOPPED) {
  430. submitErr = theState; // exit out of this routine - ex NO_COMM
  431. }
  432. // #endif
  433. while (msg && (submitErr == 0)) {
  434. // Send the message
  435. AskUps(msg);
  436. //check the message for an error
  437. if (msg->getErrcode()) {
  438. submitErr = msg->getErrcode();
  439. }
  440. else {
  441. List* newmsglist = new List();
  442. if (newmsglist != NULL) {
  443. if (theProtocol) {
  444. theProtocol->InterpretMessage(msg,theEventList, newmsglist);
  445. }
  446. else {
  447. submitErr = ErrRETRYING_COMM;
  448. }
  449. if (msg->getErrcode()) {
  450. submitErr = msg->getErrcode();
  451. }
  452. else if (submitErr == 0) {
  453. // If the Protocol has decided additional messages are
  454. // required to be sent as the result of the response,
  455. // send these before continuing.
  456. //
  457. if (newmsglist->GetItemsInContainer()) {
  458. submitErr = SubmitList(newmsglist);
  459. }
  460. msg = (PMessage)iterator.Next();
  461. }
  462. newmsglist->FlushAll();
  463. delete newmsglist;
  464. newmsglist = NULL;
  465. }
  466. else {
  467. submitErr = ErrMEMORY;
  468. }
  469. }
  470. }
  471. return submitErr;
  472. }
  473. /*--------------------------------------------------------------------
  474. *
  475. * Function...: RegisterEvent
  476. *
  477. * Description:
  478. *
  479. *-------------------------------------------------------------------*/
  480. INT CommDevice::RegisterEvent(INT id, UpdateObj* object)
  481. {
  482. INT err = ErrNO_ERROR;
  483. UpdateObj::RegisterEvent(id, object);
  484. // Add the event to the poll list
  485. PTransactionGroup transaction_group = new TransactionGroup(GET);
  486. PTransactionItem transaction_item = new TransactionItem(GET, id, "");
  487. if ((transaction_group != NULL) && (transaction_item != NULL)) {
  488. transaction_group->AddTransactionItem(transaction_item);
  489. if (theProtocol)
  490. err = theProtocol->BuildPollTransactionGroupMessages(transaction_group);
  491. else
  492. err = ErrRETRYING_COMM;
  493. if (!err)
  494. {
  495. int listAllocated = FALSE;
  496. if (thePollList == (PList) NULL)
  497. thePollList = new ProtectedList;
  498. thePollList->Append(transaction_group);
  499. if (theCurrentTransaction == (PTransactionGroup)NULL)
  500. theCurrentTransaction = (PTransactionGroup) thePollList->GetHead();
  501. if (thePollIterator == (PListIterator)NULL)
  502. thePollIterator = new ListIterator (*thePollList);
  503. }
  504. else
  505. {
  506. delete transaction_group;
  507. transaction_group = NULL;
  508. }
  509. }
  510. else {
  511. err = ErrMEMORY;
  512. // Cleanup allocations so that we don't leak
  513. delete transaction_item;
  514. transaction_item = NULL;
  515. delete transaction_group;
  516. transaction_group = NULL;
  517. }
  518. // Ignore errors that come back from BuildPollTransactionGroupMessages
  519. // since the worst that will happen is the parameter won't be polled for
  520. if (err == ErrRETRYING_COMM)
  521. {
  522. return err;
  523. }
  524. else
  525. {
  526. return ErrNO_ERROR;
  527. }
  528. }
  529. /*--------------------------------------------------------------------
  530. *
  531. * Function...: UnregisterEvent
  532. *
  533. * Description: .
  534. *
  535. *-------------------------------------------------------------------*/
  536. INT CommDevice::UnregisterEvent(INT id, UpdateObj* object)
  537. {
  538. UpdateObj::UnregisterEvent(id, object);
  539. if ( !(theDispatcher->GetRegisteredCount(id)) && // If Empty List
  540. thePollIterator && thePollList ) // just in case
  541. {
  542. PTransactionGroup tmp = (PTransactionGroup)NULL;
  543. thePollIterator->Reset();
  544. PTransactionGroup group = (PTransactionGroup) &(thePollIterator->Current());
  545. Access();
  546. while (group != (PTransactionGroup)NULL)
  547. {
  548. tmp = (PTransactionGroup)thePollIterator->Next();
  549. if (group->GetFirstTransactionItem()->GetCode() == id)
  550. {
  551. thePollList->Detach((RObj)*group);
  552. delete group;
  553. group = NULL;
  554. //
  555. // We have to do this because if we remove the
  556. // transaction we're currently pointing to we
  557. // die
  558. //
  559. thePollIterator->Reset();
  560. theCurrentTransaction = (PTransactionGroup) thePollList->GetHead();
  561. break;
  562. }
  563. group = tmp;
  564. }
  565. Release();
  566. }
  567. return ErrNO_ERROR;
  568. }
  569. /*--------------------------------------------------------------------
  570. *
  571. * Function...: Equal
  572. *
  573. * Description: .
  574. *
  575. *-------------------------------------------------------------------*/
  576. INT CommDevice::Equal(RObj item) const
  577. {
  578. RCommDevice comp = (RCommDevice)item;
  579. if ( theController == comp.GetController() )
  580. {
  581. if ( theProtocol == comp.GetProtocol() )
  582. {
  583. if ( thePort == comp.GetPort() )
  584. {
  585. return TRUE;
  586. }
  587. }
  588. }
  589. return FALSE;
  590. }
  591. /*--------------------------------------------------------------------
  592. *
  593. * Function...: HandleEvents
  594. *
  595. * Description: .
  596. *
  597. *-------------------------------------------------------------------*/
  598. INT CommDevice::HandleEvents()
  599. {
  600. INT err = ErrNO_ERROR;
  601. PEvent event = (PEvent)NULL;
  602. if (theEventIterator)
  603. {
  604. theEventIterator->Reset();
  605. event = (PEvent) &(theEventIterator->Current());
  606. }
  607. else
  608. {
  609. err = ErrRETRYING_COMM;
  610. }
  611. while (event && (err == ErrNO_ERROR))
  612. {
  613. PEvent tmp = (PEvent)NULL;
  614. if (theEventList && theEventIterator &&
  615. (theEventList->GetItemsInContainer() > 0))
  616. {
  617. // Remove the event before dispatching it to prevent
  618. // unwanted loops
  619. tmp = (PEvent) theEventIterator->Next();
  620. theEventList->Detach((RObj)*event);
  621. UpdateObj::Update(event);
  622. delete event;
  623. event = tmp;
  624. }
  625. else
  626. {
  627. err = ErrRETRYING_COMM;
  628. }
  629. }
  630. return err;
  631. }
  632. /*--------------------------------------------------------------------
  633. *
  634. * Function...: Poll
  635. *
  636. * Description: .
  637. *
  638. *-------------------------------------------------------------------*/
  639. INT CommDevice::Poll()
  640. {
  641. time_t ElapsedTime = time((time_t*)NULL);
  642. List *newmsglist = (List*)NULL;
  643. INT err = ErrNO_ERROR;
  644. if ( (theSleepingFlag == FALSE) && (theCurrentTransaction) && (err == ErrNO_ERROR))
  645. {
  646. if(pollStartTime ==0)
  647. {
  648. pollStartTime = time((time_t*)NULL);
  649. }
  650. Access();
  651. PTransactionGroup transactionGroup = theCurrentTransaction;
  652. PMessage msg = (PMessage) transactionGroup->GetProtocolMessageList()->GetHead();
  653. if ((theState == COMM_STOPPED) || (theState == PAUSE_POLLING))
  654. {
  655. // sleep and let the CPU get a break, maybe things will be ;
  656. // better when we wake up.;
  657. theSleepingFlag = TRUE;
  658. }
  659. else
  660. {
  661. // If there are no comm problems;
  662. AskUps(msg); // Should this be there ???;
  663. theAbortSem->TimedWait(500);
  664. if (msg->getErrcode() == ErrCOMMUNICATION_LOST)
  665. {
  666. theCurrentTransaction = (PTransactionGroup)NULL;
  667. }
  668. else
  669. {
  670. List* msglist = (List*)NULL;
  671. if (msg->getResponse())
  672. {
  673. theProtocol->SetCurrentTransactionGroup(theCurrentTransaction);
  674. theProtocol->InterpretMessage(msg, theEventList, msglist);
  675. if (msglist)
  676. {
  677. SubmitList(msglist);
  678. }
  679. PList a_list = transactionGroup->GetTransactionItemList();
  680. ListIterator itemIter(*a_list);
  681. for (INT i = 0; i < a_list->GetItemsInContainer(); i++)
  682. {
  683. RTransactionItem transItem = (RTransactionItem)itemIter.Current();
  684. // Check transItem for NULL. We have to check the address because
  685. // the previous call returns a reference instead of a pointer.
  686. // Fixes bug #227550
  687. if ((&transItem!=NULL) && (!(transItem.GetErrorCode())))
  688. {
  689. Event event(transItem.GetCode(), transItem.GetValue());
  690. UpdateObj::Update(&event);
  691. }
  692. itemIter.Next(); // SRB: Changed from itemIter++
  693. }
  694. }
  695. // Clean out old errors and responses;
  696. msg->setErrcode(ErrNO_ERROR);
  697. PTransactionGroup tmp = (PTransactionGroup)thePollIterator->Next();
  698. if (tmp == (PTransactionGroup)NULL)
  699. {
  700. thePollIterator->Reset();
  701. theCurrentTransaction = (PTransactionGroup)thePollList->GetHead();
  702. theSleepingFlag = TRUE;
  703. thePollIsDone = TRUE;
  704. }
  705. else
  706. {
  707. theCurrentTransaction = tmp;
  708. }
  709. }
  710. }
  711. msg->ReleaseResponse();
  712. Release();
  713. if ((err == ErrNO_ERROR) && theEventList && theEventList->GetItemsInContainer())
  714. {
  715. err = HandleEvents();
  716. theAbortSem->TimedWait(250);
  717. }
  718. }
  719. else if (theCurrentTransaction == NULL)
  720. {
  721. // puts("No transactions to process");
  722. }
  723. // Give up CPU
  724. _theTimerManager->Wait(0L);
  725. theAbortSem->TimedWait(250);
  726. if (theSleepingFlag == TRUE)
  727. {
  728. ULONG elapsed = (ULONG)(time((time_t*)NULL) - pollStartTime);
  729. if (elapsed > (ULONG)thePollInterval)
  730. {
  731. theSleepingFlag = FALSE;
  732. }
  733. else
  734. {
  735. theAbortSem->TimedWait(1000 * ((thePollInterval - elapsed)+ 1));
  736. }
  737. // for single-threaded apps, this is used outside here,
  738. // and set externally
  739. pollStartTime = 0;
  740. }
  741. return err;
  742. }
  743. //-------------------------------------------------------------------
  744. VOID CommDevice::StartPollThread ()
  745. {
  746. // Create a thread which will poll the server at a regular interval
  747. // for updated information on events in the poll list
  748. PollLoop *pollLoop = new PollLoop (this);
  749. thePollThread = new Thread (pollLoop);
  750. if (thePollThread != NULL) {
  751. thePollThread->Start();
  752. }
  753. }
  754. VOID CommDevice::OkToPoll ()
  755. {
  756. if (!thePollThread) {
  757. StartPollThread();
  758. }
  759. //
  760. // We must give up the CPU here to allow the poll thread to start running.
  761. // Otherwise we release the poll thread before we call wait, leaving the
  762. // wait to hang
  763. //
  764. _theTimerManager->Wait(500L);
  765. if (thePollThread) {
  766. thePollThread->Release();
  767. }
  768. }
  769. VOID CommDevice::Access()
  770. {
  771. theAskLock->Request();
  772. }
  773. VOID CommDevice::Release()
  774. {
  775. theAskLock->Release();
  776. }
  777. /*****************************************************************************
  778. *
  779. * PollLoop::ThreadMain is run within a seperate thread. It's purpose is to
  780. * periodically look at the events on the poll list and ask the server for
  781. * updated information on each event.
  782. *
  783. ****************************************************************************/
  784. PollLoop::PollLoop (PCommDevice aDevice)
  785. : theDevice (aDevice)
  786. {
  787. SetThreadName("APC UPS Polling");
  788. }
  789. PollLoop::~PollLoop ()
  790. {
  791. }
  792. VOID PollLoop::ThreadMain () {
  793. // Wait for the thread to be released to start polling
  794. Wait();
  795. while (ExitNow() == FALSE) {
  796. if(theDevice->HasLostComm()) {
  797. TimedWait(5000);
  798. }
  799. else {
  800. theDevice->Poll();
  801. }
  802. }
  803. DoneExiting();
  804. }