]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // (C) Copyright Dustin Spicuzza 2009. |
2 | // Adapted to vxWorks 6.9 by Peter Brockamp 2012. | |
3 | // Use, modification and distribution are subject to the | |
4 | // Boost Software License, Version 1.0. (See accompanying file | |
5 | // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
6 | ||
7 | // See http://www.boost.org for most recent version. | |
8 | ||
9 | // Since WRS does not yet properly support boost under vxWorks | |
10 | // and this file was badly outdated, but I was keen on using it, | |
11 | // I patched boost myself to make things work. This has been tested | |
12 | // and adapted by me for vxWorks 6.9 *only*, as I'm lacking access | |
13 | // to earlier 6.X versions! The only thing I know for sure is that | |
14 | // very old versions of vxWorks (namely everything below 6.x) are | |
15 | // absolutely unable to use boost. This is mainly due to the completely | |
16 | // outdated libraries and ancient compiler (GCC 2.96 or worse). Do | |
17 | // not even think of getting this to work, a miserable failure will | |
18 | // be guaranteed! | |
19 | // Equally, this file has been tested for RTPs (Real Time Processes) | |
20 | // only, not for DKMs (Downloadable Kernel Modules). These two types | |
21 | // of executables differ largely in the available functionality of | |
22 | // the C-library, STL, and so on. A DKM uses a library similar to those | |
23 | // of vxWorks 5.X - with all its limitations and incompatibilities | |
24 | // with respect to ANSI C++ and STL. So probably there might be problems | |
25 | // with the usage of boost from DKMs. WRS or any voluteers are free to | |
26 | // prove the opposite! | |
27 | ||
28 | // ==================================================================== | |
29 | // | |
30 | // Some important information regarding the usage of POSIX semaphores: | |
31 | // ------------------------------------------------------------------- | |
32 | // | |
33 | // VxWorks as a real time operating system handles threads somewhat | |
34 | // different from what "normal" OSes do, regarding their scheduling! | |
35 | // This could lead to a scenario called "priority inversion" when using | |
36 | // semaphores, see http://en.wikipedia.org/wiki/Priority_inversion. | |
37 | // | |
38 | // Now, VxWorks POSIX-semaphores for DKM's default to the usage of | |
39 | // priority inverting semaphores, which is fine. On the other hand, | |
40 | // for RTP's it defaults to using non priority inverting semaphores, | |
41 | // which could easily pose a serious problem for a real time process, | |
42 | // i.e. deadlocks! To overcome this two possibilities do exist: | |
43 | // | |
44 | // a) Patch every piece of boost that uses semaphores to instanciate | |
45 | // the proper type of semaphores. This is non-intrusive with respect | |
46 | // to the OS and could relatively easy been done by giving all | |
47 | // semaphores attributes deviating from the default (for in-depth | |
48 | // information see the POSIX functions pthread_mutexattr_init() | |
49 | // and pthread_mutexattr_setprotocol()). However this breaks all | |
50 | // too easily, as with every new version some boost library could | |
51 | // all in a sudden start using semaphores, resurrecting the very | |
52 | // same, hard to locate problem over and over again! | |
53 | // | |
54 | // b) We could change the default properties for POSIX-semaphores | |
55 | // that VxWorks uses for RTP's and this is being suggested here, | |
56 | // as it will more or less seamlessly integrate with boost. I got | |
57 | // the following information from WRS how to do this, compare | |
58 | // Wind River TSR# 1209768: | |
59 | // | |
60 | // Instructions for changing the default properties of POSIX- | |
61 | // semaphores for RTP's in VxWorks 6.9: | |
62 | // - Edit the file /vxworks-6.9/target/usr/src/posix/pthreadLib.c | |
63 | // in the root of your Workbench-installation. | |
64 | // - Around line 917 there should be the definition of the default | |
65 | // mutex attributes: | |
66 | // | |
67 | // LOCAL pthread_mutexattr_t defaultMutexAttr = | |
68 | // { | |
69 | // PTHREAD_INITIALIZED_OBJ, PTHREAD_PRIO_NONE, 0, | |
70 | // PTHREAD_MUTEX_DEFAULT | |
71 | // }; | |
72 | // | |
73 | // Here, replace PTHREAD_PRIO_NONE by PTHREAD_PRIO_INHERIT. | |
74 | // - Around line 1236 there should be a definition for the function | |
75 | // pthread_mutexattr_init(). A couple of lines below you should | |
76 | // find a block of code like this: | |
77 | // | |
78 | // pAttr->mutexAttrStatus = PTHREAD_INITIALIZED_OBJ; | |
79 | // pAttr->mutexAttrProtocol = PTHREAD_PRIO_NONE; | |
80 | // pAttr->mutexAttrPrioceiling = 0; | |
81 | // pAttr->mutexAttrType = PTHREAD_MUTEX_DEFAULT; | |
82 | // | |
83 | // Here again, replace PTHREAD_PRIO_NONE by PTHREAD_PRIO_INHERIT. | |
84 | // - Finally, rebuild your VSB. This will create a new VxWorks kernel | |
85 | // with the changed properties. That's it! Now, using boost should | |
86 | // no longer cause any problems with task deadlocks! | |
87 | // | |
88 | // And here's another useful piece of information concerning VxWorks' | |
89 | // POSIX-functionality in general: | |
90 | // VxWorks is not a genuine POSIX-OS in itself, rather it is using a | |
91 | // kind of compatibility layer (sort of a wrapper) to emulate the | |
92 | // POSIX-functionality by using its own resources and functions. | |
93 | // At the time a task (thread) calls it's first POSIX-function during | |
94 | // runtime it is being transformed by the OS into a POSIX-thread. | |
95 | // This transformation does include a call to malloc() to allocate the | |
96 | // memory required for the housekeeping of POSIX-threads. In a high | |
97 | // priority RTP this malloc() call may be highly undesirable, as its | |
98 | // timing is more or less unpredictable (depending on what your actual | |
99 | // heap looks like). You can circumvent this problem by calling the | |
100 | // function thread_self() at a well defined point in the code of the | |
101 | // task, e.g. shortly after the task spawns up. Thereby you are able | |
102 | // to define the time when the task-transformation will take place and | |
103 | // you could shift it to an uncritical point where a malloc() call is | |
104 | // tolerable. So, if this could pose a problem for your code, remember | |
105 | // to call thread_self() from the affected task at an early stage. | |
106 | // | |
107 | // ==================================================================== | |
108 | ||
109 | // Block out all versions before vxWorks 6.x, as these don't work: | |
110 | // Include header with the vxWorks version information and query them | |
111 | #include <version.h> | |
112 | #if !defined(_WRS_VXWORKS_MAJOR) || (_WRS_VXWORKS_MAJOR < 6) | |
113 | # error "The vxWorks version you're using is so badly outdated,\ | |
114 | it doesn't work at all with boost, sorry, no chance!" | |
115 | #endif | |
116 | ||
117 | // Handle versions above 5.X but below 6.9 | |
118 | #if (_WRS_VXWORKS_MAJOR == 6) && (_WRS_VXWORKS_MINOR < 9) | |
119 | // TODO: Starting from what version does vxWorks work with boost? | |
120 | // We can't reasonably insert a #warning "" as a user hint here, | |
121 | // as this will show up with every file including some boost header, | |
122 | // badly bugging the user... So for the time being we just leave it. | |
123 | #endif | |
124 | ||
125 | // vxWorks specific config options: | |
126 | // -------------------------------- | |
127 | #define BOOST_PLATFORM "vxWorks" | |
128 | ||
129 | // Special behaviour for DKMs: | |
130 | #ifdef _WRS_KERNEL | |
131 | // DKMs do not have the <cwchar>-header, | |
132 | // but apparently they do have an intrinsic wchar_t meanwhile! | |
133 | # define BOOST_NO_CWCHAR | |
134 | ||
135 | // Lots of wide-functions and -headers are unavailable for DKMs as well: | |
136 | # define BOOST_NO_CWCTYPE | |
137 | # define BOOST_NO_SWPRINTF | |
138 | # define BOOST_NO_STD_WSTRING | |
139 | # define BOOST_NO_STD_WSTREAMBUF | |
140 | #endif | |
141 | ||
142 | // Generally available headers: | |
143 | #define BOOST_HAS_UNISTD_H | |
144 | #define BOOST_HAS_STDINT_H | |
145 | #define BOOST_HAS_DIRENT_H | |
146 | #define BOOST_HAS_SLIST | |
147 | ||
148 | // vxWorks does not have installed an iconv-library by default, | |
149 | // so unfortunately no Unicode support from scratch is available! | |
150 | // Thus, instead it is suggested to switch to ICU, as this seems | |
151 | // to be the most complete and portable option... | |
152 | #define BOOST_LOCALE_WITH_ICU | |
153 | ||
154 | // Generally available functionality: | |
155 | #define BOOST_HAS_THREADS | |
156 | #define BOOST_HAS_NANOSLEEP | |
157 | #define BOOST_HAS_GETTIMEOFDAY | |
158 | #define BOOST_HAS_CLOCK_GETTIME | |
159 | #define BOOST_HAS_MACRO_USE_FACET | |
160 | ||
161 | // Generally unavailable functionality, delivered by boost's test function: | |
162 | //#define BOOST_NO_DEDUCED_TYPENAME // Commented this out, boost's test gives an errorneous result! | |
163 | #define BOOST_NO_CXX11_EXTERN_TEMPLATE | |
164 | #define BOOST_NO_CXX11_VARIADIC_MACROS | |
165 | ||
166 | // Generally available threading API's: | |
167 | #define BOOST_HAS_PTHREADS | |
168 | #define BOOST_HAS_SCHED_YIELD | |
169 | #define BOOST_HAS_SIGACTION | |
170 | ||
171 | // Functionality available for RTPs only: | |
172 | #ifdef __RTP__ | |
173 | # define BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE | |
174 | # define BOOST_HAS_LOG1P | |
175 | # define BOOST_HAS_EXPM1 | |
176 | #endif | |
177 | ||
178 | // Functionality available for DKMs only: | |
179 | #ifdef _WRS_KERNEL | |
180 | // Luckily, at the moment there seems to be none! | |
181 | #endif | |
182 | ||
183 | // These #defines allow posix_features to work, since vxWorks doesn't | |
184 | // #define them itself for DKMs (for RTPs on the contrary it does): | |
185 | #ifdef _WRS_KERNEL | |
186 | # ifndef _POSIX_TIMERS | |
187 | # define _POSIX_TIMERS 1 | |
188 | # endif | |
189 | # ifndef _POSIX_THREADS | |
190 | # define _POSIX_THREADS 1 | |
191 | # endif | |
192 | #endif | |
193 | ||
194 | // vxWorks doesn't work with asio serial ports: | |
195 | #define BOOST_ASIO_DISABLE_SERIAL_PORT | |
196 | // TODO: The problem here seems to bee that vxWorks uses its own, very specific | |
197 | // ways to handle serial ports, incompatible with POSIX or anything... | |
198 | // Maybe a specific implementation would be possible, but until the | |
199 | // straight need arises... This implementation would presumably consist | |
200 | // of some vxWorks specific ioctl-calls, etc. Any voluteers? | |
201 | ||
202 | // vxWorks-around: <time.h> #defines CLOCKS_PER_SEC as sysClkRateGet() but | |
203 | // miserably fails to #include the required <sysLib.h> to make | |
204 | // sysClkRateGet() available! So we manually include it here. | |
205 | #ifdef __RTP__ | |
206 | # include <time.h> | |
207 | # include <sysLib.h> | |
208 | #endif | |
209 | ||
210 | // vxWorks-around: In <stdint.h> the macros INT32_C(), UINT32_C(), INT64_C() and | |
211 | // UINT64_C() are defined errorneously, yielding not a signed/ | |
212 | // unsigned long/long long type, but a signed/unsigned int/long | |
213 | // type. Eventually this leads to compile errors in ratio_fwd.hpp, | |
214 | // when trying to define several constants which do not fit into a | |
215 | // long type! We correct them here by redefining. | |
216 | #include <cstdint> | |
217 | ||
218 | // Some macro-magic to do the job | |
219 | #define VX_JOIN(X, Y) VX_DO_JOIN(X, Y) | |
220 | #define VX_DO_JOIN(X, Y) VX_DO_JOIN2(X, Y) | |
221 | #define VX_DO_JOIN2(X, Y) X##Y | |
222 | ||
223 | // Correctly setup the macros | |
224 | #undef INT32_C | |
225 | #undef UINT32_C | |
226 | #undef INT64_C | |
227 | #undef UINT64_C | |
228 | #define INT32_C(x) VX_JOIN(x, L) | |
229 | #define UINT32_C(x) VX_JOIN(x, UL) | |
230 | #define INT64_C(x) VX_JOIN(x, LL) | |
231 | #define UINT64_C(x) VX_JOIN(x, ULL) | |
232 | ||
233 | // #include Libraries required for the following function adaption | |
234 | #include <ioLib.h> | |
235 | #include <tickLib.h> | |
236 | #include <sys/time.h> | |
237 | ||
238 | // Use C-linkage for the following helper functions | |
239 | extern "C" { | |
240 | ||
241 | // vxWorks-around: The required functions getrlimit() and getrlimit() are missing. | |
242 | // But we have the similar functions getprlimit() and setprlimit(), | |
243 | // which may serve the purpose. | |
244 | // Problem: The vxWorks-documentation regarding these functions | |
245 | // doesn't deserve its name! It isn't documented what the first two | |
246 | // parameters idtype and id mean, so we must fall back to an educated | |
247 | // guess - null, argh... :-/ | |
248 | ||
249 | // TODO: getprlimit() and setprlimit() do exist for RTPs only, for whatever reason. | |
250 | // Thus for DKMs there would have to be another implementation. | |
251 | #ifdef __RTP__ | |
252 | inline int getrlimit(int resource, struct rlimit *rlp){ | |
253 | return getprlimit(0, 0, resource, rlp); | |
254 | } | |
255 | ||
256 | inline int setrlimit(int resource, const struct rlimit *rlp){ | |
257 | return setprlimit(0, 0, resource, const_cast<struct rlimit*>(rlp)); | |
258 | } | |
259 | #endif | |
260 | ||
261 | // vxWorks has ftruncate() only, so we do simulate truncate(): | |
262 | inline int truncate(const char *p, off_t l){ | |
263 | int fd = open(p, O_WRONLY); | |
264 | if (fd == -1){ | |
265 | errno = EACCES; | |
266 | return -1; | |
267 | } | |
268 | if (ftruncate(fd, l) == -1){ | |
269 | close(fd); | |
270 | errno = EACCES; | |
271 | return -1; | |
272 | } | |
273 | return close(fd); | |
274 | } | |
275 | ||
276 | // Fake symlink handling by dummy functions: | |
277 | inline int symlink(const char*, const char*){ | |
278 | // vxWorks has no symlinks -> always return an error! | |
279 | errno = EACCES; | |
280 | return -1; | |
281 | } | |
282 | ||
283 | inline ssize_t readlink(const char*, char*, size_t){ | |
284 | // vxWorks has no symlinks -> always return an error! | |
285 | errno = EACCES; | |
286 | return -1; | |
287 | } | |
288 | ||
289 | // vxWorks claims to implement gettimeofday in sys/time.h | |
290 | // but nevertheless does not provide it! See | |
291 | // https://support.windriver.com/olsPortal/faces/maintenance/techtipDetail_noHeader.jspx?docId=16442&contentId=WR_TECHTIP_006256 | |
292 | // We implement a surrogate version here via clock_gettime: | |
293 | inline int gettimeofday(struct timeval *tv, void * /*tzv*/) { | |
294 | struct timespec ts; | |
295 | clock_gettime(CLOCK_MONOTONIC, &ts); | |
296 | tv->tv_sec = ts.tv_sec; | |
297 | tv->tv_usec = ts.tv_nsec / 1000; | |
298 | return 0; | |
299 | } | |
300 | ||
301 | // vxWorks does provide neither struct tms nor function times()! | |
302 | // We implement an empty dummy-function, simply setting the user | |
303 | // and system time to the half of thew actual system ticks-value | |
304 | // and the child user and system time to 0. | |
305 | // Rather ugly but at least it suppresses compiler errors... | |
306 | // Unfortunately, this of course *does* have an severe impact on | |
307 | // dependant libraries, actually this is chrono only! Here it will | |
308 | // not be possible to correctly use user and system times! But | |
309 | // as vxWorks is lacking the ability to calculate user and system | |
310 | // process times there seems to be no other possible solution. | |
311 | struct tms{ | |
312 | clock_t tms_utime; // User CPU time | |
313 | clock_t tms_stime; // System CPU time | |
314 | clock_t tms_cutime; // User CPU time of terminated child processes | |
315 | clock_t tms_cstime; // System CPU time of terminated child processes | |
316 | }; | |
317 | ||
318 | inline clock_t times(struct tms *t){ | |
319 | struct timespec ts; | |
320 | clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts); | |
321 | clock_t ticks(static_cast<clock_t>(static_cast<double>(ts.tv_sec) * CLOCKS_PER_SEC + | |
322 | static_cast<double>(ts.tv_nsec) * CLOCKS_PER_SEC / 1000000.0)); | |
323 | t->tms_utime = ticks/2U; | |
324 | t->tms_stime = ticks/2U; | |
325 | t->tms_cutime = 0; // vxWorks is lacking the concept of a child process! | |
326 | t->tms_cstime = 0; // -> Set the wait times for childs to 0 | |
327 | return ticks; | |
328 | } | |
329 | ||
330 | } // extern "C" | |
331 | ||
332 | // Put the selfmade functions into the std-namespace, just in case | |
333 | namespace std { | |
334 | # ifdef __RTP__ | |
335 | using ::getrlimit; | |
336 | using ::setrlimit; | |
337 | # endif | |
338 | using ::truncate; | |
339 | using ::symlink; | |
340 | using ::readlink; | |
341 | using ::times; | |
342 | using ::gettimeofday; | |
343 | } | |
344 | ||
345 | // Some more macro-magic: | |
346 | // vxWorks-around: Some functions are not present or broken in vxWorks | |
347 | // but may be patched to life via helper macros... | |
348 | ||
349 | // Include signal.h which might contain a typo to be corrected here | |
350 | #include <signal.h> | |
351 | ||
352 | #define getpagesize() sysconf(_SC_PAGESIZE) // getpagesize is deprecated anyway! | |
353 | #ifndef S_ISSOCK | |
354 | # define S_ISSOCK(mode) ((mode & S_IFMT) == S_IFSOCK) // Is file a socket? | |
355 | #endif | |
356 | #define lstat(p, b) stat(p, b) // lstat() == stat(), as vxWorks has no symlinks! | |
357 | #ifndef FPE_FLTINV | |
358 | # define FPE_FLTINV (FPE_FLTSUB+1) // vxWorks has no FPE_FLTINV, so define one as a dummy | |
359 | #endif | |
360 | #if !defined(BUS_ADRALN) && defined(BUS_ADRALNR) | |
361 | # define BUS_ADRALN BUS_ADRALNR // Correct a supposed typo in vxWorks' <signal.h> | |
362 | #endif | |
363 | //typedef int locale_t; // locale_t is a POSIX-extension, currently unpresent in vxWorks! | |
364 | ||
365 | // #include boilerplate code: | |
366 | #include <boost/config/posix_features.hpp> | |
367 | ||
368 | // vxWorks lies about XSI conformance, there is no nl_types.h: | |
369 | #undef BOOST_HAS_NL_TYPES_H |