OpenCores
URL https://opencores.org/ocsvn/w11/w11/trunk

Subversion Repositories w11

[/] [w11/] [tags/] [w11a_V0.7/] [tools/] [src/] [librlink/] [RlinkServer.cpp] - Blame information for rev 33

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 31 wfjm
// $Id: RlinkServer.cpp 686 2015-06-04 21:08:08Z mueller $
2 19 wfjm
//
3 29 wfjm
// Copyright 2013-2015 by Walter F.J. Mueller <W.F.J.Mueller@gsi.de>
4 19 wfjm
//
5
// This program is free software; you may redistribute and/or modify it under
6
// the terms of the GNU General Public License as published by the Free
7
// Software Foundation, either version 2, or at your option any later version.
8
//
9
// This program is distributed in the hope that it will be useful, but
10
// WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY
11
// or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12
// for complete details.
13
// 
14
// Revision History: 
15
// Date         Rev Version  Comment
16 31 wfjm
// 2015-06-05   686   1.2.1  BUGFIX: CallAttnHandler(): fix race in hnext
17 30 wfjm
// 2015-04-04   662   1.2    BUGFIX: fix race in Stop(), use UnStop()
18 29 wfjm
// 2015-01-10   632   2.2    Exec() without emsg now void, will throw
19 28 wfjm
// 2014-12-30   625   2.1    adopt to Rlink V4 attn logic
20
// 2014-12-21   617   2.0.1  use kStat_M_RbTout for rbus timeout
21 27 wfjm
// 2014-12-11   611   2.0    re-organize for rlink v4
22 21 wfjm
// 2013-05-01   513   1.0.2  fTraceLevel now uint32_t
23 20 wfjm
// 2013-04-21   509   1.0.1  add Resume(), reorganize server start handling
24 19 wfjm
// 2013-03-06   495   1.0    Initial version
25
// 2013-01-12   474   0.5    First draft
26
// ---------------------------------------------------------------------------
27
 
28
/*!
29
  \file
30 31 wfjm
  \version $Id: RlinkServer.cpp 686 2015-06-04 21:08:08Z mueller $
31 19 wfjm
  \brief   Implemenation of RlinkServer.
32
*/
33
 
34
#include "boost/thread/locks.hpp"
35
#include "boost/bind.hpp"
36
 
37
#include "librtools/Rexception.hpp"
38
#include "librtools/RosFill.hpp"
39
#include "librtools/RosPrintf.hpp"
40
#include "librtools/RosPrintBvi.hpp"
41
#include "librtools/Rexception.hpp"
42
#include "librtools/RlogMsg.hpp"
43
 
44
#include "RlinkServer.hpp"
45
 
46
using namespace std;
47
 
48
/*!
49
  \class Retro::RlinkServer
50
  \brief FIXME_docs
51
*/
52
 
53
// all method definitions in namespace Retro
54
namespace Retro {
55
 
56
//------------------------------------------+-----------------------------------
57
//! Default constructor
58
 
59
RlinkServer::RlinkServer()
60
  : fspConn(),
61
    fContext(),
62
    fAttnDsc(),
63
    fActnList(),
64
    fWakeupEvent(),
65
    fELoop(this),
66
    fServerThread(),
67
    fAttnPatt(0),
68 27 wfjm
    fAttnNotiPatt(0),
69 19 wfjm
    fTraceLevel(0),
70
    fStats()
71
{
72 30 wfjm
  fContext.SetStatus(0, RlinkCommand::kStat_M_RbTout |
73
                        RlinkCommand::kStat_M_RbNak  |
74
                        RlinkCommand::kStat_M_RbErr);
75 19 wfjm
 
76
  fELoop.AddPollHandler(boost::bind(&RlinkServer::WakeupHandler, this, _1),
77
                        fWakeupEvent, POLLIN);
78
 
79
  // Statistic setup
80
  fStats.Define(kStatNEloopWait,"NEloopWait","event loop turns (wait)");
81
  fStats.Define(kStatNEloopPoll,"NEloopPoll","event loop turns (poll)");
82
  fStats.Define(kStatNWakeupEvt,"NWakeupEvt","Wakeup events");
83
  fStats.Define(kStatNRlinkEvt, "NRlinkEvt", "Rlink data events");
84 28 wfjm
  fStats.Define(kStatNAttnHdl  ,"NAttnHdl"  ,"Attn handler calls");
85
  fStats.Define(kStatNAttnNoti ,"NAttnNoti" ,"Attn notifies processed");
86
  fStats.Define(kStatNAttnHarv ,"NAttnHarv" ,"Attn handler restarts");
87 19 wfjm
  fStats.Define(kStatNAttn00,   "NAttn00",   "Attn bit  0 set");
88
  fStats.Define(kStatNAttn01,   "NAttn01",   "Attn bit  1 set");
89
  fStats.Define(kStatNAttn02,   "NAttn02",   "Attn bit  2 set");
90
  fStats.Define(kStatNAttn03,   "NAttn03",   "Attn bit  3 set");
91
  fStats.Define(kStatNAttn04,   "NAttn04",   "Attn bit  4 set");
92
  fStats.Define(kStatNAttn05,   "NAttn05",   "Attn bit  5 set");
93
  fStats.Define(kStatNAttn06,   "NAttn06",   "Attn bit  6 set");
94
  fStats.Define(kStatNAttn07,   "NAttn07",   "Attn bit  7 set");
95
  fStats.Define(kStatNAttn08,   "NAttn08",   "Attn bit  8 set");
96
  fStats.Define(kStatNAttn09,   "NAttn09",   "Attn bit  9 set");
97
  fStats.Define(kStatNAttn10,   "NAttn10",   "Attn bit 10 set");
98
  fStats.Define(kStatNAttn11,   "NAttn11",   "Attn bit 11 set");
99
  fStats.Define(kStatNAttn12,   "NAttn12",   "Attn bit 12 set");
100
  fStats.Define(kStatNAttn13,   "NAttn13",   "Attn bit 13 set");
101
  fStats.Define(kStatNAttn14,   "NAttn14",   "Attn bit 14 set");
102
  fStats.Define(kStatNAttn15,   "NAttn15",   "Attn bit 15 set");
103
}
104
 
105
//------------------------------------------+-----------------------------------
106
//! Destructor
107
 
108
RlinkServer::~RlinkServer()
109
{
110
  Stop();
111
  if (fspConn) fspConn->SetServer(0);
112
}
113
 
114
//------------------------------------------+-----------------------------------
115
//! FIXME_docs
116
 
117
void RlinkServer::SetConnect(const boost::shared_ptr<RlinkConnect>& spconn)
118
{
119
  if (!fspConn && !spconn) return;          // allow 0 = 0 ...
120
  if (fspConn)
121
    throw Rexception("RlinkServer::SetConnect()",
122
                     "Bad state: fspConn already set");
123
  if (!spconn)
124
    throw Rexception("RlinkServer::SetConnect()", "Bad args: spconn==0");
125
 
126
  fspConn = spconn;
127
  fELoop.SetLogFile(fspConn->LogFileSPtr());
128
  fspConn->SetServer(this);
129
  return;
130
}
131
 
132
//------------------------------------------+-----------------------------------
133
//! FIXME_docs
134
 
135
void RlinkServer::AddAttnHandler(const attnhdl_t& attnhdl, uint16_t mask,
136
                                 void* cdata)
137
{
138
  if (mask == 0)
139
    throw Rexception("RlinkServer::AddAttnHandler()", "Bad args: mask == 0");
140
 
141
  boost::lock_guard<RlinkConnect> lock(*fspConn);
142
 
143
  AttnId id(mask, cdata);
144
  for (size_t i=0; i<fAttnDsc.size(); i++) {
145
    if (fAttnDsc[i].fId == id) {
146
      throw Rexception("RlinkServer::AddAttnHandler()",
147
                       "Bad args: duplicate handler");
148
    }
149
  }
150
  fAttnDsc.push_back(AttnDsc(attnhdl, id));
151
 
152
  return;
153
}
154
 
155
//------------------------------------------+-----------------------------------
156
//! FIXME_docs
157
 
158 28 wfjm
void RlinkServer::GetAttnInfo(AttnArgs& args, RlinkCommandList& clist)
159
{
160
  RlinkCommand& cmd0 = clist[0];
161
  if (cmd0.Command() != RlinkCommand::kCmdAttn)
162
    throw Rexception("RlinkServer::GetAttnInfo", "clist did't start with attn");
163
 
164 29 wfjm
  Exec(clist);
165 28 wfjm
 
166
  args.fAttnHarvest = cmd0.Data();
167
  args.fHarvestDone = true;
168
 
169
  return;
170
}
171
 
172
//------------------------------------------+-----------------------------------
173
//! FIXME_docs
174
 
175
void RlinkServer::GetAttnInfo(AttnArgs& args)
176
{
177
  RlinkCommandList clist;
178
  clist.AddAttn();
179
  GetAttnInfo(args, clist);
180
  return;
181
}
182
 
183
//------------------------------------------+-----------------------------------
184
//! FIXME_docs
185
 
186 19 wfjm
void RlinkServer::RemoveAttnHandler(uint16_t mask, void* cdata)
187
{
188
  boost::lock_guard<RlinkConnect> lock(*fspConn);
189
 
190
  AttnId id(mask, cdata);
191
  for (size_t i=0; i<fAttnDsc.size(); i++) {
192
    if (fAttnDsc[i].fId == id) {
193
      fAttnDsc.erase(fAttnDsc.begin()+i);
194
      return;
195
    }
196
  }
197
 
198
  throw Rexception("RlinkServer::RemoveAttnHandler()",
199
                   "Bad args: unknown handler");
200
}
201
 
202
//------------------------------------------+-----------------------------------
203
//! FIXME_docs
204
 
205
void RlinkServer::QueueAction(const actnhdl_t& actnhdl)
206
{
207
  boost::lock_guard<RlinkConnect> lock(*fspConn);
208
  fActnList.push_back(actnhdl);
209
  if (IsActiveOutside()) Wakeup();
210
  return;
211
}
212
 
213
//------------------------------------------+-----------------------------------
214
//! FIXME_docs
215
 
216
void RlinkServer::AddPollHandler(const pollhdl_t& pollhdl,
217
                                        int fd, short events)
218
{
219
  boost::lock_guard<RlinkConnect> lock(*fspConn);
220
  fELoop.AddPollHandler(pollhdl, fd, events);
221
  if (IsActiveOutside()) Wakeup();
222
  return;
223
}
224
 
225
//------------------------------------------+-----------------------------------
226
//! FIXME_docs
227
 
228
bool RlinkServer::TestPollHandler(int fd, short events)
229
{
230
  boost::lock_guard<RlinkConnect> lock(*fspConn);
231
  return fELoop.TestPollHandler(fd, events);
232
}
233
 
234
//------------------------------------------+-----------------------------------
235
//! FIXME_docs
236
 
237
void RlinkServer::RemovePollHandler(int fd, short events, bool nothrow)
238
{
239
  boost::lock_guard<RlinkConnect> lock(*fspConn);
240
  fELoop.RemovePollHandler(fd, events,nothrow);
241
  if (IsActiveOutside()) Wakeup();
242
  return;
243
}
244
 
245
//------------------------------------------+-----------------------------------
246
//! FIXME_docs
247
 
248
void RlinkServer::RemovePollHandler(int fd)
249
{
250
  boost::lock_guard<RlinkConnect> lock(*fspConn);
251
  fELoop.RemovePollHandler(fd);
252
  if (IsActiveOutside()) Wakeup();
253
  return;
254
}
255
 
256
//------------------------------------------+-----------------------------------
257
//! FIXME_docs
258
 
259
void RlinkServer::Start()
260
{
261 20 wfjm
  StartOrResume(false);
262 19 wfjm
  return;
263
}
264
 
265
//------------------------------------------+-----------------------------------
266
//! FIXME_docs
267
 
268
void RlinkServer::Stop()
269
{
270
  fELoop.Stop();
271
  Wakeup();
272
  fServerThread.join();
273
  return;
274
}
275
 
276
//------------------------------------------+-----------------------------------
277
//! FIXME_docs
278
 
279 20 wfjm
void RlinkServer::Resume()
280
{
281
  StartOrResume(true);
282
  return;
283
}
284
 
285
//------------------------------------------+-----------------------------------
286
//! FIXME_docs
287
 
288 19 wfjm
void RlinkServer::Wakeup()
289
{
290
  uint64_t one(1);
291
  int irc = write(fWakeupEvent, &one, sizeof(one));
292
  if (irc < 0)
293
    throw Rexception("RlinkServer::Wakeup()",
294
                     "write() to eventfd failed: ", errno);
295
  return;
296
}
297
 
298
//------------------------------------------+-----------------------------------
299
//! FIXME_docs
300
 
301 27 wfjm
void RlinkServer::SignalAttnNotify(uint16_t apat)
302 19 wfjm
{
303 27 wfjm
  // only called under lock !!
304
  if (apat & fAttnNotiPatt) {
305
    RlogMsg lmsg(LogFile(), 'W');
306 28 wfjm
    lmsg << "SignalAttnNotify: redundant notify:"
307
         << " have=" << RosPrintBvi(fAttnNotiPatt,16)
308
         << " apat=" << RosPrintBvi(apat,16);
309 27 wfjm
  }
310
  fAttnNotiPatt |= apat;
311 19 wfjm
  Wakeup();
312
  return;
313
}
314
 
315
//------------------------------------------+-----------------------------------
316 27 wfjm
//! Indicates whether server is active.
317
/*!
318
  \returns \c true if server active.
319
 */
320 19 wfjm
 
321
bool RlinkServer::IsActive() const
322
{
323
  return fServerThread.get_id() != boost::thread::id();
324
}
325
 
326
//------------------------------------------+-----------------------------------
327 27 wfjm
//! Indicates whether server is active and caller is inside server thread.
328
/*!
329
  \returns \c true if server active and method is called from server thread.
330
 */
331 19 wfjm
 
332
bool RlinkServer::IsActiveInside() const
333
{
334
  return IsActive() && boost::this_thread::get_id() == fServerThread.get_id();
335
}
336
 
337
//------------------------------------------+-----------------------------------
338 27 wfjm
//! Indicates whether server is active and caller is outside server thread.
339
/*!
340
  \returns \c true if server active and method is called from a thread
341
           other than the server thread.
342
 */
343 19 wfjm
 
344
bool RlinkServer::IsActiveOutside() const
345
{
346
  return IsActive() && boost::this_thread::get_id() != fServerThread.get_id();
347
}
348
 
349
//------------------------------------------+-----------------------------------
350
//! FIXME_docs
351
 
352 21 wfjm
void RlinkServer::SetTraceLevel(uint32_t level)
353 19 wfjm
{
354
  fTraceLevel = level;
355
  fELoop.SetTraceLevel(level);
356
  return;
357
}
358
 
359
//------------------------------------------+-----------------------------------
360
//! FIXME_docs
361
 
362
void RlinkServer::Print(std::ostream& os) const
363
{
364
  os << "RlinkServer::Print(std::ostream& os)" << endl;
365
  return;
366
}
367
 
368
//------------------------------------------+-----------------------------------
369
//! FIXME_docs
370
 
371
void RlinkServer::Dump(std::ostream& os, int ind, const char* text) const
372
{
373
  // FIXME_code: is that thread safe ??? fActnList.size() ???
374
  RosFill bl(ind);
375
  os << bl << (text?text:"--") << "RlinkServer @ " << this << endl;
376
  os << bl << "  fspConn:         " <<  fspConn << endl;
377
 
378
  os << bl << "  fAttnDsc:        " << endl;
379
  for (size_t i=0; i<fAttnDsc.size(); i++)
380
    os << bl << "    [" << RosPrintf(i,"d",3) << "]: "
381
       << RosPrintBvi(fAttnDsc[i].fId.fMask,16)
382
       << ", " << fAttnDsc[i].fId.fCdata << endl;
383
  os << bl << "  fActnList.size:  " << fActnList.size() << endl;
384
  fELoop.Dump(os, ind+2, "fELoop");
385
  os << bl << "  fServerThread:   " << fServerThread.get_id() << endl;
386
  os << bl << "  fAttnPatt:       " << RosPrintBvi(fAttnPatt,16) << endl;
387 27 wfjm
  os << bl << "  fAttnNotiPatt:   " << RosPrintBvi(fAttnNotiPatt,16) << endl;
388 19 wfjm
  fStats.Dump(os, ind+2, "fStats: ");
389
  return;
390
}
391
 
392
//------------------------------------------+-----------------------------------
393
//! FIXME_docs
394
 
395 20 wfjm
void RlinkServer::StartOrResume(bool resume)
396
{
397
  if (IsActive())
398
    throw Rexception("RlinkServer::StartOrResume()",
399
                     "Bad state: server thread already running");
400
  if (!fspConn->IsOpen())
401
    throw Rexception("RlinkServer::StartOrResume()",
402
                     "Bad state: RlinkConnect not open");
403
 
404
  boost::lock_guard<RlinkConnect> lock(Connect());
405 27 wfjm
  // enable attn notify send
406 20 wfjm
  RlinkCommandList clist;
407
  if (!resume) clist.AddAttn();
408 27 wfjm
  clist.AddWreg(RlinkConnect::kRbaddr_RLCNTL, RlinkConnect::kRLCNTL_M_AnEna);
409 20 wfjm
  Exec(clist);
410
 
411
  // setup poll handler for Rlink traffic
412
  int rlinkfd = fspConn->Port()->FdRead();
413
  if (!fELoop.TestPollHandler(rlinkfd, POLLIN))
414
    fELoop.AddPollHandler(boost::bind(&RlinkServer::RlinkHandler, this, _1),
415
                          rlinkfd, POLLIN);
416
 
417
  // and start server thread
418 30 wfjm
  fELoop.UnStop();
419 20 wfjm
  fServerThread = boost::thread(boost::bind(&RlinkServerEventLoop::EventLoop,
420
                                            &fELoop));
421
 
422
  if (resume) {
423
    RerrMsg emsg;
424
    if (!Connect().SndAttn(emsg)) {
425
      RlogMsg lmsg(LogFile(), 'E');
426
      lmsg << "attn send for server resume failed:" << emsg;
427
    }
428
  }
429
 
430
  return;
431
}
432
 
433
//------------------------------------------+-----------------------------------
434
//! FIXME_docs
435
 
436 19 wfjm
void RlinkServer::CallAttnHandler()
437
{
438 28 wfjm
  fStats.Inc(kStatNAttnHdl);
439 31 wfjm
  if (fTraceLevel>0) {
440
    RlogMsg lmsg(LogFile());
441
    lmsg << "-I attnhdl-beg: patt=" << RosPrintBvi(fAttnPatt,8);
442
  }
443 28 wfjm
 
444
  // if notifier pending, transfer it to current attn pattern
445 27 wfjm
  if (fAttnNotiPatt) {
446 19 wfjm
    boost::lock_guard<RlinkConnect> lock(*fspConn);
447 28 wfjm
    fStats.Inc(kStatNAttnNoti);
448 31 wfjm
    if (fTraceLevel>0) {
449
      RlogMsg lmsg(LogFile());
450
      lmsg << "-I attnhdl-add: patt=" << RosPrintBvi(fAttnPatt,8)
451
           << " noti=" << RosPrintBvi(fAttnNotiPatt,8);
452
    }
453 28 wfjm
    fAttnPatt |= fAttnNotiPatt;
454 27 wfjm
    fAttnNotiPatt = 0;
455 28 wfjm
  }
456 27 wfjm
 
457 28 wfjm
  // do stats for pending attentions
458
  for (size_t i=0; i<16; i++) {
459
    if (fAttnPatt & (uint16_t(1)<<i)) fStats.Inc(kStatNAttn00+i);
460
  }
461 27 wfjm
 
462 28 wfjm
  // now call handlers, multiple handlers may be called for one attn bit
463
  uint16_t hnext = 0;
464 19 wfjm
  uint16_t hdone = 0;
465
  for (size_t i=0; i<fAttnDsc.size(); i++) {
466
    uint16_t hmatch = fAttnPatt & fAttnDsc[i].fId.fMask;
467
    if (hmatch) {
468
      AttnArgs args(fAttnPatt, fAttnDsc[i].fId.fMask);
469 28 wfjm
      boost::lock_guard<RlinkConnect> lock(*fspConn);
470
 
471 31 wfjm
      if (fTraceLevel>0) {
472
        RlogMsg lmsg(LogFile());
473
        lmsg << "-I attnhdl-bef: patt=" << RosPrintBvi(fAttnPatt,8)
474
             << " hmat=" << RosPrintBvi(hmatch,8);
475
      }
476
 
477 19 wfjm
      // FIXME_code: return code not used, yet
478
      fAttnDsc[i].fHandler(args);
479 28 wfjm
      if (!args.fHarvestDone)
480
        Rexception("RlinkServer::CallAttnHandler()",
481 31 wfjm
                   "Handler didn't set fHarvestDone");
482 28 wfjm
 
483
      uint16_t hnew = args.fAttnHarvest & ~fAttnDsc[i].fId.fMask;
484 31 wfjm
      hnext |=  hnew;
485
      hnext &= ~hmatch;      // FIXME_code: this is a patch
486
                             //   works for single lam handlers only
487
                             //   ok for now, but will not work in general !!
488
      hdone |=  hmatch;
489
 
490
      if (fTraceLevel>0) {
491
        RlogMsg lmsg(LogFile());
492
        lmsg << "-I attnhdl-aft: patt=" << RosPrintBvi(fAttnPatt,8)
493
             << " done=" << RosPrintBvi(hdone,8)
494
             << " next=" << RosPrintBvi(hnext,8);
495
      }
496
 
497 19 wfjm
    }
498
  }
499
  fAttnPatt &= ~hdone;                      // clear handled bits
500
 
501 28 wfjm
  // if there are any unhandled attenions, do default handling which will
502
  // ensure that attention harvest is done
503
  if (fAttnPatt) {
504
    AttnArgs args(fAttnPatt, fAttnPatt);
505
    GetAttnInfo(args);
506
    hnext |= args.fAttnHarvest & ~fAttnPatt;
507
    if (fTraceLevel>0) {
508
      RlogMsg lmsg(LogFile(), 'I');
509
      lmsg << "eloop: unhandled attn, mask="
510
           << RosPrintBvi(fAttnPatt,16) << endl;
511
    }
512 19 wfjm
  }
513
 
514 28 wfjm
  // finally replace current attn pattern by the attentions found during
515
  // harvest and not yet handled
516
  fAttnPatt = hnext;
517
  if (fAttnPatt) fStats.Inc(kStatNAttnHarv);
518 19 wfjm
 
519
  return;
520
}
521
 
522
//------------------------------------------+-----------------------------------
523
//! FIXME_docs
524
 
525
void RlinkServer::CallActnHandler()
526
{
527
  if (!ActnPending()) return;
528
 
529
  // call first action
530
  boost::lock_guard<RlinkConnect> lock(*fspConn);
531
 
532
  int irc = fActnList.front()();
533
 
534 20 wfjm
  // if irc>0 requeue to end, otherwise drop
535
  if (irc > 0) {
536 19 wfjm
    fActnList.splice(fActnList.end(), fActnList, fActnList.begin());
537
  } else {
538
    fActnList.pop_front();
539
  }
540
 
541
  return;
542
}
543
 
544
//------------------------------------------+-----------------------------------
545
//! FIXME_docs
546
 
547
int RlinkServer::WakeupHandler(const pollfd& pfd)
548
{
549
  fStats.Inc(kStatNWakeupEvt);
550
 
551
  // bail-out and cancel handler if poll returns an error event
552
  if (pfd.revents & (~pfd.events)) return -1;
553
 
554
  uint64_t buf;
555
  int irc = read(fWakeupEvent, &buf, sizeof(buf));
556
  if (irc < 0)
557
    throw Rexception("RlinkServer::WakeupHandler()",
558
                     "read() from eventfd failed: ", errno);
559
  return 0;
560
}
561
 
562
//------------------------------------------+-----------------------------------
563
//! FIXME_docs
564
 
565
int RlinkServer::RlinkHandler(const pollfd& pfd)
566
{
567
  fStats.Inc(kStatNRlinkEvt);
568
 
569
  // bail-out and cancel handler if poll returns an error event
570
  if (pfd.revents & (~pfd.events)) return -1;
571
 
572 27 wfjm
  fspConn->HandleUnsolicitedData();
573 19 wfjm
  return 0;
574
}
575
 
576
} // end namespace Retro

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.