-
Notifications
You must be signed in to change notification settings - Fork 40
/
Copy pathFAQ
1847 lines (1457 loc) · 70.4 KB
/
FAQ
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
There are many changes and improvements in the new version of ACE.
The ChangeLog file contains complete details about all of them.
I've tested ACE thoroughly on Solaris 2.3 and 2.4 with the SunC++ 4.x
compiler and Centerline 2.x. I've also tested it with the SunC++ 3.x
compiler on the SunOS 4.x platform. However, I've not been able to
test it on other platforms. If anyone has time to do that, and can
report the results back to me I'd appreciate that.
Please let me know if you have any questions or comments.
Doug
----------------------------------------
1. SIGHUP
> 1) Where the heck does the HUP signal get registered for the
> $ACE_ROOT/tests/Service_Configurator/server stuff? I looked there and
> in $ACE_ROOT/libsrc/Service_Configurator. No luck. I guess I am
> just blind from reading.
Take a look in ./libsrc/Service_Configurator/Service_Config.h.
The constructor for Service_Config is where it happens:
Service_Config (int ignore_defaults = 0,
size_t size = Service_Config::MAX_SERVICES,
int signum = SIGHUP);
----------------------------------------
2. Multi-threaded Signal_Handler support
> It appears Signal_Handler is
> not setup for multi-threaded apps. How do you handle signals
> in different threads? Do I have to put in the hooks in my app or should
> it go in the Threads arena?
Ah, good question... My design follows the approach espoused
by Sun. Basically, they suggest that you implement per-thread signal
handling atop of the basic UNIX signal handlers (or in the case of
ACE, the handle_signal() callbacks on Event_Handler subclasses) by
using the thread id returned by thr_self() to index into a search
structure containing the handlers. This should be pretty straight
forward to layer atop the existing ACE Signal_Handler mechanisms.
However, you might ask yourself whether you really want (1) separate
signal handler *functionality* in different threads or (2) different
threads that mask out certain signals. The latter might be easier to
implement and reason about!
----------------------------------------
3. Problems compiling ACE with G++
> I substituted -lg++ for -lC in macro_wrappers.GNU and ran make.
>
> Most stuff seemed to build. Continually got messages like the following:
> ld: /usr2/tss/jvm/ACE_wrappers/lib/libASX.a: warning: archive has no table of c
> ontents; add one using ranlib(1)
> ld: /usr2/tss/jvm/ACE_wrappers/lib/libThreads.a: warning: archive has no table
> of contents; add one using ranlib(1)
> ld: /usr2/tss/jvm/ACE_wrappers/lib/libSPIPE.a: warning: archive has no table of
> contents; add one using ranlib(1)
> ld: /usr2/tss/jvm/ACE_wrappers/lib/libASX.a: warning: archive has no table of c
> ontents; add one using ranlib(1)
> ld: /usr2/tss/jvm/ACE_wrappers/lib/libThreads.a: warning: archive has no table
> of contents; add one using ranlib(1)
> ld: /usr2/tss/jvm/ACE_wrappers/lib/libSPIPE.a: warning: archive has no table of
> contents; add one using ranlib(1)
> no matter how many times I used ranlib or removed the libraries and re-compiled
> or whatever. Perhaps these are System V specific and will not work on 4.1.3?
Yes, that's exactly right. If you look at the files, they all
contain ifdef's for features that aren't included in the
./include/makeinclude/wrapper_macros.GNU file. To make this more
obvious, I've enclosed the following message in the ACE-INSTALL.html file:
* Sun OS 4.1.x
Note that on SunOS 4.x you may get warnings from the
linker that "archive has no table of contents; add
one using ranlib(1)" for certain libraries (e.g.,
libASX.a, libThreads.a, and libSPIPE.a). This
occurs since SunOS 4.x does not support these features.
> never able to get .so -- assume these are shared libraries that gcc can not
> deal with.
Yes, if you use the stock gcc/gas/gnu ld
compiler/assembler/linker, you won't get shared libraries to work. It
is possible to hack this by using the "collect" version of g++.
However, as usual, I strongly advise people to stay away from g++ if
you want to use shared libraries or templates.
> got some linker errors as follows:
>
> g++ -g -DACE_NTRACE -DACE_HAS_MT_SAFE_SOCKETS -DACE_HAS_NO_T_ERRNO -DACE_HAS_
> OLD_MALLOC -DACE_HAS_POLL -DACE_HAS_SEMUN -DACE_HAS_SETOWN -DACE_HAS_STRBUF_T -
> DACE_HAS_STREAMS -DACE_HAS_SVR4_DYNAMIC_LINKING -DACE_HAS_TIUSER_H -DACE_HAS_SY
> S_FILIO_H -DACE_PAGE_SIZE=4096 -DACE_HAS_ALLOCA -DACE_HAS_CPLUSPLUS_HEADERS -DA
> CE_HAS_SVR4_SIGNAL_T -DACE_HAS_STRERROR -DMALLOC_STATS -I/usr2/tss/jvm/ACE_wrap
> pers/include -I/usr2/tss/jvm/ACE_wrappers/libsrc/Shared_Malloc -o test_malloc
> .obj/test_malloc.o -L/usr2/tss/jvm/ACE_wrappers/lib -Bstatic -lSemaphores -lS
> hared_Malloc -lShared_Memory -lReactor -lThreads -lMem_Map -lLog_Msg -lFIFO -lI
> PC_SAP -lMisc -lnsl -lg++
> ld: /usr2/tss/jvm/ACE_wrappers/lib/libThreads.a: warning: archive has no table
> of contents; add one using ranlib(1)
> ld: Undefined symbol
> _free__t6Malloc2Z18Shared_Memory_PoolZ13PROCESS_MUTEXPv
> _free__t6Malloc2Z17Local_Memory_PoolZ10Null_MutexPv
> _malloc__t6Malloc2Z18Shared_Memory_PoolZ13PROCESS_MUTEXUl
> _malloc__t6Malloc2Z17Local_Memory_PoolZ10Null_MutexUl
> _remove__t6Malloc2Z17Local_Memory_PoolZ10Null_Mutex
> ___t6Malloc2Z17Local_Memory_PoolZ10Null_Mutex
> _print_stats__t6Malloc2Z17Local_Memory_PoolZ10Null_Mutex
> _remove__t6Malloc2Z18Shared_Memory_PoolZ13PROCESS_MUTEX
> ___t6Malloc2Z18Shared_Memory_PoolZ13PROCESS_MUTEX
> _print_stats__t6Malloc2Z18Shared_Memory_PoolZ13PROCESS_MUTEX
> collect2: ld returned 2 exit status
> gcc: file path prefix `static' never used
> make[2]: *** [test_malloc] Error 1
> make[2]: Leaving directory `/usr2/tss/jvm/ACE_wrappers/tests/Shared_Malloc'
> <======== End all: /usr2/tss/jvm/ACE_wrappers/tests/Shared_Malloc
That looks like a problem that G++ has with templates. I
don't know of any reasonable solution to this problem using g++.
> Finally decided there was enough stuff that it looked like I might have some
> thing so I tried to run some tests and could not find so much as one piece
> of documentation that might give me some clue about running tests.
You should take a look at ./tests/Service_Configurator/server/README
file. That explains how to run the more complicated tests. As for
the other tests, it is pretty straight forward if you look at the
./tests/IPC_SAP/SOCK_SAP and ./tests/Reactor/* directory code to
figure out how to run the tests. I don't have a Q/A department, so
any documentation has to come from volunteers.
----------------------------------------
4. Is there any docs or man pages on the Log_Record class?
There is a paper in the C++_wrappers_doc.tar.Z file on ics.uci.edu
called reactor2.ps that has some examples of using Log_Record. The
./apps/Logger directories show several examples using Log_Record.
Finally, the source code for Log_Record is pretty short (though it
clearly could be commented better ;-)).
----------------------------------------
5. Signal handling prototypes
> According to the man page on sigaction on our system, that line
> should look something like the following:
>
> sa.sa_handler = SIG_DFL;
The problem is that most versions of UNIX I've come across
don't have a correct prototype for this field of struct sigaction.
That's why I define two variants of signal handler typedefs: one that
is a typedef of the "correct version" (which I call SignalHandler) and
one of which is a typedef of the "incorrect version" (which I call
SignalHandlerV). You might check out the sysincludes.h file to see
how it is defining SignalHandlerV and make sure this matches what your
OS/Compiler defines in <sys/signal.h>
----------------------------------------
6. Omitting shared libraries
> Can anyone tell me a way to turn off the creation of the shared libraries
> in the ACE build.
You can simply comment out the LIB target in the $ACE_ROOT/ace/Makefile
or change the BUILD target from
BUILD = $(VLIB) $(VSHLIB) $(SHLIBA)
to
BUILD = $(VSHLIB) $(SHLIBA)
----------------------------------------
7. DCE threading and signal handling
>Reading the DCE docs leaves me confused as to how to make everyone
>work together in a happy hormonious whole. May basic need is to catch
>asynchronous signals so i can release some global resources before
>the process exits.
You need to spawn a separate thread to handle signals. As part of
your init, do this:
pthread_create(&tid, thread_attr, signal_catcher, NULL);
pthread_detach(&tid);
Where signal_catcher is like this:
static void *
signal_catcher(void *arg)
{
static int catch_sigs[] = {
SIGHUP, SIGINT, SIGQUIT, SIGTERM, SIGCHLD
};
sigset_t catch_these;
int i;
error_status_t st;
for ( ; ; ) {
sigemptyset(&catch_these);
for (i = 0; i < sizeof catch_sigs / sizeof catch_sigs[0]; i++)
sigaddset(&catch_these, catch_sigs[i]);
i = sigwait(&catch_these);
/* Note continue below, to re-do the loop. */
switch (i) {
default:
fprintf(stderr, "Caught signal %d. Exiting.\n", i);
CLEANUP_AND_EXIT();
/* NOTREACHED */
#if defined(SIGCHLD)
case SIGCHLD:
srvrexec__reap();
continue;
#endif /* defined(SIGCHLD) */
}
}
return NULL;
}
----------------------------------------
8.
> I have installed ACE2.15.5 on SunOS 4.1.3 with gcc2.6.0. I run the test program
> ---server_test. The static is OK, but error found when I commented out the first
> one and uncommented out the second one in the svc.conf file:
>
> #static Svc_Manager "-d -p 3912"
> dynamic Remote_Brdcast Service_Object * .shobj/Handle_Broadcast.so:remote_broad
> cast "-p 10001"
>
> The error goes like this:
>
> -----------
> jupiter[12] %server_test -d
> starting up daemon server_test
> opening static service Svc_Manager
> did static on Svc_Manager, error = 0
> signal signal 1 occurred
> beginning reconfiguration at Sat Feb 25 13:40:29 1995
> Segmentation fault (core dumped)
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
My guess is that the code generated by GCC on SunOS 4.x does not
correctly initialize static variables from shared libraries. The
SunC++ 4.0.x compiler does this correctly on Solaris 2.x (though I
believe that on SunOS 4.x it doesn't work without some extra coaxing).
In general, I try to avoid using ACE's explicit dynamic linking
mechanisms on SunOS 4.x and GCC. You can write plenty of interesting
and useful code with ACE without using those features. Those tests
are mostly there to illustrate the "proof of concept."
----------------------------------------
9.
> a) I noticed the default constructor for the reactor does an open w/ defaults.
> Does this mean I need to close it if I wish to re-open it with different
> size and restart values?
No. With the latest versions of ACE, you can now just call
open() with a new size and it will correctly resize the internal
tables to fit.
> b) What is the usage difference between the normal FD_Set objects
> (rd/wr/ex_handle_mask_) and the ready FD_Set objects
> (rd/wr/ex_handle_mask_ready)?
The normal FD_Sets (now called Handle_Set in ACE 3.0.5) holds
the "waitable" descriptors (these are the descriptors given to
select() or poll()). In contrast, the ready FD_Sets may be set by
Event_Handler subclasses (by called the set_ready() API) to indicate
to the Reactor that they want to be redispatched on the next go-round
*without* blocking. If you look at the Reactor code, you'll see that
the wait_for() method checks the ready sets first and doesn't block if
there are any bits set in those masks. This features makes it
possible for Event_Handlers to control subsequent dispatching policies
of the Reactor.
> c) What does the positive return value do from an event handler callback:
> -1 detaches the event handler for that mask
> 0 does nothing - keeps the event handler registered for that mask
> >0 resets a bit in the current dispatching mask (I think) - does this mean
> this event will be called again before the current dispatch cycle is done?
Almost... (it's tied in with my description of the ready sets above).
It means that once the Reactor finishes cycling through the set of
descriptors it got back from select() or poll(), it will redispatch
the ready set descriptors before sleeping.
> Without direct access to the bit masks in X, I'm not sure I could emulate
> this activity - what do you think?
I'm not sure. I'm not enough of an X guru. Maybe someone else on the
list knows the answer to this?
> d) If I let X do the select blocking, will that have any affect on
> the Reactor performing signal handling?
Yes, I think that will cause problems since the Reactor relies
on a "handshake" between its Signal_Handler component and its
handle_events loop to properly handle signals.
> e) Is the Poll method preferred over Select if it is available - why?
For systems that implement select() in terms of poll() (e.g., Solaris
2.x) then it may be somewhat faster. Otherwise, it doesn't really
matter since (1) they (should) do the same thing and (2) the end user
shouldn't notice any change in behavior.
----------------------------------------
10.
> I would very much like to evaluate/use the ACE Toolkit,
> but am limited as to disk space on our system.
> What is the total disk space required for a compiled,
> usable toolkit?
The source code itself is around 2 Meg, uncompressed.
The compiled version of ACE is around 90 Meg compiled with the SunC++
4.x compiler (naturally, this will differ with other compilers).
However, of this amount, about 40 meg are for the libraries, and
another 50 meg are for the test programs. Naturally, you don't need
to keep the test programs compiled.
The postscript documentation is around 5 Meg, compressed.
----------------------------------------
11.
> This is regarding the newer release of ACE and pertaining to the library
> archive file. My question is, if all the ".o" files are archived into one
> single "libACE.a", does it increase the size of the executable program?
No. The use of a *.a file allows the linker to extract out only those
*.o files that are actually used by the program.
> If it does, then does a large executable program mean possibility of it being
> slower?
No.
----------------------------------------
12.
> What happens if I have several reactors in a process (e.g. in different
> threads)?
>
> Programmer 1 decides to register at reactor 1 in his thread 1 a signal handler
> for SIGUSR.
> Programmer 2 decides to register at reactor 2 in his thread 2 a signal handler
> for SIGUSR.
Naturally, the behavior of this all depends on the semantics
of the threads package... In Solaris 2.x, signal handlers are shared
by all threads. Moreover, the Reactor uses a static table to hold the
thread handlers. Thus, only one of the handler's would be registered
(i.e., whichever one was registered second).
> Programmer 3 designs the process and decides to have thread 1 and thread 2
> running in the same process and also makes use of a third party software library
> that internally has also registered a signal handler (not at the reactor) for
> SIGUSR.
Now you've got big problems! This is an example of a
limitation with UNIX signal handlers... In general, it's a bad idea
to use signal handlers if you can avoid it. This is yet another
reason why.
> When looking into Ace/ACE_wrappers/tests/Reactor/misc/signal_tester.C you
> have shown a way to do this by marking the dummy file_descriptor of the
> Sig_Handler object ready for reading asynchronously. The handle_input()
> routine of Sig_Handler object will then be dispatched synchronously.
> But what happens if I have several reactors.
> The asynchronously dispatched
> handle_signal() routine does not know via which reactor it has been registered
> so in which reactor to modify the dummy file_descriptor.
> Is your suggestion to have just one process global reactor in such a case?
Yes, precisely. I would *strongly* recommend against using
several reactors within separate threads within the same process if
you are going to be having them handle signals. Can you use 1
reactor and/or have one reactor handle signals within a process?
> One thing we want to do is the priorization of Event_Handlers. I.e. in case
> of concurrent events the sequence in which the Event_Handler methods will be
> activated depends on their priority relative to each other.
> We have two choices:
> - complete priorization, which means a high priority Input Event_Handler may
> be activated prior to a lower prioritized Output Event_Handler (and doing
> so violating the 'hardcoded rule' that output must be done prior to input).
> - priorization only in categories, which means all Output Event_handler are
> ordered by their priority regardless of priorities for the category of Input
> Event_Handlers. The priority is fixed between the categories, i.e. first
> output then input then out-of-band.
>
> Right now I would think that we have to use the second choice if we want to
> use the feature of asynchronous output with automatical re-queueing. Am I right
> ?
Hum, that's an interesting problem. It might be better to
subclass the Reactor to form a new class called Priority_Reactor.
This subclass would override the Reactor's dispatch method and
dispatch the event handlers in "priority" order. I've never done
that, but I don't think it would be all that difficult.
----------------------------------------
13.
> Is the Orbix (aka CORBA) version still around?
Nope, IONA does not support Orbix-2.X nor Orbix-3.0 anymore (the
versions of Orbix that the ACE code was based upon). Plus we didn't
maintain this code for ages, so it probably was broken too.
----------------------------------------
14.
> We are using your ACE software and ran into a problem which may or may not
> be related to the mutex locks. The question may have more to do with how
> mutex locks should be used. We had a class which was using your mutex
> lock wrapper. Each member function of the class acquired the lock before
> processing and released on exiting the function. Some member functions may
> call other member functions. The following is an example:
>
> class foo {
>
> void a()
> {
> MT( Mutex_Block<Mutex> m( this->lock_ ));
>
> if( cond )
> b();
> }
>
> void b()
> {
> MT( Mutex_Block<Mutex> m( this->lock_ ));
>
> if( cond )
> a();
> }
>
> };
>
> Is this valid ? My assumtpion is that the mutex lock is recursive and
> the same thread can acquire the lock multiple times in different member
> functions.
Ah, that's a great question since there are subtle and
pernicious problems lurking in the approach you are trying above.
Basically, Solaris mutex locks are *not* recursive (don't ask why...)
Thus, if you want to design an application like the one above you'll
need to use one or more of the following patterns:
----------------------------------------
A. Use recursive mutexes. Although these are not available in
Solaris directly they are supported in the later versions
of ACE. You might want to take a look at the latest
version (./gnu/ACE-3.1.9.tar.Z). It's got lots of new
support for threading and synchronization. In that case,
you simply do the following:
class Foo
{
public:
void a()
{
MT( Guard<Recursive_Lock <Mutex> > m( this->lock_ ));
b ();
}
void b()
{
MT( Guard<Recursive_Lock <Mutex> > m( this->lock_ ));
b_i ();
}
};
The advantage with this is that it requires almost no
changes to existing code. The disadvantage is that
recursive locks are just slightly more expensive.
B. Have two layers of methods (a) which are public and acquire
the Mutex and then call down to methods in layer (b), which
are private and do all the work. Methods in layer b assume
that the locks are held. This avoids the deadlock problem
caused by non-recursive mutexes. Here's what this approach
looks like (using the more recent ACE class names):
class Foo
{
public:
void b()
{
MT( Guard<Mutex> m( this->lock_ ));
b_i ();
}
void b_i()
{
if( cond )
a_i();
}
void a_i()
{
if( cond )
b_i();
}
void a()
{
MT( Guard<Mutex> m( this->lock_ ));
a_i ();
}
};
The advantage here is that inline functions can basically
remove all performance overhead. The disadvantage is that
you need to maintain two sets of interfaces.
C. Yet another approach is to release locks when calling
other methods, like this:
class Foo
{
public:
void b()
{
MT( Guard<Mutex> m( this->lock_ ));
m.release ();
a ();
m.acquire ();
}
void a()
{
MT( Guard<Mutex> m( this->lock_ ));
m.release ();
b ();
m.acquire ();
}
};
The disadvantage with this, of course, is that you
greatly increase your locking overhead. In addition,
you need to be very careful about introducing race
conditions into the code. The primary reason for
using this approach is if you need to call back to
code that you don't have any control over (such as
OS I/O routines) and you don't want to hold the
lock for an indefinite period of time.
----------------------------------------
BTW, all three of these patterns are used in the ACE Reactor
class category. The Reactor has a number of fairly complex
concurrency control and callback issues it must deal with and I've
found it useful to use all three of these patterns jointly.
I'd be interested to hear any comments on these approaches.
Doug
----------------------------------------
15.
> I am working on Solaris 2.3 and trying to understand how to get around
> the problem of trying to open a Socket connection to a remote host that
> is "dead". Of course you get a nice long process block if the socket
> is in Blocking mode (TCP lets you know when you can continue - how polite).
>
> So how does a non-blocking connect work with respect to using
> the Reactor and a SOCK_Stream object to coordinate the opening
> of the connection? Do I wait on the OUTPUT event for the FD?
> How do I know if the connect worked or possibly timed-out? Is
> this a reliable approach (I read somewhere that this will only
> work if the STREAMS module is at the top of the protocol stack
> - MAN page I think)?
An example of implementing this is in the Gateway sample application
in the new ACE. It's also encapsulated in the Connector<> pattern of
the Connection class category in ./libsrc/Connection. You may want to
take a look at those two things for concrete usage examples.
However, the basics of getting non-blocking to work are:
- set socket to non-blocking
- initiate connect() request
- if connect() returned 0 you're connected
- if connect() returned -1 and errno is EWOULDBLOCK (or EAGAIN, depending
on where you are), then register an event handler for read and write events
on the socket
- any other errno value is fatal
When an event is returned
- no matter which event you get back (read or write), you may have gotten
the event out of error. Thus, re-attempt the connect() and check to see if
errno is EISCONN (if it's not there's a problem!)
- if errno was EISCONN, the connection is ready to go, otherwise you must
handle an error condition
If you want to "time out" after a certain period of time, consider
registering for a timer event with Reactor. If the timer goes off before
the connection succeeds, close down the appropriate socket.
> Is using a separate thread to make the connection a better way to avoid
> the potentialy long block in the main thread during the connect call?
You could do that, but it can all be accomplised in a single process using
the facilities available.
----------------------------------------
16.
> I was wondering, does the Reactor class have the ability to prioritize
> activity on the registered event handlers?
The default strategy for the Reactor's dispatch routine
(Reactor::dispatch) does not prioritize dispatching other than to
dispatch callbacks in ascending order from 0 -> maxhandlep1.
> We have a requirment to be able to process both real-time, as well as, stored
> telemetry and ERMs concurrently. Real-time needs to be processed at a higher
> priority than stored data. Our design is based on both real-time and stored
> data coming into our process via separate sockets.
I can think of several ways to do this:
1. Use dup() or dup2() to organize your sockets such that the
higher priority sockets come first in the Handle_Sets that
the Reactor uses to dispatch sockets. This is pretty easy
if you don't want to muck with the Reactor code at all.
2. You could subclass Reactor::dispatch() and revise it so
that it dispatches according to some other criteria that
you define in order to ensure your prioritization of
sockets.
BTW, I'm not sure what you mean by "real-time" but I assume that you
are aware that there is no true "real-time" scheduling for network I/O
in Solaris. However, if by "real-time" you mean "higher priority"
then either of the above strategies should work fine.
----------------------------------------
17.
> I compiled the new ACE 3.2.0 's apps/Gateway. The compiling went
> through without any errors. But I could not get it running, neither single
> threaded nor multi-threaded. The cc_config and rt_config files entries are given
> below. Also the machine configurations are given below. Does it need some more
> settings or some patch !!??
I believe you are seeing the effects of the dreaded Sun MP bug
with non-blocking connects. The easy work around for now is simply to
give the "-b" option to the Gateway::init() routine via the svc.conf
file:
dynamic Gateway Service_Object *.shobj/Gateway.so:_alloc_gatewayd() active
"-b -d -c cc_config -f rt_config"
If you check line 137 of the Gateway::parse_args() method you'll see
what this does.
----------------------------------------
18.
How to get ACE to work with GCC C++ templates.
The first and foremost thing to do is to get the latest version of GCC
(2.7.2) and also get the template repository patches from
ftp://ftp.cygnus.com/pub/g++/gcc-2.7.1-repo.gz
This will get the ball rolling...
Here is some more info on G++ templates courtesy of Medhi TABATABAI
Where's the Template?
=====================
C++ templates are the first language feature to require more
intelligence from the environment than one usually finds on a UNIX
system. Somehow the compiler and linker have to make sure that each
template instance occurs exactly once in the executable if it is
needed, and not at all otherwise. There are two basic approaches to
this problem, which I will refer to as the Borland model and the
Cfront model.
Borland model
Borland C++ solved the template instantiation problem by adding
the code equivalent of common blocks to their linker; template
instances are emitted in each translation unit that uses them, and
they are collapsed together at run time. The advantage of this
model is that the linker only has to consider the object files
themselves; there is no external complexity to worry about. This
disadvantage is that compilation time is increased because the
template code is being compiled repeatedly. Code written for this
model tends to include definitions of all member templates in the
header file, since they must be seen to be compiled.
Cfront model
The AT&T C++ translator, Cfront, solved the template instantiation
problem by creating the notion of a template repository, an
automatically maintained place where template instances are
stored. As individual object files are built, notes are placed in
the repository to record where templates and potential type
arguments were seen so that the subsequent instantiation step
knows where to find them. At link time, any needed instances are
generated and linked in. The advantages of this model are more
optimal compilation speed and the ability to use the system
linker; to implement the Borland model a compiler vendor also
needs to replace the linker. The disadvantages are vastly
increased complexity, and thus potential for error; theoretically,
this should be just as transparent, but in practice it has been
very difficult to build multiple programs in one directory and one
program in multiple directories using Cfront. Code written for
this model tends to separate definitions of non-inline member
templates into a separate file, which is magically found by the
link preprocessor when a template needs to be instantiated.
Currently, g++ implements neither automatic model. The g++ team
hopes to have a repository working for 2.7.0. In the mean time, you
have three options for dealing with template instantiations:
1. Do nothing. Pretend g++ does implement automatic instantiation
management. Code written for the Borland model will work fine, but
each translation unit will contain instances of each of the
templates it uses. In a large program, this can lead to an
unacceptable amount of code duplication.
2. Add `#pragma interface' to all files containing template
definitions. For each of these files, add `#pragma implementation
"FILENAME"' to the top of some `.C' file which `#include's it.
Then compile everything with -fexternal-templates. The templates
will then only be expanded in the translation unit which
implements them (i.e. has a `#pragma implementation' line for the
file where they live); all other files will use external
references. If you're lucky, everything should work properly. If
you get undefined symbol errors, you need to make sure that each
template instance which is used in the program is used in the file
which implements that template. If you don't have any use for a
particular instance in that file, you can just instantiate it
explicitly, using the syntax from the latest C++ working paper:
template class A<int>;
template ostream& operator << (ostream&, const A<int>&);
This strategy will work with code written for either model. If
you are using code written for the Cfront model, the file
containing a class template and the file containing its member
templates should be implemented in the same translation unit.
A slight variation on this approach is to use the flag
-falt-external-templates instead; this flag causes template
instances to be emitted in the translation unit that implements
the header where they are first instantiated, rather than the one
which implements the file where the templates are defined. This
header must be the same in all translation units, or things are
likely to break.
*See Declarations and Definitions in One Header: C++ Interface,
for more discussion of these pragmas.
3. Explicitly instantiate all the template instances you use, and
compile with -fno-implicit-templates. This is probably your best
bet; it may require more knowledge of exactly which templates you
are using, but it's less mysterious than the previous approach,
and it doesn't require any `#pragma's or other g++-specific code.
You can scatter the instantiations throughout your program, you
can create one big file to do all the instantiations, or you can
create tiny files like
#include "Foo.h"
#include "Foo.cc"
template class Foo<int>;
for each instance you need, and create a template instantiation
library from those. I'm partial to the last, but your mileage may
vary. If you are using Cfront-model code, you can probably get
away with not using -fno-implicit-templates when compiling files
that don't `#include' the member template definitions.
4. Placing a function that looks like this near the top of a .C file
that uses any inline template member functions permits proper inlining:
// #ifdef __GNUG__
// This function works around the g++ problem with inline template member
// calls not being inlined ONLY in the first block (in a compilation
// unit) from which they are called.
// This function is inline and is never called, so it does not produce
// any executable code. The "if" statements avoid compiler warnings about
// unused variables.
inline
void
gcc_inline_template_member_function_instantiator()
{
if ( (List<FOO> *) 0 );
}
// #endif // __GNUG__
other prerequisites:
-- All inline template member functions should be defined in
the template class header. Otherwise, g++ will not inline
nested inline template member function calls.
-- Template .h and .C files should NOT include iostream.h
(and therefore debugging.h).
This is because iostream.h indirectly includes other
GNU headers that have unprotected #pragma interface,
which is incompatible with -fno-implicit-templates and optimal
space savings.
-- inline virtual destructors will not be inlined, unless necessary,
if you want to save every last byte
-- be sure that -Winline is enabled
----------------------------------------
19.
> 1. when are dynamically loaded objects removed from the Service_Config.
The Service Configurator calls dlclose() when a "remove Service_Name"
directive is encountered in the svc.conf file (or programmatically
when the Service_Config::remove() method is invoked). Check out the
code in ./libsrc/Service_Config/Service_Repository.i and
./libsrc/Service_Config/Service_Config.i to see exactly what happens.
> 2. In the Service Configurator, when an item is entered in the svc.conf
> how dow you know which items will be invoked as threads and
> which items are forked. I know that static items are executed
> internally.
No! It's totally up to the subclass of Service_Object to
decide whetehr threading/forking/single-threading is used. Check out
the ./apps/Logger/Service_Configurator_Logger for examples of
single-threaded and multi-threaded configuration.
----------------------------------------
20.
> I have been reading the Service Configurator Logger. I was wondering about
> cleanup of new objects. In the handle_input method for the Acceptor a new
> svc_handler is allocated for each new input request and deleted in the
> handle_close. I was wondering how handle close was called when a client who
> has created a socket terminates the connection (i.e., when is handle_close
> called).
handle_close() is automatically called by the Reactor when a
handle_input()/handle_output()/etc. method returns -1. This is the
"hook" that instructs the Reactor to call handle_**() and then remove
the Event_Handler object from its internal tables.
----------------------------------------
21.
> How does the Logger know to remove the client socket and the svc_handler object.
> Does he recieve an exception.
No. when the client terminates the underlying TCP/IP
implementation sends a RESET message to the logger host. This is
delivered to the logger process as a 0-sized read(). It then knows to
close down.
> What I am worried about is a leak. Where by alot of clients connect and
> disconnect and the server does not cleanup correctly. Such as a core dump
> from the client where he cannot close correctly.
That's handled by the underlying TCP (assuming it is
implemented correctly...).
> What I am doing is attempting to convert the logger example into an alarm
> manager for remote nodes. In this application a node may be powered down
> there by terminating a Logger/Alarm server connection abnormally, this could
> leave the Logger with many dangling sockets and allocated svc_handler objects.
If the TCP implementation doesn't handle this correctly then
the standard way of dealing with it is to have an Event_Handler use a
watchdog timer to periodically "poll" the client to make sure it is
still connected. BTW, PCs tend to have more problems with this than
UNIX boxes since when they are turned off the TCP implementation may
not be able to send a RESET...
----------------------------------------
22.
Using templates with Centerline.
Centerline uses ptlink to process the C++ templates. ptlink expect the
template declarations and definitions (app.h and app.C) to reside in
the same directory. This works fine for the ACE hierarchy since
everything is a link to the appropriate src directory (include/*.[hi]
--> ../src/). When a users of the ACE distribution attempts to include
the ACE classes in an existing application hierarchy this problem will
arise if ptlink is used.
The solution is to create a link to the declaration file from the
definition file directory and use the "-I" to point to the definition
directory.
----------------------------------------
23.
> When I try to compile $ACE_ROOT/src/Message_Queue.C on a Solaris
> 5.3 system using SUNPro CC 4.0, the compiler aborts with a Signal 10
> (Bus Error). Our copy of CC 4.0 is over a year old and I do not
> know if any patches or upgrades exist for it. If they do, then we
> have not applied them to our compiler.
Several other people have run across this as well. It turns
out that there is a bug in the Sun 4.0.0 C++ compiler that will get a
bus error when -g is used. If you compilg Message_Queue.C *without*
-g then it works fine. The later versions of SunC++ don't have this
bug. I'd recommend that you upgrade as soon as possible.
----------------------------------------
24.
> I have added a dynamic service to the Service Configurator. This new service
> fails on the load because it uses application libraries that are not shared
> object libraries (i.e., objects in libApp.a). I am assuming from the error
> message that the problem is the mix match of shared and non-shared objects.
Right, exactly.
> I was wondering if there is an easy way to add static services to the
> Service Configurator. The example directory listing static service is
> very tightly coupled with the Service_Config object. Is there another
> way of adding static services.
Sure, that's easy. The best way to do this is to use the
interfaces of the Service_Respository class to configure static
services into the Service_Config. A good example of how to do this is
in Service_Config.[Chi]:
int
Service_Config::load_defaults (void)
{
for (Static_Svc_Descriptor *sl = Service_Config::service_list_; sl->name_ != 0; sl++)
{
Service_Type *stp = ace_create_service_type (sl->name_, sl->type_,
(const void *) (*sl->alloc_)(),
sl->flags_);
if (stp == 0)
continue;
const Service_Record *sr = new Service_Record (sl->name_, stp, 0, sl->active_);
if (Service_Config::svc_rep->insert (sr) == -1)
return -1;
}
return 0;
}
----------------------------------------
25.
> 8. Do you have examples of the SYNC/ASYNC pattern?
Yes. Check out the following:
1. The latest version of ./apps/Gateway/Gateway has
an example of this when you compile with the USE_OUTPUT_MT
flag. In this case, the Reactor performs the "Async"
processing, which multiplexes all incoming messages from peers
arriving on Input_Channels. These messages are then queued
up at the appropriate Output_Channels. Each Output_Channel
runs in a separate thread, performing the "Sync"
processing.
2. Also, the latest version of the OOCP-tutorial4.ps.gz
file available from wuarchive.wustl.edu in the
directory /languages/c++/ACE/ACE-documentation shows
an example of using the Half-Sync/Half-Async pattern
to build an Image Server. I'm using this as an
example in my tutorials these days.
----------------------------------------
26.
> We had a discussion about something we saw in the new ACE code.
> I thing there was a member function of a class that was doing a
> "delete this". Is this safe?
In general it is safe as long as (1) the object has been allocated
dynamically off the heap and (2) you don't try to access the object
after it has been deleted. You'll note that I tend to use this idiom
in places where an object is registered with the Reactor, which must
then must ensure the object cleans itself up when handle_close() is
called. Note that to ensure (1) I try to declare the destructor
"private" or "protected" so that the object must be allocated off the
heap (some compilers have a problem with this, so I may not be as
consistent as I ought to...).
----------------------------------------
27.
> 5. What is the correct way for building a modified ACE library?
> Changing in "libsrc" or in "include" directory?
> When I make a complete new directory, how can I get introduced
> the dependencies within my new makefile, can you give a short hint?