source: trunk/FACT++/src/fad.cc@ 11493

Last change on this file since 11493 was 11493, checked in by tbretz, 13 years ago
Receive the trigger id from the ftm; added gauss pulses in case the data was triggered from the ftm.
File size: 23.2 KB
Line 
1#include <iostream>
2#include <string>
3#include <boost/asio.hpp>
4#include <boost/bind.hpp>
5#include <boost/lexical_cast.hpp>
6#include <boost/asio/deadline_timer.hpp>
7#include <boost/enable_shared_from_this.hpp>
8
9using boost::lexical_cast;
10
11#include "Time.h"
12#include "Converter.h"
13
14#include "HeadersFAD.h"
15
16#include "dis.hxx"
17#include "Dim.h"
18
19using namespace std;
20using namespace FAD;
21
22namespace ba = boost::asio;
23namespace bs = boost::system;
24namespace dummy = ba::placeholders;
25
26using boost::lexical_cast;
27using ba::ip::tcp;
28
29class tcp_connection;
30
31class Trigger : public DimCommandHandler
32{
33 DimCommand fCmd;
34
35 vector<tcp_connection*> vec;
36
37public:
38 Trigger() : fCmd("FAD/TRIGGER", "I:1", this)
39 {
40 }
41
42 void Add(tcp_connection *ptr)
43 {
44 vec.push_back(ptr);
45 }
46
47 void Remove(tcp_connection *ptr)
48 {
49 vec.erase(find(vec.begin(), vec.end(), ptr));
50 }
51
52 void commandHandler();
53};
54
55// ------------------------------------------------------------------------
56
57class tcp_connection : public ba::ip::tcp::socket, public boost::enable_shared_from_this<tcp_connection>
58{
59public:
60 static Trigger fTrigger;
61
62 const int fBoardId;
63
64 double fStartTime;
65
66 void AsyncRead(ba::mutable_buffers_1 buffers)
67 {
68 ba::async_read(*this, buffers,
69 boost::bind(&tcp_connection::HandleReceivedData, shared_from_this(),
70 dummy::error, dummy::bytes_transferred));
71 }
72
73 void AsyncWrite(ba::ip::tcp::socket *socket, const ba::const_buffers_1 &buffers)
74 {
75 ba::async_write(*socket, buffers,
76 boost::bind(&tcp_connection::HandleSentData, shared_from_this(),
77 dummy::error, dummy::bytes_transferred));
78 }
79 void AsyncWait(ba::deadline_timer &timer, int seconds,
80 void (tcp_connection::*handler)(const bs::error_code&))// const
81 {
82 timer.expires_from_now(boost::posix_time::milliseconds(seconds));
83 timer.async_wait(boost::bind(handler, shared_from_this(), dummy::error));
84 }
85
86 // The constructor is prvate to force the obtained pointer to be shared
87 tcp_connection(ba::io_service& ioservice, int boardid) : ba::ip::tcp::socket(ioservice),
88 fBoardId(boardid), fRamRoi(kNumChannels), fTriggerSendData(ioservice),
89 fTriggerEnabled(false)
90 {
91 fTrigger.Add(this);
92 }
93 void PostTrigger(uint32_t triggerid)
94 {
95 if (fTriggerEnabled)
96 get_io_service().post(boost::bind(&tcp_connection::SendData, this, triggerid));
97 }
98
99 // Callback when writing was successfull or failed
100 void HandleSentData(const boost::system::error_code& error, size_t bytes_transferred)
101 {
102 cout << "Data sent: (transmitted=" << bytes_transferred << ") rc=" << error.message() << " (" << error << ")" << endl;
103 fOutQueue.pop_front();
104 }
105
106 vector<uint16_t> fBufCommand;
107
108 vector<uint16_t> fCommand;
109
110 FAD::EventHeader fHeader;
111 FAD::EventHeader fRam;
112 FAD::ChannelHeader fChHeader[kNumChannels];
113
114 vector<uint16_t> fRamRoi;
115
116 ba::deadline_timer fTriggerSendData;
117
118 bool fTriggerEnabled;
119 bool fCommandSocket;
120
121 int fSocket;
122
123 deque<vector<uint16_t>> fOutQueue;
124
125 void SendData(uint32_t triggerid)
126 {
127 fHeader.fPackageLength = sizeof(EventHeader)/2+1;
128 fHeader.fEventCounter++;
129 fHeader.fTriggerId = triggerid;
130 fHeader.fTimeStamp = uint32_t((Time(Time::utc).UnixTime()-fStartTime)*10000);
131 fHeader.fFreqRefClock = 997+rand()/(RAND_MAX/7);
132
133 for (int i=0; i<FAD::kNumTemp; i++)
134 fHeader.fTempDrs[i] = (42.+fBoardId/40.+float(rand())/RAND_MAX*5)*16;
135
136 vector<uint16_t> evtbuf;
137
138 for (int i=0; i<kNumChannels; i++)
139 {
140 fChHeader[i].fStartCell = i*10;
141
142 const vector<uint16_t> buf = fChHeader[i].HtoN();
143
144 evtbuf.insert(evtbuf.end(), buf.begin(), buf.end());
145 evtbuf.insert(evtbuf.end(), fChHeader[i].fRegionOfInterest, 0x42+i+11.*rand()/RAND_MAX-5+fHeader.fDac[1]/32);
146
147 if (triggerid>0)
148 {
149 int p = 5.*rand()/RAND_MAX+20;
150 double rndm = 500.*rand()/RAND_MAX+500;
151 for (int ii=0; ii<fChHeader[i].fRegionOfInterest; ii++)
152 *(evtbuf.end()-fChHeader[i].fRegionOfInterest+ii) = rndm*exp(-0.5*(ii-p)*(ii-p)/25); // sigma=10
153 }
154
155 fHeader.fPackageLength += sizeof(ChannelHeader)/2;
156 fHeader.fPackageLength += fChHeader[i].fRegionOfInterest;
157 }
158
159 evtbuf.push_back(htons(FAD::kDelimiterEnd));
160
161 const vector<uint16_t> h = fHeader.HtoN();
162
163 evtbuf.insert(evtbuf.begin(), h.begin(), h.end());
164
165 fOutQueue.push_back(evtbuf);
166
167 if (fCommandSocket)
168 AsyncWrite(this, ba::buffer(ba::const_buffer(fOutQueue.back().data(), fOutQueue.back().size()*2)));
169 else
170 {
171 if (fSockets.size()==0)
172 return;
173
174 fSocket++;
175 fSocket %= fSockets.size();
176
177 AsyncWrite(fSockets[fSocket].get(), ba::buffer(ba::const_buffer(fOutQueue.back().data(), fOutQueue.back().size()*2)));
178 }
179 }
180
181 void TriggerSendData(const boost::system::error_code &ec)
182 {
183 if (!is_open())
184 {
185 // For example: Here we could schedule a new accept if we
186 // would not want to allow two connections at the same time.
187 return;
188 }
189
190 if (ec==ba::error::basic_errors::operation_aborted)
191 return;
192
193 // Check whether the deadline has passed. We compare the deadline
194 // against the current time since a new asynchronous operation
195 // may have moved the deadline before this actor had a chance
196 // to run.
197 if (fTriggerSendData.expires_at() > ba::deadline_timer::traits_type::now())
198 return;
199
200 // The deadline has passed.
201 if (fTriggerEnabled)
202 SendData(0);
203
204 AsyncWait(fTriggerSendData, fHeader.fTriggerGeneratorPrescaler, &tcp_connection::TriggerSendData);
205 }
206
207 void HandleReceivedData(const boost::system::error_code& error, size_t bytes_received)
208 {
209 // Do not schedule a new read if the connection failed.
210 if (bytes_received==0)
211 {
212 // Close the connection
213 close();
214 return;
215 }
216
217 // No command received yet
218 if (fCommand.size()==0)
219 {
220 transform(fBufCommand.begin(), fBufCommand.begin()+bytes_received/2,
221 fBufCommand.begin(), ntohs);
222
223 switch (fBufCommand[0])
224 {
225 case kCmdDrsEnable:
226 case kCmdDrsEnable+0x100:
227 fHeader.Enable(FAD::EventHeader::kDenable, fBufCommand[0]==kCmdDrsEnable);
228 cout << "-> DrsEnable " << fBoardId << " " << (fBufCommand[0]==kCmdDrsEnable) << endl;
229 break;
230
231 case kCmdDwrite:
232 case kCmdDwrite+0x100:
233 fHeader.Enable(FAD::EventHeader::kDwrite, fBufCommand[0]==kCmdDwrite);
234 cout << "-> Dwrite " << fBoardId << " " << (fBufCommand[0]==kCmdDwrite) << endl;
235 break;
236
237 case kCmdTriggerLine:
238 case kCmdTriggerLine+0x100:
239 cout << "-> Trigger line " << fBoardId << " " << (fBufCommand[0]==kCmdTriggerLine) << endl;
240 fTriggerEnabled = fBufCommand[0]==kCmdTriggerLine;
241 fHeader.Enable(FAD::EventHeader::kTriggerLine, fTriggerEnabled);
242 break;
243
244 case kCmdSclk:
245 case kCmdSclk+0x100:
246 cout << "-> Sclk " << fBoardId << endl;
247 fHeader.Enable(FAD::EventHeader::kSpiSclk, fBufCommand[0]==kCmdSclk);
248 break;
249
250 case kCmdSrclk:
251 case kCmdSrclk+0x100:
252 cout << "-> Drclk " << fBoardId << endl;
253 break;
254
255 case kCmdRun:
256 case kCmdRun+0x100:
257 fStartTime = Time(Time::utc).UnixTime();
258 cout << "-> Run " << fBoardId << endl;
259 break;
260
261 case kCmdBusy:
262 case kCmdBusy+0x100:
263 cout << "-> Busy " << fBoardId << " " << (fBufCommand[0]==kCmdBusy) << endl;
264 fHeader.Enable(FAD::EventHeader::kBusy, fBufCommand[0]==kCmdBusy);
265 break;
266
267 case kCmdSocket:
268 case kCmdSocket+0x100:
269 cout << "-> Socket " << fBoardId << " " << (fBufCommand[0]==kCmdSocket) << endl;
270 fCommandSocket = fBufCommand[0]==kCmdSocket;
271 fHeader.Enable(FAD::EventHeader::kSock17, !fCommandSocket);
272 break;
273
274 case kCmdContTrigger:
275 case kCmdContTrigger+0x100:
276 if (fBufCommand[0]==kCmdContTrigger)
277 AsyncWait(fTriggerSendData, 0, &tcp_connection::TriggerSendData);
278 else
279 fTriggerSendData.cancel();
280 fHeader.Enable(FAD::EventHeader::kContTrigger, fBufCommand[0]==kCmdContTrigger);
281 cout << "-> ContTrig " << fBoardId << " " << (fBufCommand[0]==kCmdContTrigger) << endl;
282 break;
283
284 case kCmdResetEventCounter:
285 cout << "-> ResetId " << fBoardId << endl;
286 fHeader.fEventCounter = 0;
287 break;
288
289 case kCmdSingleTrigger:
290 cout << "-> Trigger " << fBoardId << endl;
291 SendData(0);
292 break;
293
294 case kCmdWriteExecute:
295 cout << "-> Execute " << fBoardId << endl;
296 memcpy(fHeader.fDac, fRam.fDac, sizeof(fHeader.fDac));
297 for (int i=0; i<kNumChannels; i++)
298 fChHeader[i].fRegionOfInterest = fRamRoi[i];
299 fHeader.fRunNumber = fRam.fRunNumber;
300 break;
301
302 case kCmdWriteRunNumberMSW:
303 fCommand = fBufCommand;
304 break;
305
306 case kCmdWriteRunNumberLSW:
307 fCommand = fBufCommand;
308 break;
309
310 default:
311 if (fBufCommand[0]>=kCmdWriteRoi && fBufCommand[0]<kCmdWriteRoi+kNumChannels)
312 {
313 fCommand.resize(2);
314 fCommand[0] = kCmdWriteRoi;
315 fCommand[1] = fBufCommand[0]-kCmdWriteRoi;
316 break;
317 }
318 if (fBufCommand[0]>= kCmdWriteDac && fBufCommand[0]<kCmdWriteDac+kNumDac)
319 {
320 fCommand.resize(2);
321 fCommand[0] = kCmdWriteDac;
322 fCommand[1] = fBufCommand[0]-kCmdWriteDac;
323 break;
324 }
325 if (fBufCommand[0]==kCmdWriteRate)
326 {
327 fCommand.resize(1);
328 fCommand[0] = kCmdWriteRate;
329 break;
330 }
331
332 cout << "Received b=" << bytes_received << ": " << error.message() << " (" << error << ")" << endl;
333 cout << "Hex:" << Converter::GetHex<uint16_t>(&fBufCommand[0], bytes_received) << endl;
334 return;
335 }
336
337 fBufCommand.resize(1);
338 AsyncRead(ba::buffer(fBufCommand));
339 return;
340 }
341
342 transform(fBufCommand.begin(), fBufCommand.begin()+bytes_received/2,
343 fBufCommand.begin(), ntohs);
344
345 switch (fCommand[0])
346 {
347 case kCmdWriteRunNumberMSW:
348 fRam.fRunNumber &= 0xffff;
349 fRam.fRunNumber |= fBufCommand[0]<<16;
350 cout << "-> Set RunNumber " << fBoardId << " MSW" << endl;
351 break;
352 case kCmdWriteRunNumberLSW:
353 fRam.fRunNumber &= 0xffff0000;
354 fRam.fRunNumber |= fBufCommand[0];
355 cout << "-> Set RunNumber " << fBoardId << " LSW" << endl;
356 break;
357 case kCmdWriteRoi:
358 cout << "-> Set " << fBoardId << " Roi[" << fCommand[1] << "]=" << fBufCommand[0] << endl;
359 //fChHeader[fCommand[1]].fRegionOfInterest = fBufCommand[0];
360 fRamRoi[fCommand[1]] = fBufCommand[0];
361 break;
362
363 case kCmdWriteDac:
364 cout << "-> Set " << fBoardId << " Dac[" << fCommand[1] << "]=" << fBufCommand[0] << endl;
365 fRam.fDac[fCommand[1]] = fBufCommand[0];
366 break;
367
368 case kCmdWriteRate:
369 cout << "-> Set " << fBoardId << " Rate =" << fBufCommand[0] << endl;
370 fHeader.fTriggerGeneratorPrescaler = fBufCommand[0];
371 break;
372 }
373
374 fCommand.resize(0);
375
376 fBufCommand.resize(1);
377 AsyncRead(ba::buffer(fBufCommand));
378 }
379
380public:
381 typedef boost::shared_ptr<tcp_connection> shared_ptr;
382
383 static shared_ptr create(ba::io_service& io_service, int boardid)
384 {
385 return shared_ptr(new tcp_connection(io_service, boardid));
386 }
387
388 void start()
389 {
390 // Ownership of buffer must be valid until Handler is called.
391
392 fTriggerEnabled=false;
393 fCommandSocket=true;
394
395 fHeader.fStartDelimiter = FAD::kDelimiterStart;
396 fHeader.fVersion = 0x104;
397 fHeader.fBoardId = (fBoardId%10) | ((fBoardId/10)<<8);
398 fHeader.fRunNumber = 0;
399 fHeader.fDNA = reinterpret_cast<uint64_t>(this);
400 fHeader.fTriggerGeneratorPrescaler = 100;
401 fHeader.fStatus = 0xf<<12 |
402 FAD::EventHeader::kDenable |
403 FAD::EventHeader::kDwrite |
404 FAD::EventHeader::kDcmLocked |
405 FAD::EventHeader::kDcmReady |
406 FAD::EventHeader::kSpiSclk;
407
408
409 fStartTime = Time(Time::utc).UnixTime();
410
411 for (int i=0; i<kNumChannels; i++)
412 {
413 fChHeader[i].fId = (i%9) | ((i/9)<<4);
414 fChHeader[i].fRegionOfInterest = 0;
415 }
416
417 // Emit something to be written to the socket
418 fBufCommand.resize(1);
419 AsyncRead(ba::buffer(fBufCommand));
420
421// AsyncWait(fTriggerDynData, 1, &tcp_connection::SendDynData);
422
423// AsyncWrite(ba::buffer(ba::const_buffer(&fHeader, sizeof(FTM::Header))));
424// AsyncWait(deadline_, 3, &tcp_connection::check_deadline);
425
426 }
427
428 vector<boost::shared_ptr<ba::ip::tcp::socket>> fSockets;
429
430 ~tcp_connection()
431 {
432 fTrigger.Remove(this);
433 fSockets.clear();
434 }
435
436 void handle_accept(boost::shared_ptr<ba::ip::tcp::socket> socket, int port, const boost::system::error_code&/* error*/)
437 {
438 cout << this << " Added one socket[" << fBoardId << "] " << socket->remote_endpoint().address().to_v4().to_string();
439 cout << ":"<< port << endl;
440 fSockets.push_back(socket);
441 }
442};
443
444Trigger tcp_connection::fTrigger;
445
446void Trigger::commandHandler()
447{
448 if (!getCommand())
449 return;
450
451 for (vector<tcp_connection*>::iterator it=vec.begin();
452 it!=vec.end(); it++)
453 (*it)->PostTrigger(getCommand()->getInt());
454}
455
456
457class tcp_server
458{
459 tcp::acceptor acc0;
460 tcp::acceptor acc1;
461 tcp::acceptor acc2;
462 tcp::acceptor acc3;
463 tcp::acceptor acc4;
464 tcp::acceptor acc5;
465 tcp::acceptor acc6;
466 tcp::acceptor acc7;
467
468 int fBoardId;
469
470public:
471 tcp_server(ba::io_service& ioservice, int port, int board) :
472 acc0(ioservice, tcp::endpoint(tcp::v4(), port)),
473 acc1(ioservice, tcp::endpoint(tcp::v4(), port+1)),
474 acc2(ioservice, tcp::endpoint(tcp::v4(), port+2)),
475 acc3(ioservice, tcp::endpoint(tcp::v4(), port+3)),
476 acc4(ioservice, tcp::endpoint(tcp::v4(), port+4)),
477 acc5(ioservice, tcp::endpoint(tcp::v4(), port+5)),
478 acc6(ioservice, tcp::endpoint(tcp::v4(), port+6)),
479 acc7(ioservice, tcp::endpoint(tcp::v4(), port+7)),
480 fBoardId(board)
481 {
482 // We could start listening for more than one connection
483 // here, but since there is only one handler executed each time
484 // it would not make sense. Before one handle_accept is not
485 // finished no new handle_accept will be called.
486 // Workround: Start a new thread in handle_accept
487 start_accept();
488 }
489
490private:
491 void start_accept(tcp_connection::shared_ptr dest, tcp::acceptor &acc)
492 {
493 boost::shared_ptr<ba::ip::tcp::socket> connection =
494 boost::shared_ptr<ba::ip::tcp::socket>(new ba::ip::tcp::socket(acc.io_service()));
495
496 acc.async_accept(*connection,
497 boost::bind(&tcp_connection::handle_accept,
498 dest, connection,
499 acc.local_endpoint().port(),
500 ba::placeholders::error));
501 }
502
503 void start_accept()
504 {
505 cout << "Start accept[" << fBoardId << "] " << acc0.local_endpoint().port() << "..." << flush;
506 tcp_connection::shared_ptr new_connection = tcp_connection::create(/*acceptor_.*/acc0.io_service(), fBoardId);
507
508 cout << new_connection.get() << " ";
509
510 // This will accept a connection without blocking
511 acc0.async_accept(*new_connection,
512 boost::bind(&tcp_server::handle_accept,
513 this,
514 new_connection,
515 ba::placeholders::error));
516
517 start_accept(new_connection, acc1);
518 start_accept(new_connection, acc2);
519 start_accept(new_connection, acc3);
520 start_accept(new_connection, acc4);
521 start_accept(new_connection, acc5);
522 start_accept(new_connection, acc6);
523 start_accept(new_connection, acc7);
524
525 cout << "start-done." << endl;
526 }
527
528 void handle_accept(tcp_connection::shared_ptr new_connection, const boost::system::error_code& error)
529 {
530 // The connection has been accepted and is now ready to use
531
532 // not installing a new handler will stop run()
533 cout << new_connection.get() << " Handle accept[" << fBoardId << "]["<<new_connection->fBoardId<<"]..." << flush;
534 if (!error)
535 {
536 new_connection->start();
537
538 // The is now an open connection/server (tcp_connection)
539 // we immediatly schedule another connection
540 // This allowed two client-connection at the same time
541 start_accept();
542 }
543 cout << "handle-done." << endl;
544 }
545};
546
547#include "Configuration.h"
548
549void SetupConfiguration(::Configuration &conf)
550{
551 const string n = conf.GetName()+".log";
552
553 po::options_description config("Program options");
554 config.add_options()
555 ("dns", var<string>("localhost"), "Dim nameserver host name (Overwites DIM_DNS_NODE environment variable)")
556 ("port,p", var<uint16_t>(4000), "")
557 ("num,n", var<uint16_t>(40), "")
558 ;
559
560 po::positional_options_description p;
561 p.add("port", 1); // The first positional options
562 p.add("num", 1); // The second positional options
563
564 conf.AddEnv("dns", "DIM_DNS_NODE");
565
566 conf.AddOptions(config);
567 conf.SetArgumentPositions(p);
568}
569
570int main(int argc, const char **argv)
571{
572 ::Configuration conf(argv[0]);
573
574 SetupConfiguration(conf);
575
576 po::variables_map vm;
577 try
578 {
579 vm = conf.Parse(argc, argv);
580 }
581#if BOOST_VERSION > 104000
582 catch (po::multiple_occurrences &e)
583 {
584 cerr << "Program options invalid due to: " << e.what() << " of '" << e.get_option_name() << "'." << endl;
585 return -1;
586 }
587#endif
588 catch (exception& e)
589 {
590 cerr << "Program options invalid due to: " << e.what() << endl;
591 return -1;
592 }
593
594 if (conf.HasVersion() || conf.HasPrint() || conf.HasHelp())
595 return -1;
596
597 Dim::Setup(conf.Get<string>("dns"));
598
599 DimServer::start("FAD");
600
601 //try
602 {
603 ba::io_service io_service;
604
605 const uint16_t n = conf.Get<uint16_t>("num");
606 uint16_t port = conf.Get<uint16_t>("port");
607
608 vector<shared_ptr<tcp_server>> servers;
609
610 for (int i=0; i<n; i++)
611 {
612 shared_ptr<tcp_server> server(new tcp_server(io_service, port, i));
613 servers.push_back(server);
614
615 port += 8;
616 }
617
618 // ba::add_service(io_service, &server);
619 // server.add_service(...);
620 //cout << "Run..." << flush;
621
622 // Calling run() from a single thread ensures no concurrent access
623 // of the handler which are called!!!
624 io_service.run();
625
626 //cout << "end." << endl;
627 }
628 /*catch (std::exception& e)
629 {
630 std::cerr << e.what() << std::endl;
631 }*/
632
633 return 0;
634}
635/* ====================== Buffers ===========================
636
637char d1[128]; ba::buffer(d1));
638std::vector<char> d2(128); ba::buffer(d2);
639boost::array<char, 128> d3; by::buffer(d3);
640
641// --------------------------------
642char d1[128];
643std::vector<char> d2(128);
644boost::array<char, 128> d3;
645
646boost::array<mutable_buffer, 3> bufs1 = {
647 ba::buffer(d1),
648 ba::buffer(d2),
649 ba::buffer(d3) };
650sock.read(bufs1);
651
652std::vector<const_buffer> bufs2;
653bufs2.push_back(boost::asio::buffer(d1));
654bufs2.push_back(boost::asio::buffer(d2));
655bufs2.push_back(boost::asio::buffer(d3));
656sock.write(bufs2);
657
658
659// ======================= Read functions =========================
660
661ba::async_read_until --> delimiter
662
663streambuf buf; // Ensure validity until handler!
664by::async_read(s, buf, ....);
665
666ba::async_read(s, ba:buffer(data, size), handler);
667 // Single buffer
668 boost::asio::async_read(s,
669 ba::buffer(data, size),
670 compl-func --> ba::transfer_at_least(32),
671 handler);
672
673 // Multiple buffers
674boost::asio::async_read(s, buffers,
675 compl-func --> boost::asio::transfer_all(),
676 handler);
677 */
678
679// ================= Others ===============================
680
681 /*
682 strand Provides serialised handler execution.
683 work Class to inform the io_service when it has work to do.
684
685
686io_service::
687dispatch Request the io_service to invoke the given handler.
688poll Run the io_service's event processing loop to execute ready
689 handlers.
690poll_one Run the io_service's event processing loop to execute one ready
691 handler.
692post Request the io_service to invoke the given handler and return
693 immediately.
694reset Reset the io_service in preparation for a subsequent run()
695 invocation.
696run Run the io_service's event processing loop.
697run_one Run the io_service's event processing loop to execute at most
698 one handler.
699stop Stop the io_service's event processing loop.
700wrap Create a new handler that automatically dispatches the wrapped
701 handler on the io_service.
702
703strand:: The io_service::strand class provides the ability to
704 post and dispatch handlers with the guarantee that none
705 of those handlers will execute concurrently.
706
707dispatch Request the strand to invoke the given handler.
708get_io_service Get the io_service associated with the strand.
709post Request the strand to invoke the given handler and return
710 immediately.
711wrap Create a new handler that automatically dispatches the
712 wrapped handler on the strand.
713
714work:: The work class is used to inform the io_service when
715 work starts and finishes. This ensures that the io_service's run() function will not exit while work is underway, and that it does exit when there is no unfinished work remaining.
716get_io_service Get the io_service associated with the work.
717work Constructor notifies the io_service that work is starting.
718
719*/
720
721
Note: See TracBrowser for help on using the repository browser.