Merge ~epics-core/epics-base/+git/rtems5libcom:hj/rtems5libcom into ~epics-core/epics-base/+git/epics-base:libcom/master

Proposed by Heinz Junkes
Status: Rejected
Rejected by: mdavidsaver
Proposed branch: ~epics-core/epics-base/+git/rtems5libcom:hj/rtems5libcom
Merge into: ~epics-core/epics-base/+git/epics-base:libcom/master
Diff against target: 3753 lines (+3397/-54)
48 files modified
RTEMS/Makefile (+32/-7)
RTEMS/kernel/epicsRtemsInitHookPost.c (+0/-0)
RTEMS/kernel/epicsRtemsInitHooks.h (+0/-0)
RTEMS/kernel/rtems_config.c (+7/-6)
RTEMS/kernel/rtems_init.c (+0/-0)
RTEMS/kernel/rtems_netconfig.c (+56/-41)
RTEMS/kernel/setBootConfigFromNVRAM.c (+0/-0)
RTEMS/ne2kpci.c (+58/-0)
RTEMS/posix/epicsMakeMemFs.pl (+83/-0)
RTEMS/posix/epicsMemFs.c (+110/-0)
RTEMS/posix/epicsMemFs.h (+24/-0)
RTEMS/posix/epicsRtemsInitHookPost.c (+23/-0)
RTEMS/posix/epicsRtemsInitHooks.h (+25/-0)
RTEMS/posix/rtems_config.c (+88/-0)
RTEMS/posix/rtems_init.c (+796/-0)
RTEMS/posix/rtems_netconfig.c (+128/-0)
RTEMS/posix/setBootConfigFromNVRAM.c (+458/-0)
RTEMS/rtems_netconfig.h (+7/-0)
src/osi/os/RTEMS-kernel/epicsAtomicOSD.cpp (+0/-0)
src/osi/os/RTEMS-kernel/epicsAtomicOSD.h (+0/-0)
src/osi/os/RTEMS-kernel/osdEvent.c (+0/-0)
src/osi/os/RTEMS-kernel/osdEvent.h (+0/-0)
src/osi/os/RTEMS-kernel/osdFindSymbol.c (+0/-0)
src/osi/os/RTEMS-kernel/osdMessageQueue.c (+0/-0)
src/osi/os/RTEMS-kernel/osdMessageQueue.h (+0/-0)
src/osi/os/RTEMS-kernel/osdMutex.c (+0/-0)
src/osi/os/RTEMS-kernel/osdMutex.h (+0/-0)
src/osi/os/RTEMS-kernel/osdPoolStatus.c (+0/-0)
src/osi/os/RTEMS-kernel/osdProcess.c (+0/-0)
src/osi/os/RTEMS-kernel/osdReadline.c (+0/-0)
src/osi/os/RTEMS-kernel/osdSignal.cpp (+0/-0)
src/osi/os/RTEMS-kernel/osdSock.h (+0/-0)
src/osi/os/RTEMS-kernel/osdSpin.c (+0/-0)
src/osi/os/RTEMS-kernel/osdStrtod.h (+0/-0)
src/osi/os/RTEMS-kernel/osdThread.c (+0/-0)
src/osi/os/RTEMS-kernel/osdThread.h (+0/-0)
src/osi/os/RTEMS-kernel/osdThreadExtra.c (+0/-0)
src/osi/os/RTEMS-kernel/osdTime.cpp (+0/-0)
src/osi/os/RTEMS-kernel/osdTime.h (+0/-0)
src/osi/os/RTEMS-kernel/osiUnistd.h (+0/-0)
src/osi/os/RTEMS-posix/osdInterrupt.c (+59/-0)
src/osi/os/RTEMS-posix/osdMessageQueue.cpp (+163/-0)
src/osi/os/RTEMS-posix/osdMessageQueue.h (+31/-0)
src/osi/os/RTEMS-posix/osdMutex.c (+6/-0)
src/osi/os/RTEMS-posix/osdPoolStatus.c (+34/-0)
src/osi/os/RTEMS-posix/osdSock.h (+112/-0)
src/osi/os/RTEMS-posix/osdThread.c (+1042/-0)
src/osi/os/RTEMS-posix/osdThread.h (+55/-0)
Reviewer Review Type Date Requested Status
mdavidsaver Disapprove
Review via email: mp+342545@code.launchpad.net
To post a comment you must log in.
Revision history for this message
mdavidsaver (mdavidsaver) wrote :

After a first pass reading through the diff I see two areas which need attention.

1) Parts of my RTEMS testing branch are still included. Not enough to actually work though. I'm referring to the files ne2kpci.*, epicsMakeMemFs.pl, and epicsMemFs.*. I think these could be removed with minimal effort.

2) There is still imo. too much duplication. The files I'd specifically like to see de-duplicated are: rtems_init.c, setBootConfigFromNVRAM.c, and osdThread.*.

review: Needs Fixing
Revision history for this message
Heinz Junkes (junkes) wrote :

> On 5. Apr 2018, at 20:20, mdavidsaver <email address hidden> wrote:
>
> Review: Needs Fixing
>
> After a first pass reading through the diff I see two areas which need attention.
>
> 1) Parts of my RTEMS testing branch are still included. Not enough to actually work though. I'm referring to the files ne2kpci.*, epicsMakeMemFs.pl, and epicsMemFs.*. I think these could be removed with minimal effort.

Ok, thought this is a good idea to include this in rtemss5 … and only there. I had not touch the existing stuff.

>
> 2) There is still imo. too much duplication. The files I'd specifically like to see de-duplicated are: rtems_init.c, setBootConfigFromNVRAM.c, and osdThread.*.

The files are in the respective subfolders posix or kernel to be sure that the old stuff is untouched.
My first approach with ifdef's was not very nice.

Revision history for this message
mdavidsaver (mdavidsaver) wrote :

I did a diff of the RTEMS-kernel/ vs. RTEMS-posix/ vs. posix/ implementations. Some notes below:

> diff -uwrN RTEMS/kernel RTEMS/posix |less

= RTEMS/*/rtems_config.c

These one might as well be different files.

= RTEMS/*/rtems_init.c

The differences here are largely due to my testing changes having been applied to the posix/ version and kernel/ version. Backing these out from the posix/ version, most of the remaining changes have to do with NFS and TFTP file systems. I think this could be further reduced. eg. the 4.10 version of nfsMount() could use mount_and_make_target_path().

= RTEMS/*/rtems_netconfig.c

The diff here is smaller than I expected. Just the removal of loopback_config and not setting the bsdnet thread priority.

= RTEMS/*/setBootConfigFromNVRAM.c

I think all diff here is my doing, and should be applied to both or neither.

> diff -uwr src/osi/os/RTEMS-posix src/osi/os/posix | less

Most of this diff seems to be related to changes to the checkStatus* macro definitions and usage. I didn't look at this in detail.

There is some special handling of the main() thread which seems to be duplicated in init_threadInfo() and rtemsMainInit().

The remainder looks like differences to how thread priorities are handled.

= src/osi/os/RTEMS*/osdInterrupt.c

A verbatim copy.

= src/osi/os/RTEMS-*/osdPoolStatus.c

Another diff which was smaller than I was expecting.

Revision history for this message
mdavidsaver (mdavidsaver) wrote :
review: Disapprove

Unmerged commits

bfe868e... by Heinz Junkes

Add support for Rtems 5

Rtems recommends the posix api for new developments to enable the use of
SMP in the future. To distinguish if posix is used the new GNUmake
variable $(OS_API) is evaluated in the makefile.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/RTEMS/Makefile b/RTEMS/Makefile
2index b0f3b6f..2fb2c36 100644
3--- a/RTEMS/Makefile
4+++ b/RTEMS/Makefile
5@@ -6,12 +6,33 @@
6 # EPICS BASE is distributed subject to a Software License Agreement found
7 # in file LICENSE that is included with this distribution.
8 #*************************************************************************
9-
10-TOP = ..
11+TOP=../../..
12 include $(TOP)/configure/CONFIG
13-include $(TOP)/configure/CONFIG_LIBCOM_VERSION
14
15-INC += epicsRtemsInitHooks.h
16+SRC_IMPL_DIR = $(if $(OS_API),$(OS_API),) kernel
17+
18+SRC_DIRS += ../$(SRC_IMPL_DIR)
19+
20+ifeq ($(OS_API),posix)
21+PERL_SCRIPTS += epicsMakeMemFs.pl
22+endif
23+
24+INC += $(SRC_IMPL_DIR)/epicsRtemsInitHooks.h
25+
26+ifeq ($(OS_API),posix)
27+INC += $(OS_API)/epicsMemFs.h
28+endif
29+
30+ifeq ($(USE_RTEMS_GDBSTUB_$(T_A)),YES)
31+rtems_init_CPPFLAGS += -DUSE_GDBSTUB
32+endif
33+
34+ifeq ($(T_A),RTEMS-pc386)
35+setBootConfigFromNVRAM_CPPFLAGS += -DUSE_MULTIBOOT
36+endif
37+ifeq ($(RTEMS_QEMU_FIXUPS),YES)
38+rtems_init_CPPFLAGS += -DQEMU_FIXUPS
39+endif
40
41 rtemsCom_SRCS += rtems_init.c
42 rtemsCom_SRCS += rtems_config.c
43@@ -20,10 +41,14 @@ rtemsCom_SRCS += rtems_util.c
44 rtemsCom_SRCS += setBootConfigFromNVRAM.c
45 rtemsCom_SRCS += epicsRtemsInitHookPre.c
46 rtemsCom_SRCS += epicsRtemsInitHookPost.c
47+ifeq ($(OS_API),posix)
48+rtemsCom_SRCS += epicsMemFs.c
49+endif
50
51-LIBRARY_RTEMS = rtemsCom
52+ifeq ($(T_A),RTEMS-pc386)
53+rtemsCom_SRCS += ne2kpci.c
54+endif
55
56-# shared library ABI version.
57-SHRLIB_VERSION = $(EPICS_LIBCOM_MAJOR_VERSION).$(EPICS_LIBCOM_MINOR_VERSION).$(EPICS_LIBCOM_MAINTENANCE_VERSION)
58+LIBRARY_RTEMS = rtemsCom
59
60 include $(TOP)/configure/RULES
61diff --git a/RTEMS/epicsRtemsInitHookPost.c b/RTEMS/kernel/epicsRtemsInitHookPost.c
62index f589eb9..f589eb9 100644
63--- a/RTEMS/epicsRtemsInitHookPost.c
64+++ b/RTEMS/kernel/epicsRtemsInitHookPost.c
65diff --git a/RTEMS/epicsRtemsInitHooks.h b/RTEMS/kernel/epicsRtemsInitHooks.h
66index b7f09c1..b7f09c1 100644
67--- a/RTEMS/epicsRtemsInitHooks.h
68+++ b/RTEMS/kernel/epicsRtemsInitHooks.h
69diff --git a/RTEMS/rtems_config.c b/RTEMS/kernel/rtems_config.c
70index 147c08b..6612aad 100644
71--- a/RTEMS/rtems_config.c
72+++ b/RTEMS/kernel/rtems_config.c
73@@ -1,17 +1,17 @@
74 /*************************************************************************\
75 * Copyright (c) 2002 The University of Saskatchewan
76-* EPICS BASE Versions 3.13.7
77-* and higher are distributed subject to a Software License Agreement found
78-* in file LICENSE that is included with this distribution.
79+* EPICS BASE is distributed subject to a Software License Agreement found
80+* in file LICENSE that is included with this distribution.
81 \*************************************************************************/
82 /*
83 * RTEMS configuration for EPICS
84 * Author: W. Eric Norum
85- * norume@aps.anl.gov
86- * (630) 252-4793
87 */
88
89 #include <rtems.h>
90+#include <epicsVersion.h>
91+#define RTEMS_VERSION_INT \
92+ VERSION_INT(__RTEMS_MAJOR__, __RTEMS_MINOR__, __RTEMS_REVISION__, 0)
93
94 /*
95 ***********************************************************************
96@@ -20,7 +20,7 @@
97 */
98 #define CONFIGURE_RTEMS_INIT_TASKS_TABLE
99
100-#if __RTEMS_MAJOR__>4 || (__RTEMS_MAJOR__==4 && __RTEMS_MINOR__>9) || (__RTEMS_MAJOR__==4 && __RTEMS_MINOR__==9 && __RTEMS_REVISION__==99)
101+#if RTEMS_VERSION_INT >= VERSION_INT(4, 9, 99, 0)
102 # define CONFIGURE_UNIFIED_WORK_AREAS
103 #else
104 # define CONFIGURE_EXECUTIVE_RAM_SIZE (2000*1024)
105@@ -54,6 +54,7 @@ rtems_task Init (rtems_task_argument argument);
106 #define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
107 #define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
108
109+#define CONFIGURE_FILESYSTEM_TFTPFS
110 #define CONFIGURE_FILESYSTEM_NFS
111 #define CONFIGURE_FILESYSTEM_IMFS
112
113diff --git a/RTEMS/rtems_init.c b/RTEMS/kernel/rtems_init.c
114index 82871da..82871da 100644
115--- a/RTEMS/rtems_init.c
116+++ b/RTEMS/kernel/rtems_init.c
117diff --git a/RTEMS/rtems_netconfig.c b/RTEMS/kernel/rtems_netconfig.c
118index 832a664..83d50dd 100644
119--- a/RTEMS/rtems_netconfig.c
120+++ b/RTEMS/kernel/rtems_netconfig.c
121@@ -16,58 +16,75 @@
122 #include <bsp.h>
123 #include <rtems/rtems_bsdnet.h>
124
125+#include "rtems_netconfig.h"
126+
127 extern void rtems_bsdnet_loopattach();
128 static struct rtems_bsdnet_ifconfig loopback_config = {
129 "lo0", /* name */
130- (int (*)(struct rtems_bsdnet_ifconfig *, int))rtems_bsdnet_loopattach, /* attach function */
131- NULL, /* link to next interface */
132+ (int (*)(struct rtems_bsdnet_ifconfig *, int))rtems_bsdnet_loopattach,
133+ NULL, /* last interface */
134 "127.0.0.1", /* IP address */
135 "255.0.0.0", /* IP net mask */
136 };
137
138+#define stringOf(x) #x
139+#define STRING(x) stringOf(x)
140+
141 /*
142- * The following conditionals select the network interface card.
143- *
144- * On RTEMS-pc386 targets all network drivers which support run-time
145- * probing are linked.
146- * On other targets the network interface specified by the board-support
147- * package is used.
148- * To use a different NIC for a particular application, copy this file to the
149- * application directory and make the appropriate changes.
150+ * The following configures up to 2 network interface card(s) using
151+ * settings in either configure/os/CONFIG_SITE.Common.RTEMS or in a
152+ * BSP-specific configure/os/CONFIG_SITE.Common.RTEMS-<bsp> file.
153+ * If no settings are provided, it uses the BSP's defaults instead.
154 */
155-#if defined(__i386__)
156-extern int rtems_fxp_attach (struct rtems_bsdnet_ifconfig *, int);
157-static struct rtems_bsdnet_ifconfig fxp_driver_config = {
158- "fxp1", /* name */
159- rtems_fxp_attach, /* attach function */
160- &loopback_config, /* link to next interface */
161-};
162-extern int rtems_3c509_driver_attach (struct rtems_bsdnet_ifconfig *, int);
163-static struct rtems_bsdnet_ifconfig e3c509_driver_config = {
164- "ep0", /* name */
165- rtems_3c509_driver_attach, /* attach function */
166- &fxp_driver_config, /* link to next interface */
167-};
168-#define FIRST_DRIVER_CONFIG &e3c509_driver_config
169-#else
170
171-# if defined(__PPC)
172- /*
173- * FIXME: This really belongs in the BSP
174- */
175-# ifndef RTEMS_BSP_NETWORK_DRIVER_NAME
176-# define RTEMS_BSP_NETWORK_DRIVER_NAME "dc1"
177-# endif
178-# ifndef RTEMS_BSP_NETWORK_DRIVER_ATTACH
179-# define RTEMS_BSP_NETWORK_DRIVER_ATTACH rtems_dec21140_driver_attach
180- extern int rtems_dec21140_driver_attach();
181-# endif
182-# endif
183+#if defined(RTEMS_NETWORK_DRIVER_NAME_1)
184+
185+ #if defined(RTEMS_NETWORK_DRIVER_NAME_2)
186+ static struct rtems_bsdnet_ifconfig netdriver_config_2 = {
187+ STRING(RTEMS_NETWORK_DRIVER_NAME_2),
188+ #if defined(RTEMS_NETWORK_DRIVER_ATTACH_2)
189+ RTEMS_NETWORK_DRIVER_ATTACH_2, /* specific attach function */
190+ #else
191+ RTEMS_BSP_NETWORK_DRIVER_ATTACH, /* default attach function */
192+ #endif
193+ &loopback_config, /* loopback interface */
194+ #if defined(RTEMS_NETWORK_IP4_ADDR_2)
195+ STRING(RTEMS_NETWORK_IP4_ADDR_2),
196+ #if defined(RTEMS_NETWORK_IP4_MASK_2)
197+ STRING(RTEMS_NETWORK_IP4_MASK_2),
198+ #endif
199+ #endif
200+ };
201+ #endif /* RTEMS_NETWORK_DRIVER_NAME_2 */
202+
203+ static struct rtems_bsdnet_ifconfig netdriver_config = {
204+ STRING(RTEMS_NETWORK_DRIVER_NAME_1),
205+ #if defined(RTEMS_NETWORK_DRIVER_ATTACH_1)
206+ RTEMS_NETWORK_DRIVER_ATTACH_1, /* specific attach function */
207+ #else
208+ RTEMS_BSP_NETWORK_DRIVER_ATTACH, /* default attach function */
209+ #endif
210+ #if defined(RTEMS_NETWORK_DRIVER_NAME_2)
211+ &netdriver_config_2, /* link to next interface */
212+ #else
213+ &loopback_config, /* loopback interface */
214+ #endif
215+ #if defined(RTEMS_NETWORK_IP4_ADDR_1)
216+ STRING(RTEMS_NETWORK_IP4_ADDR_1),
217+ #if defined(RTEMS_NETWORK_IP4_MASK_1)
218+ STRING(RTEMS_NETWORK_IP4_MASK_1),
219+ #endif
220+ #endif
221+ };
222+ #define FIRST_DRIVER_CONFIG &netdriver_config
223+
224+#else /* RTEMS_NETWORK_DRIVER_NAME_1 */
225
226+/* Use the BSP-provided standard macros */
227 static struct rtems_bsdnet_ifconfig bsp_driver_config = {
228 RTEMS_BSP_NETWORK_DRIVER_NAME, /* name */
229 RTEMS_BSP_NETWORK_DRIVER_ATTACH, /* attach function */
230- &loopback_config, /* link to next interface */
231+ &loopback_config, /* loopback interface */
232 };
233 #define FIRST_DRIVER_CONFIG &bsp_driver_config
234
235@@ -77,9 +94,7 @@ static struct rtems_bsdnet_ifconfig bsp_driver_config = {
236 * Allow configure/os/CONFIG_SITE.Common.RTEMS to provide domain name
237 */
238 #ifdef RTEMS_NETWORK_CONFIG_DNS_DOMAINNAME
239-# define XSTR(x) STR(x)
240-# define STR(x) #x
241-# define MY_DOMAINNAME XSTR(RTEMS_NETWORK_CONFIG_DNS_DOMAINNAME)
242+# define MY_DOMAINNAME STRING(RTEMS_NETWORK_CONFIG_DNS_DOMAINNAME)
243 #else
244 # define MY_DOMAINNAME NULL
245 #endif
246diff --git a/RTEMS/setBootConfigFromNVRAM.c b/RTEMS/kernel/setBootConfigFromNVRAM.c
247index 6a162c6..6a162c6 100644
248--- a/RTEMS/setBootConfigFromNVRAM.c
249+++ b/RTEMS/kernel/setBootConfigFromNVRAM.c
250diff --git a/RTEMS/ne2kpci.c b/RTEMS/ne2kpci.c
251new file mode 100644
252index 0000000..909d885
253--- /dev/null
254+++ b/RTEMS/ne2kpci.c
255@@ -0,0 +1,58 @@
256+/*************************************************************************\
257+* Copyright (c) 2015 Brookhaven Science Associates, as Operator of
258+* Brookhaven National Laboratory.
259+* EPICS BASE is distributed subject to a Software License Agreement found
260+* in file LICENSE that is included with this distribution.
261+\*************************************************************************/
262+/*
263+ * Wrapper around the ISA ne2000 driver to support detection of the PCI variant.
264+ * Can be used with the ne2k_pci device provided by QEMU.
265+ *
266+ * eg. "qemu-system-i386 ... -net nic,model=ne2k_pci"
267+ */
268+
269+#include <stdio.h>
270+#include <inttypes.h>
271+#include <bsp.h>
272+#include <rtems/pci.h>
273+#include <rtems/rtems_bsdnet.h>
274+
275+/* The plain ISA driver attach()
276+ * which doesn't (can't?) do any test to see if
277+ * the HW is really present
278+ */
279+extern int
280+rtems_ne_driver_attach (struct rtems_bsdnet_ifconfig *config, int attach);
281+
282+int
283+rtems_ne2kpci_driver_attach (struct rtems_bsdnet_ifconfig *config, int attach)
284+{
285+ uint8_t irq;
286+ uint32_t bar0;
287+ int B, D, F, ret;
288+ printk("Probing for NE2000 on PCI (aka. Realtek 8029)\n");
289+
290+ if(pci_find_device(PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8029, 0, &B, &D, &F))
291+ {
292+ printk("Not found\n");
293+ return 0;
294+ }
295+
296+ printk("Found %d:%d.%d\n", B, D, F);
297+
298+ ret = pci_read_config_dword(B, D, F, PCI_BASE_ADDRESS_0, &bar0);
299+ ret|= pci_read_config_byte(B, D, F, PCI_INTERRUPT_LINE, &irq);
300+
301+ if(ret || (bar0&PCI_BASE_ADDRESS_SPACE)!=PCI_BASE_ADDRESS_SPACE_IO)
302+ {
303+ printk("Failed reading card config\n");
304+ return 0;
305+ }
306+
307+ config->irno = irq;
308+ config->port = bar0&PCI_BASE_ADDRESS_IO_MASK;
309+
310+ printk("Using port=0x%x irq=%u\n", (unsigned)config->port, config->irno);
311+
312+ return rtems_ne_driver_attach(config, attach);
313+}
314diff --git a/RTEMS/posix/epicsMakeMemFs.pl b/RTEMS/posix/epicsMakeMemFs.pl
315new file mode 100644
316index 0000000..a97074e
317--- /dev/null
318+++ b/RTEMS/posix/epicsMakeMemFs.pl
319@@ -0,0 +1,83 @@
320+#!/usr/bin/env perl
321+#
322+
323+use File::Basename;
324+
325+use strict;
326+
327+my $outfile = shift;
328+my $varname = shift;
329+
330+open(my $DST, '>', $outfile) or die "Failed to open $outfile";
331+
332+print $DST <<EOF;
333+#include <epicsMemFs.h>
334+EOF
335+
336+my $N = 0;
337+
338+for my $fname (@ARGV) {
339+ print "<- $fname\n";
340+ my $realfname = $fname;
341+
342+ # strip leading "../" "./" or "/"
343+ while ($fname =~ /^\.*\/(.*)$/) { $fname = $1; }
344+
345+ my $file = basename($fname);
346+ my @dirs = split('/', dirname($fname));
347+
348+ print $DST "/* begin $realfname */\nstatic const char * const file_${N}_dir[] = {";
349+ for my $dpart (@dirs) {
350+ print $DST "\"$dpart\", ";
351+ }
352+ print $DST "NULL};\nstatic const char file_${N}_data[] = {\n ";
353+
354+ open(my $SRC, '<', $realfname) or die "Failed to open $realfname";
355+ binmode($SRC);
356+
357+ my $buf;
358+ my $total = 0;
359+ while (my $num = read($SRC, $buf, 32)) {
360+ if($total != 0) {
361+ print $DST ",\n ";
362+ }
363+ $total += $num;
364+ my $out = join(",",map(ord,split(//,$buf)));
365+ print $DST "$out";
366+ }
367+
368+ close($SRC);
369+
370+ print $DST <<EOF;
371+
372+};
373+static const epicsMemFile file_${N} = {
374+ file_${N}_dir,
375+ \"$file\",
376+ file_${N}_data,
377+ $total
378+};
379+/* end $realfname */
380+EOF
381+ $N = $N + 1;
382+}
383+
384+print $DST <<EOF;
385+static const epicsMemFile* files[] = {
386+EOF
387+
388+$N = $N - 1;
389+
390+for my $i (0..${N}) {
391+ print $DST " &file_${i},";
392+}
393+
394+print $DST <<EOF;
395+ NULL
396+};
397+static
398+const epicsMemFS ${varname}_image = {&files[0]};
399+const epicsMemFS * $varname = &${varname}_image;
400+EOF
401+
402+close($DST);
403diff --git a/RTEMS/posix/epicsMemFs.c b/RTEMS/posix/epicsMemFs.c
404new file mode 100644
405index 0000000..4689d21
406--- /dev/null
407+++ b/RTEMS/posix/epicsMemFs.c
408@@ -0,0 +1,110 @@
409+/*************************************************************************\
410+* Copyright (c) 2014 Brookhaven National Laboratory.
411+* EPICS BASE is distributed subject to a Software License Agreement found
412+* in file LICENSE that is included with this distribution.
413+\*************************************************************************/
414+
415+#include <stdlib.h>
416+#include <stdio.h>
417+#include <errno.h>
418+
419+#include <unistd.h>
420+#include <sys/stat.h>
421+#include <sys/types.h>
422+#include <fcntl.h>
423+
424+#include "epicsMemFs.h"
425+
426+#ifndef PATH_MAX
427+# define PATH_MAX 100
428+#endif
429+
430+int epicsMemFsLoad(const epicsMemFS *fs)
431+{
432+ char initdir[PATH_MAX];
433+ const epicsMemFile * const *fileptr = fs->files;
434+
435+ if(getcwd(initdir, sizeof(initdir)-1)==NULL) {
436+ perror("getcwd");
437+ return errno;
438+ }
439+ initdir[sizeof(initdir)-1] = '\0';
440+
441+ for(;*fileptr; fileptr++) {
442+ const epicsMemFile *curfile = *fileptr;
443+ int fd;
444+ ssize_t ret;
445+ size_t sofar;
446+ const char * const *dir = curfile->directory;
447+ /* jump back to the root each time,
448+ * slow but simple.
449+ */
450+ if(chdir(initdir)) {
451+ perror("chdir");
452+ return errno;
453+ }
454+
455+ printf("-> /");
456+
457+ /* traverse directory tree, creating as necessary */
458+ for(;*dir; dir++) {
459+ int ret;
460+ if(**dir=='.') continue; /* ignore '.' and '..' */
461+ printf("%s/", *dir);
462+ ret = chdir(*dir);
463+ if(ret==-1 && errno==ENOENT) {
464+ /* this directory doesn't exist */
465+ if(mkdir(*dir,0744)==-1) {
466+ printf("\n");
467+ perror("mkdir");
468+ return errno;
469+ }
470+ if(chdir(*dir)==-1) {
471+ printf("\n");
472+ perror("chdir2");
473+ return errno;
474+ }
475+ } else if(ret==-1) {
476+ printf("\n");
477+ perror("chdir1");
478+ return errno;
479+ }
480+ }
481+
482+ /* no file name creates an empty directory */
483+ if(!curfile->name) {
484+ printf("\n");
485+ continue;
486+ }
487+ printf("%s", curfile->name);
488+
489+ /* create or overwrite */
490+ fd = open(curfile->name, O_WRONLY|O_CREAT|O_TRUNC, 0644);
491+
492+ if(fd==-1) {
493+ printf("\n");
494+ perror("open");
495+ return errno;
496+ }
497+
498+ sofar = 0;
499+
500+ while(sofar<curfile->size) {
501+ ret = write(fd, curfile->data+sofar, curfile->size-sofar);
502+ if(ret<=0) {
503+ printf("\n");
504+ perror("write");
505+ return errno;
506+ }
507+ sofar += ret;
508+ }
509+
510+ close(fd);
511+ printf(" - ok\n");
512+ }
513+
514+ if(chdir(initdir))
515+ perror("chdir");
516+
517+ return 0;
518+}
519diff --git a/RTEMS/posix/epicsMemFs.h b/RTEMS/posix/epicsMemFs.h
520new file mode 100644
521index 0000000..c57f4d7
522--- /dev/null
523+++ b/RTEMS/posix/epicsMemFs.h
524@@ -0,0 +1,24 @@
525+/*************************************************************************\
526+* Copyright (c) 2014 Brookhaven National Laboratory.
527+* EPICS BASE is distributed subject to a Software License Agreement found
528+* in file LICENSE that is included with this distribution.
529+\*************************************************************************/
530+#ifndef EPICSMEMFS_H
531+#define EPICSMEMFS_H
532+
533+#include <stdlib.h>
534+
535+typedef struct {
536+ const char * const *directory; /* NULL terminated list of directories */
537+ const char *name; /* file name */
538+ const char *data; /* file contents */
539+ size_t size; /* size of file contents in bytes */
540+} epicsMemFile;
541+
542+typedef struct {
543+ const epicsMemFile * const *files;
544+} epicsMemFS;
545+
546+int epicsMemFsLoad(const epicsMemFS *fs);
547+
548+#endif // EPICSMEMFS_H
549diff --git a/RTEMS/posix/epicsRtemsInitHookPost.c b/RTEMS/posix/epicsRtemsInitHookPost.c
550new file mode 100644
551index 0000000..9d8ef65
552--- /dev/null
553+++ b/RTEMS/posix/epicsRtemsInitHookPost.c
554@@ -0,0 +1,23 @@
555+/*************************************************************************\
556+* Copyright (c) 2006 The University of Chicago, as Operator of Argonne
557+* National Laboratory.
558+* EPICS BASE Versions 3.13.7
559+* and higher are distributed subject to a Software License Agreement found
560+* in file LICENSE that is included with this distribution.
561+\*************************************************************************/
562+
563+/*
564+ * Dummy version -- use if application does not provide its own version
565+ */
566+#include "epicsRtemsInitHooks.h"
567+
568+int
569+epicsRtemsInitPostSetBootConfigFromNVRAM(struct rtems_bsdnet_config *config)
570+{
571+ return 0;
572+}
573+
574+
575+
576+void bootpFallbackFromNVRAM(void) __attribute__((weak));
577+void bootpFallbackFromNVRAM(void) {}
578diff --git a/RTEMS/posix/epicsRtemsInitHooks.h b/RTEMS/posix/epicsRtemsInitHooks.h
579new file mode 100644
580index 0000000..4313f19
581--- /dev/null
582+++ b/RTEMS/posix/epicsRtemsInitHooks.h
583@@ -0,0 +1,25 @@
584+/*************************************************************************\
585+* Copyright (c) 2006 The University of Chicago, as Operator of Argonne
586+* National Laboratory.
587+* EPICS BASE Versions 3.13.7
588+* and higher are distributed subject to a Software License Agreement found
589+* in file LICENSE that is included with this distribution.
590+\*************************************************************************/
591+
592+/*
593+ * Hooks into RTEMS startup code
594+ */
595+#include <bsp.h>
596+#include <rtems/rtems_bsdnet.h>
597+
598+extern char *env_nfsServer;
599+extern char *env_nfsPath;
600+extern char *env_nfsMountPoint;
601+
602+/*
603+ * Return 0 for success, non-zero for failure (will cause panic)
604+ */
605+int epicsRtemsInitPreSetBootConfigFromNVRAM(struct rtems_bsdnet_config *config);
606+int epicsRtemsInitPostSetBootConfigFromNVRAM(struct rtems_bsdnet_config *config);
607+/* Return 0 if local file system was setup, or non-zero (will fall back to network */
608+int epicsRtemsMountLocalFilesystem(char **argv);
609diff --git a/RTEMS/posix/rtems_config.c b/RTEMS/posix/rtems_config.c
610new file mode 100644
611index 0000000..8eb71eb
612--- /dev/null
613+++ b/RTEMS/posix/rtems_config.c
614@@ -0,0 +1,88 @@
615+/*************************************************************************\
616+* Copyright (c) 2002 The University of Saskatchewan
617+* Copyright (c) 2017 Fritz-Haber-Institut der Max-Planck-Gesellschaft
618+* EPICS BASE is distributed subject to a Software License Agreement found
619+* in file LICENSE that is included with this distribution.
620+\*************************************************************************/
621+/*
622+ * RTEMS configuration for EPICS
623+ * Author: W. Eric Norum
624+ * Heinz Junkes
625+ *
626+ * Version for RTEMS-5 and higher
627+ */
628+
629+#include <rtems.h>
630+
631+/*
632+ ***********************************************************************
633+ * RTEMS CONFIGURATION *
634+ ***********************************************************************
635+ */
636+
637+extern void *POSIX_Init(void *argument);
638+
639+#define CONFIGURE_POSIX_INIT_THREAD_TABLE
640+// Entry Point defaults to POSIX_Init
641+/*
642+ * nfs is using rtems tasks
643+ */
644+#define CONFIGURE_MAXIMUM_TASKS 5
645+#define CONFIGURE_MAXIMUM_MESSAGE_QUEUES 5
646+#define CONFIGURE_MAXIMUM_SEMAPHORES 5
647+#define CONFIGURE_MAXIMUM_EVENTS 5
648+
649+#define CONFIGURE_MAXIMUM_POSIX_MUTEXES 500
650+#define CONFIGURE_MAXIMUM_POSIX_THREADS 200
651+#define CONFIGURE_MAXIMUM_POSIX_KEYS 200
652+#define CONFIGURE_MAXIMUM_POSIX_KEY_VALUE_PAIRS 200
653+#define CONFIGURE_MAXIMUM_POSIX_SPINLOCKS 100
654+#define CONFIGURE_MAXIMUM_POSIX_SEMAPHORES 300
655+#define CONFIGURE_MAXIMUM_POSIX_TIMERS 100
656+#define CONFIGURE_MAXIMUM_POSIX_MESSAGE_QUEUES 200
657+#define CONFIGURE_MAXIMUM_POSIX_CONDITION_VARIABLES 400
658+
659+#define CONFIGURE_UNIFIED_WORK_AREAS
660+
661+#define CONFIGURE_MAXIMUM_PERIODS 5
662+#define CONFIGURE_MICROSECONDS_PER_TICK 10000
663+#define CONFIGURE_MALLOC_STATISTICS 1
664+/* MINIMUM_STACK_SIZE == 8K */
665+#define CONFIGURE_EXTRA_TASK_STACKS (4000 * RTEMS_MINIMUM_STACK_SIZE)
666+
667+#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
668+#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
669+
670+#define CONFIGURE_FILESYSTEM_DEVFS
671+#define CONFIGURE_FILESYSTEM_TFTPFS
672+#define CONFIGURE_FILESYSTEM_NFS
673+#define CONFIGURE_FILESYSTEM_IMFS
674+#define CONFIGURE_USE_IMFS_AS_BASE_FILESYSTEM
675+#define CONFIGURE_LIBIO_MAXIMUM_FILE_DESCRIPTORS 150
676+
677+#define CONFIGURE_MAXIMUM_NFS_MOUNTS 3
678+#define CONFIGURE_MAXIMUM_USER_EXTENSIONS 5
679+
680+#define CONFIGURE_POSIX_INIT_THREAD_STACK_SIZE (64*1024)
681+
682+#define CONFIGURE_MAXIMUM_DRIVERS 8
683+
684+//#define CONFIGURE_INITIAL_EXTENSIONS { .fatal = fatal_extension }
685+
686+#define CONFIGURE_INIT
687+
688+
689+/*
690+ * This should be made BSP dependent, not CPU dependent but I know of no
691+ * appropriate conditionals to use.
692+ * The new general time support makes including the RTC driver less important.
693+ */
694+#if !defined(mpc604) && !defined(__mc68040__) && !defined(__mcf5200__) && \
695+ !defined(mpc7455) && !defined(__arm__) && !defined(__nios2__)
696+ /* don't have RTC code */
697+#define CONFIGURE_APPLICATION_NEEDS_RTC_DRIVER
698+#endif
699+
700+
701+#include <bsp.h>
702+#include <rtems/confdefs.h>
703diff --git a/RTEMS/posix/rtems_init.c b/RTEMS/posix/rtems_init.c
704new file mode 100644
705index 0000000..a1904e7
706--- /dev/null
707+++ b/RTEMS/posix/rtems_init.c
708@@ -0,0 +1,796 @@
709+/*************************************************************************\
710+* Copyright (c) 2002 The University of Saskatchewan
711+* Copyright (c) 2018 Fritz-Haber-Institut der Max-Planck-Gesellschaft
712+* EPICS BASE is distributed subject to a Software License Agreement found
713+* in file LICENSE that is included with this distribution.
714+\*************************************************************************/
715+/*
716+ * RTEMS startup task for EPICS
717+ * Author: W. Eric Norum
718+ * Heinz Junkes
719+ *
720+ * Version for RTEMS-5 and higher
721+ */
722+#include <stdio.h>
723+#include <stdlib.h>
724+#include <string.h>
725+#include <ctype.h>
726+#include <time.h>
727+#include <errno.h>
728+#include <fcntl.h>
729+#include <unistd.h>
730+#include <sys/types.h>
731+#include <sys/stat.h>
732+#include <sys/socket.h>
733+#include <netinet/in.h>
734+#include <arpa/inet.h>
735+#include <rtems.h>
736+#include <epicsVersion.h>
737+#define RTEMS_VERSION_INT \
738+ VERSION_INT(__RTEMS_MAJOR__, __RTEMS_MINOR__, __RTEMS_REVISION__, 0)
739+#include <rtems/malloc.h>
740+#include <rtems/error.h>
741+#include <rtems/stackchk.h>
742+#include <rtems/rtems_bsdnet.h>
743+#include <rtems/imfs.h>
744+#include <rtems/tftp.h>
745+#include <librtemsNfs.h>
746+#include <pthread.h>
747+#include <signal.h>
748+#include <sched.h>
749+#include <rtems/libio.h>
750+#include <sys/stat.h>
751+#include <termios.h>
752+#include <bsp.h>
753+
754+#ifdef USE_GDBSTUB
755+#include <rtems-gdb-stub.h>
756+#endif
757+
758+#include "epicsThread.h"
759+#include "epicsTime.h"
760+#include "epicsExit.h"
761+#include "envDefs.h"
762+#include "errlog.h"
763+#include "logClient.h"
764+#include "osiUnistd.h"
765+#include "iocsh.h"
766+#include "osdTime.h"
767+#include "epicsMemFs.h"
768+
769+#include "epicsRtemsInitHooks.h"
770+#include <rtems/malloc.h>
771+#include <rtems/score/heap.h>
772+#include <pthread.h>
773+#include <assert.h>
774+#define rtems_test_assert(_a) assert(_a)
775+
776+/*
777+ * Prototypes for some functions not in header files
778+ */
779+void tzset(void);
780+int fileno(FILE *);
781+int main(int argc, char **argv);
782+
783+static void
784+logReset (void)
785+{
786+ void rtems_bsp_reset_cause(char *buf, size_t capacity) __attribute__((weak));
787+ void (*fp)(char *buf, size_t capacity) = rtems_bsp_reset_cause;
788+
789+ if (fp) {
790+ char buf[80];
791+ fp(buf, sizeof buf);
792+ errlogPrintf("Startup after %s.\n", buf);
793+ }
794+ else {
795+ errlogPrintf("Startup.\n");
796+ }
797+}
798+
799+/*
800+ ***********************************************************************
801+ * FATAL ERROR REPORTING *
802+ ***********************************************************************
803+ */
804+/*
805+ * Delay for a while, then terminate
806+ */
807+static void
808+delayedPanic (const char *msg)
809+{
810+ rtems_task_wake_after (rtems_clock_get_ticks_per_second());
811+ rtems_task_wake_after (rtems_clock_get_ticks_per_second());
812+ rtems_panic (msg);
813+}
814+
815+/*
816+ * Log error and terminate
817+ */
818+void
819+LogFatal (const char *msg, ...)
820+{
821+ va_list ap;
822+
823+ va_start (ap, msg);
824+ errlogVprintf (msg, ap);
825+ va_end (ap);
826+ delayedPanic (msg);
827+}
828+
829+/*
830+ * Log RTEMS error and terminate
831+ */
832+void
833+LogRtemsFatal (const char *msg, rtems_status_code sc)
834+{
835+ errlogPrintf ("%s: %s\n", msg, rtems_status_text (sc));
836+ delayedPanic (msg);
837+}
838+
839+/*
840+ * Log network error and terminate
841+ */
842+void
843+LogNetFatal (const char *msg, int err)
844+{
845+ errlogPrintf ("%s: %d\n", msg, err);
846+ delayedPanic (msg);
847+}
848+
849+void *
850+mustMalloc(int size, const char *msg)
851+{
852+ void *p;
853+
854+ if ((p = malloc (size)) == NULL)
855+ LogFatal ("Can't allocate space for %s.\n", msg);
856+ return p;
857+}
858+
859+/*
860+ ***********************************************************************
861+ * REMOTE FILE ACCESS *
862+ ***********************************************************************
863+ */
864+#ifdef OMIT_NFS_SUPPORT
865+# include <rtems/tftp.h>
866+#endif
867+
868+const epicsMemFS *epicsRtemsFSImage __attribute__((weak));
869+const epicsMemFS *epicsRtemsFSImage = (void*)&epicsRtemsFSImage;
870+
871+/* hook to allow app specific FS setup */
872+int
873+epicsRtemsMountLocalFilesystem(char **argv) __attribute__((weak));
874+int
875+epicsRtemsMountLocalFilesystem(char **argv)
876+{
877+ if(epicsRtemsFSImage==(void*)&epicsRtemsFSImage)
878+ return -1; /* no FS image provided. */
879+ else if(epicsRtemsFSImage==NULL)
880+ return 0; /* no FS image provided, but none is needed. */
881+ else {
882+ printf("***** Using compiled in file data *****\n");
883+ if (epicsMemFsLoad(epicsRtemsFSImage) != 0) {
884+ printf("Can't unpack tar filesystem\n");
885+ return -1;
886+ } else {
887+ argv[1] = "/";
888+ return 0;
889+ }
890+ }
891+}
892+
893+static int
894+initialize_local_filesystem(char **argv)
895+{
896+ extern char _DownloadLocation[] __attribute__((weak));
897+ extern char _FlashBase[] __attribute__((weak));
898+ extern char _FlashSize[] __attribute__((weak));
899+
900+ argv[0] = rtems_bsdnet_bootp_boot_file_name;
901+ if (epicsRtemsMountLocalFilesystem(argv)==0) {
902+ return 1; /* FS setup successful */
903+ } else if (_FlashSize && (_DownloadLocation || _FlashBase)) {
904+ extern char _edata[];
905+ size_t flashIndex = _edata - _DownloadLocation;
906+ char *header = _FlashBase + flashIndex;
907+
908+ if (memcmp(header + 257, "ustar ", 8) == 0) {
909+ int fd;
910+ printf ("***** Unpack in-memory file system (IMFS) *****\n");
911+ if (rtems_tarfs_load("/", (unsigned char *)header, (size_t)_FlashSize - flashIndex) != 0) {
912+ printf("Can't unpack tar filesystem\n");
913+ return 0;
914+ }
915+ if ((fd = open(rtems_bsdnet_bootp_cmdline, 0)) >= 0) {
916+ close(fd);
917+ printf ("***** Found startup script (%s) in IMFS *****\n", rtems_bsdnet_bootp_cmdline);
918+ argv[1] = rtems_bsdnet_bootp_cmdline;
919+ return 1;
920+ }
921+ printf ("***** Startup script (%s) not in IMFS *****\n", rtems_bsdnet_bootp_cmdline);
922+ }
923+ }
924+ return 0;
925+}
926+
927+#ifndef OMIT_NFS_SUPPORT
928+int
929+nfsMount(char *uidhost, char *path, char *mntpoint)
930+{
931+ int devl = strlen(uidhost) + strlen(path) + 2;
932+ char *dev;
933+ int rval = -1;
934+
935+ if ((dev = malloc(devl)) == NULL) {
936+ printf("nfsMount: out of memory\n");
937+ return -1;
938+ }
939+ sprintf(dev, "%s:%s", uidhost, path);
940+ rval = mount_and_make_target_path (
941+ dev, mntpoint, RTEMS_FILESYSTEM_TYPE_NFS,
942+ RTEMS_FILESYSTEM_READ_WRITE, NULL );
943+ if(rval)
944+ perror("mount failed");
945+
946+ free(dev);
947+ return rval;
948+}
949+#define NFS_INIT
950+#endif
951+
952+static void
953+initialize_remote_filesystem(char **argv, int hasLocalFilesystem)
954+{
955+#ifndef OMIT_NFS_SUPPORT
956+ char *server_name = "notDefined";
957+ char *server_path = "notDefined";
958+ char *mount_point = "notDefined";
959+ char *cp;
960+ int l = 0;
961+#endif
962+
963+ printf ("***** Initializing TFTP *****\n");
964+ if(mount_and_make_target_path("BOOTP_HOST:/",
965+ "/TFTP/BOOTP_HOST",
966+ RTEMS_FILESYSTEM_TYPE_TFTPFS,
967+ RTEMS_FILESYSTEM_READ_WRITE,
968+ NULL)) {
969+ perror("mount TFTP");
970+ }
971+
972+ if(rtems_bsdnet_bootp_cmdline && strncmp("/TFTP", rtems_bsdnet_bootp_cmdline, 4)==0) {
973+ argv[1] = rtems_bsdnet_bootp_cmdline;
974+ printf("Boot from TFTP\n");
975+ return;
976+ }
977+
978+ printf ("***** Initializing NFS *****\n");
979+ NFS_INIT
980+ if (env_nfsServer && env_nfsPath && env_nfsMountPoint) {
981+ server_name = env_nfsServer;
982+ server_path = env_nfsPath;
983+ mount_point = env_nfsMountPoint;
984+ cp = mount_point;
985+ while ((cp = strchr(cp+1, '/')) != NULL) {
986+ *cp = '\0';
987+ if ((mkdir (mount_point, 0755) != 0)
988+ && (errno != EEXIST))
989+ LogFatal("Can't create directory \"%s\": %s.\n",
990+ mount_point, strerror(errno));
991+ *cp = '/';
992+ }
993+ argv[1] = rtems_bsdnet_bootp_cmdline;
994+ }
995+ else if (hasLocalFilesystem) {
996+ printf("Using Local FS\n");
997+ return;
998+ }
999+ else if (rtems_bsdnet_bootp_cmdline) {
1000+ /*
1001+ * Use first component of nvram/bootp command line pathname
1002+ * to set up initial NFS mount. A "/tftpboot/" is prepended
1003+ * if the pathname does not begin with a '/'. This allows
1004+ * NFS and TFTP to have a similar view of the remote system.
1005+ */
1006+ if (rtems_bsdnet_bootp_cmdline[0] == '/')
1007+ cp = rtems_bsdnet_bootp_cmdline + 1;
1008+ else
1009+ cp = rtems_bsdnet_bootp_cmdline;
1010+ cp = strchr(cp, '/');
1011+ if ((cp == NULL)
1012+ || ((l = cp - rtems_bsdnet_bootp_cmdline) == 0))
1013+ LogFatal("\"%s\" is not a valid command pathname.\n", rtems_bsdnet_bootp_cmdline);
1014+ cp = mustMalloc(l + 20, "NFS mount paths");
1015+ server_path = cp;
1016+ server_name = rtems_bsdnet_bootp_server_name;
1017+ if (rtems_bsdnet_bootp_cmdline[0] == '/') {
1018+ mount_point = server_path;
1019+ strncpy(mount_point, rtems_bsdnet_bootp_cmdline, l);
1020+ mount_point[l] = '\0';
1021+ argv[1] = rtems_bsdnet_bootp_cmdline;
1022+ /*
1023+ * Its probably common to embed the mount point in the server
1024+ * name so, when this is occurring, dont clobber the mount point
1025+ * by appending the first node from the command path. This allows
1026+ * the mount point to be a different path then the server's mount
1027+ * path.
1028+ *
1029+ * This allows for example a line similar to as follows the DHCP
1030+ * configuration file.
1031+ *
1032+ * server-name "159.233@192.168.0.123:/vol/vol0/bootRTEMS";
1033+ */
1034+ if ( server_name ) {
1035+ const size_t allocSize = strlen ( server_name ) + 2;
1036+ char * const pServerName = mustMalloc( allocSize,
1037+ "NFS mount paths");
1038+ char * const pServerPath = mustMalloc ( allocSize,
1039+ "NFS mount paths");
1040+ const int scanfStatus = sscanf (
1041+ server_name,
1042+ "%[^:] : / %s",
1043+ pServerName,
1044+ pServerPath + 1u );
1045+
1046+ if ( scanfStatus == 2 ) {
1047+ pServerPath[0u]= '/';
1048+ server_name = pServerName;
1049+ server_path = mount_point = pServerPath;
1050+ }
1051+ else {
1052+ free ( pServerName );
1053+ free ( pServerPath );
1054+ }
1055+ }
1056+ }
1057+ else {
1058+ char *abspath = mustMalloc(strlen(rtems_bsdnet_bootp_cmdline)+2,"Absolute command path");
1059+ strcpy(server_path, "/tftpboot/");
1060+ mount_point = server_path + strlen(server_path);
1061+ strncpy(mount_point, rtems_bsdnet_bootp_cmdline, l);
1062+ mount_point[l] = '\0';
1063+ mount_point--;
1064+ strcpy(abspath, "/");
1065+ strcat(abspath, rtems_bsdnet_bootp_cmdline);
1066+ argv[1] = abspath;
1067+ }
1068+ }
1069+ if(server_name && server_path && mount_point) {
1070+ int ret = nfsMount(server_name, server_path, mount_point);
1071+ printf("nfsMount(\"%s\", \"%s\", \"%s\") -> %d\n", server_name, server_path, mount_point, ret);
1072+
1073+ } else if (!hasLocalFilesystem) {
1074+ char *path;
1075+ int pathsize = 200;
1076+ int l;
1077+
1078+ printf("No NFS configuration found. Falling back to TFTP\n");
1079+
1080+ path = mustMalloc(pathsize, "Command path name ");
1081+ strcpy (path, "/TFTP/BOOTP_HOST/epics/");
1082+ l = strlen (path);
1083+ if (gethostname (&path[l], pathsize - l - 10) || (path[l] == '\0'))
1084+ {
1085+ LogFatal ("Can't get host name");
1086+ }
1087+ strcat (path, "/st.cmd");
1088+ argv[1] = path;
1089+
1090+ } else {
1091+ printf("Local FS\n");
1092+ }
1093+}
1094+
1095+static
1096+char rtems_etc_hosts[] = "127.0.0.1 localhost\n";
1097+
1098+/* If it doesn't already exist, create /etc/hosts with an entry for 'localhost' */
1099+static
1100+void fixup_hosts(void)
1101+{
1102+ FILE *fp;
1103+ int ret;
1104+ struct stat STAT;
1105+
1106+ ret=stat("/etc/hosts", &STAT);
1107+ if(ret==0)
1108+ {
1109+ return; /* already exists, assume file */
1110+ } else if(errno!=ENOENT) {
1111+ perror("error: fixup_hosts stat /etc/hosts");
1112+ return;
1113+ }
1114+ ret = mkdir("/etc", 0775);
1115+ if(ret!=0 && errno!=EEXIST)
1116+ {
1117+ perror("error: fixup_hosts create /etc");
1118+ return;
1119+ }
1120+
1121+ if((fp=fopen("/etc/hosts", "w"))==NULL)
1122+ {
1123+ perror("error: fixup_hosts create /etc/hosts");
1124+ }
1125+
1126+ if(fwrite(rtems_etc_hosts, 1, sizeof(rtems_etc_hosts)-1, fp)!=sizeof(rtems_etc_hosts)-1)
1127+ {
1128+ perror("error: failed to write /etc/hosts");
1129+ }
1130+ fclose(fp);
1131+}
1132+
1133+/*
1134+ * Get to the startup script directory
1135+ * The TFTP filesystem requires a trailing '/' on chdir arguments.
1136+ */
1137+static void
1138+set_directory (const char *commandline)
1139+{
1140+ const char *cp;
1141+ char *directoryPath;
1142+ int l;
1143+
1144+ cp = strrchr(commandline, '/');
1145+ if (cp == NULL) {
1146+ l = 0;
1147+ cp = "/";
1148+ }
1149+ else {
1150+ l = cp - commandline;
1151+ cp = commandline;
1152+ }
1153+ directoryPath = mustMalloc(l + 2, "Command path directory ");
1154+ strncpy(directoryPath, cp, l);
1155+ directoryPath[l] = '/';
1156+ directoryPath[l+1] = '\0';
1157+ if (chdir (directoryPath) < 0)
1158+ LogFatal ("Can't set initial directory(%s): %s\n", directoryPath, strerror(errno));
1159+ else
1160+ free(directoryPath);
1161+}
1162+
1163+/*
1164+ ***********************************************************************
1165+ * RTEMS/EPICS COMMANDS *
1166+ ***********************************************************************
1167+ */
1168+/*
1169+ * RTEMS status
1170+ */
1171+static void
1172+rtems_netstat (unsigned int level)
1173+{
1174+ rtems_bsdnet_show_if_stats ();
1175+ rtems_bsdnet_show_mbuf_stats ();
1176+ if (level >= 1) {
1177+ rtems_bsdnet_show_inet_routes ();
1178+ }
1179+ if (level >= 2) {
1180+ rtems_bsdnet_show_ip_stats ();
1181+ rtems_bsdnet_show_icmp_stats ();
1182+ rtems_bsdnet_show_udp_stats ();
1183+ rtems_bsdnet_show_tcp_stats ();
1184+ }
1185+}
1186+
1187+static const iocshArg netStatArg0 = { "level",iocshArgInt};
1188+static const iocshArg * const netStatArgs[1] = {&netStatArg0};
1189+static const iocshFuncDef netStatFuncDef = {"netstat",1,netStatArgs};
1190+static void netStatCallFunc(const iocshArgBuf *args)
1191+{
1192+ rtems_netstat(args[0].ival);
1193+}
1194+
1195+static const iocshFuncDef heapSpaceFuncDef = {"heapSpace",0,NULL};
1196+static void heapSpaceCallFunc(const iocshArgBuf *args)
1197+{
1198+ Heap_Information_block info;
1199+ double x;
1200+
1201+ malloc_info (&info);
1202+ x = info.Stats.size - (unsigned long)
1203+ (info.Stats.lifetime_allocated - info.Stats.lifetime_freed);
1204+ if (x >= 1024*1024)
1205+ printf("Heap space: %.1f MB\n", x / (1024 * 1024));
1206+ else
1207+ printf("Heap space: %.1f kB\n", x / 1024);
1208+}
1209+
1210+#ifndef OMIT_NFS_SUPPORT
1211+static const iocshArg nfsMountArg0 = { "[uid.gid@]host",iocshArgString};
1212+static const iocshArg nfsMountArg1 = { "server path",iocshArgString};
1213+static const iocshArg nfsMountArg2 = { "mount point",iocshArgString};
1214+static const iocshArg * const nfsMountArgs[3] = {&nfsMountArg0,&nfsMountArg1,
1215+ &nfsMountArg2};
1216+static const iocshFuncDef nfsMountFuncDef = {"nfsMount",3,nfsMountArgs};
1217+static void nfsMountCallFunc(const iocshArgBuf *args)
1218+{
1219+ char *cp = args[2].sval;
1220+ while ((cp = strchr(cp+1, '/')) != NULL) {
1221+ *cp = '\0';
1222+ if ((mkdir (args[2].sval, 0755) != 0) && (errno != EEXIST)) {
1223+ printf("Can't create directory \"%s\": %s.\n",
1224+ args[2].sval, strerror(errno));
1225+ return;
1226+ }
1227+ *cp = '/';
1228+ }
1229+ nfsMount(args[0].sval, args[1].sval, args[2].sval);
1230+}
1231+#endif
1232+
1233+#ifdef USE_GDBSTUB
1234+static const iocshArg gdbstartArg0 = { "prio",iocshArgInt};
1235+static const iocshArg gdbstartArg1 = { "ttyName",iocshArgString};
1236+static const iocshArg * const gdbstartArgs[3] = {&gdbstartArg0,&gdbstartArg1};
1237+static const iocshFuncDef gdbstartFuncDef = {"rtems_gdb_start",2,gdbstartArgs};
1238+static void gdbstartCallFunc(const iocshArgBuf *args)
1239+{
1240+ rtems_gdb_start(args[0].ival, args->sval);
1241+}
1242+
1243+static const iocshArg gdbstopArg0 = { "override",iocshArgInt};
1244+static const iocshArg * const gdbstopArgs[3] = {&gdbstopArg0};
1245+static const iocshFuncDef gdbstopFuncDef = {"rtems_gdb_stop",1,gdbstopArgs};
1246+static void gdbstopCallFunc(const iocshArgBuf *args)
1247+{
1248+ rtems_gdb_stop(args[0].ival);
1249+}
1250+#endif /* USE_GDBSTUB */
1251+
1252+/*
1253+ * Register RTEMS-specific commands
1254+ */
1255+static void iocshRegisterRTEMS (void)
1256+{
1257+ iocshRegister(&netStatFuncDef, netStatCallFunc);
1258+ iocshRegister(&heapSpaceFuncDef, heapSpaceCallFunc);
1259+#ifndef OMIT_NFS_SUPPORT
1260+ iocshRegister(&nfsMountFuncDef, nfsMountCallFunc);
1261+#endif
1262+#ifdef USE_GDBSTUB
1263+ iocshRegister(&gdbstartFuncDef, gdbstartCallFunc);
1264+ iocshRegister(&gdbstopFuncDef, gdbstopCallFunc);
1265+#endif
1266+}
1267+
1268+/*
1269+ * Set up the console serial line (no handshaking)
1270+ */
1271+static void
1272+initConsole (void)
1273+{
1274+ struct termios t;
1275+
1276+ if (tcgetattr (fileno (stdin), &t) < 0) {
1277+ printf ("tcgetattr failed: %s\n", strerror (errno));
1278+ return;
1279+ }
1280+ t.c_iflag &= ~(IXOFF | IXON | IXANY);
1281+ if (tcsetattr (fileno (stdin), TCSANOW, &t) < 0) {
1282+ printf ("tcsetattr failed: %s\n", strerror (errno));
1283+ return;
1284+ }
1285+}
1286+
1287+/*
1288+ * Hook to ensure that BSP cleanup code gets run on exit
1289+ */
1290+static void
1291+exitHandler(void)
1292+{
1293+ rtems_shutdown_executive(0);
1294+}
1295+
1296+extern char *env_rtems_gdb_stub;
1297+extern int epics_initialized_environment;
1298+extern void setBootConfigFromNVRAM(void);
1299+extern void bootpFallbackFromNVRAM(void);
1300+
1301+static void *
1302+rtemsEpicsStartUp(void *arg)
1303+{
1304+ int result;
1305+ char *argv[3] = { NULL, NULL, NULL };
1306+ char *cp;
1307+ rtems_status_code sc;
1308+ rtems_time_of_day now;
1309+
1310+ /*
1311+ * Explain why we're here, calls errlogPrintf -> epicsThreadInit etc.
1312+ */
1313+
1314+ errlogSetConsole(stdout); // prevent mixup of stdout/stderr
1315+ logReset();
1316+
1317+ /*
1318+ * Architecture-specific hooks
1319+ */
1320+ if (epicsRtemsInitPreSetBootConfigFromNVRAM(&rtems_bsdnet_config) != 0)
1321+ delayedPanic("epicsRtemsInitPreSetBootConfigFromNVRAM");
1322+ epics_initialized_environment = 0;
1323+ setBootConfigFromNVRAM();
1324+ if (epicsRtemsInitPostSetBootConfigFromNVRAM(&rtems_bsdnet_config) != 0)
1325+ delayedPanic("epicsRtemsInitPostSetBootConfigFromNVRAM");
1326+
1327+ /*
1328+ * Create a reasonable environment
1329+ */
1330+ initConsole ();
1331+ putenv ("TERM=xterm");
1332+ putenv ("IOCSH_HISTSIZE=20");
1333+
1334+ if(!epics_initialized_environment) {
1335+ fprintf(stdout, "BSP doesn't implement non-volatile memory.\n");
1336+ }
1337+
1338+ /*
1339+ * Display some OS information
1340+ */
1341+ printf("\n***** RTEMS Version: %s *****\n",
1342+ rtems_get_version_string());
1343+
1344+ /*
1345+ * Start network
1346+ */
1347+ if ((cp = getenv("EPICS_TS_NTP_INET")) != NULL)
1348+ rtems_bsdnet_config.ntp_server[0] = cp;
1349+ if (rtems_bsdnet_config.network_task_priority == 0)
1350+ {
1351+ unsigned int p;
1352+ if (epicsThreadHighestPriorityLevelBelow(epicsThreadPriorityScanLow, &p)
1353+ == epicsThreadBooleanStatusSuccess)
1354+ {
1355+
1356+ /* This is an rtems task, so use the rtems task priority */
1357+ rtems_bsdnet_config.network_task_priority =
1358+ epicsThreadGetPosixMinPriorityValue() + epicsThreadGetPosixPriorityValue(p);
1359+ /* For rtems tasks, lower number = higher priority */
1360+
1361+ }
1362+ }
1363+ printf("\n***** Initializing network *****\n");
1364+ rtems_bsdnet_initialize_network();
1365+ bootpFallbackFromNVRAM();
1366+ printf("\n***** Setting up file system *****\n");
1367+ initialize_remote_filesystem(argv, initialize_local_filesystem(argv));
1368+ fixup_hosts();
1369+
1370+ if(env_rtems_gdb_stub) {
1371+#ifdef USE_GDBSTUB
1372+ char *arg = NULL;
1373+ if(strcmp(env_rtems_gdb_stub, "yes")!=0)
1374+ arg = env_rtems_gdb_stub;
1375+ printf("Start GDB server on %s\n", arg);
1376+ rtems_gdb_start(0,arg);
1377+#else
1378+ printf("GDB server support not enabled.\n");
1379+#endif
1380+ }
1381+ /*
1382+ * More environment: iocsh prompt and hostname
1383+ */
1384+ {
1385+ char hostname[1024];
1386+ gethostname(hostname, 1023);
1387+ char *cp = mustMalloc(strlen(hostname)+3, "iocsh prompt");
1388+ sprintf(cp, "%s> ", hostname);
1389+ epicsEnvSet ("IOCSH_PS1", cp);
1390+ epicsEnvSet("IOC_NAME", hostname);
1391+ }
1392+
1393+ /*
1394+ * Use BSP-supplied time of day if available otherwise supply default time.
1395+ * It is very likely that other time synchronization facilities in EPICS
1396+ * will soon override this value.
1397+ */
1398+ if (rtems_clock_get_tod(&now) != RTEMS_SUCCESSFUL) {
1399+ now.year = 2012;
1400+ now.month = 4;
1401+ now.day = 14;
1402+ now.hour = 7;
1403+ now.minute = 23;
1404+ now.second = 0;
1405+ now.ticks = 0;
1406+ if ((sc = rtems_clock_set (&now)) != RTEMS_SUCCESSFUL)
1407+ printf ("***** Can't set time: %s\n", rtems_status_text (sc));
1408+ }
1409+ if (getenv("TZ") == NULL) {
1410+ const char *tzp = envGetConfigParamPtr(&EPICS_TIMEZONE);
1411+ if (tzp == NULL) {
1412+ printf("Warning -- no timezone information available -- times will be displayed as GMT.\n");
1413+ }
1414+ else {
1415+ char tz[10];
1416+ int minWest, toDst = 0, fromDst = 0;
1417+ if(sscanf(tzp, "%9[^:]::%d:%d:%d", tz, &minWest, &toDst, &fromDst) < 2) {
1418+ printf("Warning: EPICS_TIMEZONE (%s) unrecognizable -- times will be displayed as GMT.\n", tzp);
1419+ }
1420+ else {
1421+ char posixTzBuf[40];
1422+ char *p = posixTzBuf;
1423+ p += sprintf(p, "%cST%d:%.2d", tz[0], minWest/60, minWest%60);
1424+ if (toDst != fromDst)
1425+ p += sprintf(p, "%cDT", tz[0]);
1426+ epicsEnvSet("TZ", posixTzBuf);
1427+ }
1428+ }
1429+ }
1430+ tzset();
1431+ /* osdTimeRegister() was called during C++ initialization */
1432+ rtems_netstat(0);
1433+ /*
1434+ * Run the EPICS startup script
1435+ */
1436+ printf ("***** Preparing EPICS application *****\n");
1437+ iocshRegisterRTEMS ();
1438+ set_directory (argv[1]);
1439+ epicsEnvSet ("IOC_STARTUP_SCRIPT", argv[1]);
1440+ atexit(exitHandler);
1441+ errlogFlush();
1442+ printf ("***** Starting EPICS application *****\n");
1443+ result = main ((sizeof argv / sizeof argv[0]) - 1, argv);
1444+ printf ("***** IOC application terminating *****\n");
1445+ epicsThreadSleep(1.0);
1446+ epicsExit(result);
1447+ return NULL;
1448+}
1449+
1450+/*
1451+ * RTEMS Startup task
1452+ */
1453+void *
1454+POSIX_Init (void *argument)
1455+{
1456+ struct sched_param schedParam;
1457+ /*
1458+ * Override RTEMS Posix configuration, starts with posix prio 2
1459+ */
1460+
1461+ double maxPriority,minPriority,slope,posixPrio;
1462+ maxPriority = (double)sched_get_priority_max(SCHED_FIFO);
1463+ minPriority = (double)sched_get_priority_min(SCHED_FIFO);
1464+ slope = (maxPriority - minPriority)/100.0;
1465+ posixPrio = (double)epicsThreadPriorityIocsh * slope + minPriority;
1466+ schedParam.sched_priority = (int) posixPrio;
1467+ int s = pthread_setschedparam(pthread_self(), SCHED_FIFO, &schedParam);
1468+ if(s) delayedPanic ("Panix pthread_attr_setschedparam in Init ...");
1469+
1470+ rtemsMainInit(epicsThreadPriorityIocsh);
1471+ /* try to retrieve pthreadInfo from global list for _main_ */
1472+ rtemsEpicsStartUp(NULL);
1473+ return 0;
1474+}
1475+
1476+#if defined(QEMU_FIXUPS)
1477+/* Override some hooks (weak symbols)
1478+ * if BSP defaults aren't configured for running tests.
1479+ */
1480+
1481+
1482+/* Ensure that stdio goes to serial (so it can be captured) */
1483+#if defined(__i386__) && !USE_COM1_AS_CONSOLE
1484+#include <uart.h>
1485+extern int BSPPrintkPort;
1486+void bsp_predriver_hook(void)
1487+{
1488+ BSPConsolePort = BSP_CONSOLE_PORT_COM1;
1489+ BSPPrintkPort = BSP_CONSOLE_PORT_COM1;
1490+}
1491+#endif
1492+
1493+/* reboot immediately when done. */
1494+#if defined(__i386__) && BSP_PRESS_KEY_FOR_RESET
1495+void bsp_cleanup(void)
1496+{
1497+ void bsp_reset();
1498+ bsp_reset();
1499+}
1500+#endif
1501+
1502+#endif /* QEMU_FIXUPS */
1503+
1504+int cexpdebug __attribute__((weak));
1505diff --git a/RTEMS/posix/rtems_netconfig.c b/RTEMS/posix/rtems_netconfig.c
1506new file mode 100644
1507index 0000000..86ed527
1508--- /dev/null
1509+++ b/RTEMS/posix/rtems_netconfig.c
1510@@ -0,0 +1,128 @@
1511+/*************************************************************************\
1512+* Copyright (c) 2002 The University of Saskatchewan
1513+* Copyright (c) 2017 Fritz-Haber-Institut der Max-Planck-Gesellschaft
1514+* EPICS BASE is distributed subject to a Software License Agreement found
1515+* in file LICENSE that is included with this distribution.
1516+\*************************************************************************/
1517+/*
1518+ * RTEMS network configuration for EPICS
1519+ * Author: W. Eric Norum
1520+ * Heinz Junkes
1521+ *
1522+ * Version for RTEMS-5
1523+ *
1524+ * This file can be copied to an application source dirctory
1525+ * and modified to override the values shown below.
1526+ */
1527+#include <stdio.h>
1528+#include <bsp.h>
1529+#include <rtems/rtems_bsdnet.h>
1530+
1531+#include "rtems_netconfig.h"
1532+
1533+#define stringOf(x) #x
1534+#define STRING(x) stringOf(x)
1535+
1536+/*
1537+ * The following configures up to 2 network interface card(s) using
1538+ * settings in either configure/os/CONFIG_SITE.Common.RTEMS or in a
1539+ * BSP-specific configure/os/CONFIG_SITE.Common.RTEMS-<bsp> file.
1540+ * If no settings are provided, it uses the BSP's defaults instead.
1541+ */
1542+
1543+#if defined(RTEMS_NETWORK_DRIVER_NAME_1)
1544+
1545+ #if defined(RTEMS_NETWORK_DRIVER_NAME_2)
1546+ static struct rtems_bsdnet_ifconfig netdriver_config_2 = {
1547+ STRING(RTEMS_NETWORK_DRIVER_NAME_2),
1548+ #if defined(RTEMS_NETWORK_DRIVER_ATTACH_2)
1549+ RTEMS_NETWORK_DRIVER_ATTACH_2, /* specific attach function */
1550+ #else
1551+ RTEMS_BSP_NETWORK_DRIVER_ATTACH, /* default attach function */
1552+ #endif
1553+ NULL, /* last interface */
1554+ #if defined(RTEMS_NETWORK_IP4_ADDR_2)
1555+ STRING(RTEMS_NETWORK_IP4_ADDR_2),
1556+ #if defined(RTEMS_NETWORK_IP4_MASK_2)
1557+ STRING(RTEMS_NETWORK_IP4_MASK_2),
1558+ #endif
1559+ #endif
1560+ };
1561+ #endif /* RTEMS_NETWORK_DRIVER_NAME_2 */
1562+
1563+ static struct rtems_bsdnet_ifconfig netdriver_config = {
1564+ STRING(RTEMS_NETWORK_DRIVER_NAME_1),
1565+ #if defined(RTEMS_NETWORK_DRIVER_ATTACH_1)
1566+ RTEMS_NETWORK_DRIVER_ATTACH_1, /* specific attach function */
1567+ #else
1568+ RTEMS_BSP_NETWORK_DRIVER_ATTACH, /* default attach function */
1569+ #endif
1570+ #if defined(RTEMS_NETWORK_DRIVER_NAME_2)
1571+ &netdriver_config_2, /* link to next interface */
1572+ #else
1573+ NULL, /* last interface */
1574+ #endif
1575+ #if defined(RTEMS_NETWORK_IP4_ADDR_1)
1576+ STRING(RTEMS_NETWORK_IP4_ADDR_1),
1577+ #if defined(RTEMS_NETWORK_IP4_MASK_1)
1578+ STRING(RTEMS_NETWORK_IP4_MASK_1),
1579+ #endif
1580+ #endif
1581+ };
1582+ #define FIRST_DRIVER_CONFIG &netdriver_config
1583+
1584+#else /* RTEMS_NETWORK_DRIVER_NAME_1 */
1585+
1586+/* Use the BSP-provided standard macros */
1587+static struct rtems_bsdnet_ifconfig bsp_driver_config = {
1588+ RTEMS_BSP_NETWORK_DRIVER_NAME, /* name */
1589+ RTEMS_BSP_NETWORK_DRIVER_ATTACH, /* attach function */
1590+ NULL, /* last interface */
1591+};
1592+#define FIRST_DRIVER_CONFIG &bsp_driver_config
1593+
1594+#endif
1595+
1596+/*
1597+ * Allow configure/os/CONFIG_SITE.Common.RTEMS to provide domain name
1598+ */
1599+#ifdef RTEMS_NETWORK_CONFIG_DNS_DOMAINNAME
1600+# define MY_DOMAINNAME STRING(RTEMS_NETWORK_CONFIG_DNS_DOMAINNAME)
1601+#else
1602+# define MY_DOMAINNAME NULL
1603+#endif
1604+
1605+/*
1606+ * Allow non-BOOTP network configuration
1607+ */
1608+#ifndef MY_DO_BOOTP
1609+# define MY_DO_BOOTP rtems_bsdnet_do_bootp
1610+#endif
1611+
1612+/*
1613+ * Allow site- and BSP-specific network buffer space configuration.
1614+ * The macro values are specified in KBytes.
1615+ */
1616+#ifndef RTEMS_NETWORK_CONFIG_MBUF_SPACE
1617+# define RTEMS_NETWORK_CONFIG_MBUF_SPACE 180
1618+#endif
1619+#ifndef RTEMS_NETWORK_CONFIG_CLUSTER_SPACE
1620+# define RTEMS_NETWORK_CONFIG_CLUSTER_SPACE 350
1621+#endif
1622+
1623+/*
1624+ * Network configuration
1625+ */
1626+struct rtems_bsdnet_config rtems_bsdnet_config = {
1627+ FIRST_DRIVER_CONFIG, /* Link to next interface */
1628+ MY_DO_BOOTP, /* How to find network config */
1629+ 0, /* If 0 then the network daemons will run at a */
1630+ /* priority just less than the lowest-priority */
1631+ /* EPICS scan thread. */
1632+ /* If non-zero then the network daemons will run */
1633+ /* at this *RTEMS* priority */
1634+ RTEMS_NETWORK_CONFIG_MBUF_SPACE*1024,
1635+ RTEMS_NETWORK_CONFIG_CLUSTER_SPACE*1024,
1636+ NULL, /* Host name */
1637+ MY_DOMAINNAME, /* Domain name */
1638+};
1639diff --git a/RTEMS/posix/setBootConfigFromNVRAM.c b/RTEMS/posix/setBootConfigFromNVRAM.c
1640new file mode 100644
1641index 0000000..8a93d95
1642--- /dev/null
1643+++ b/RTEMS/posix/setBootConfigFromNVRAM.c
1644@@ -0,0 +1,458 @@
1645+/*************************************************************************\
1646+* Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne
1647+* National Laboratory.
1648+* EPICS BASE is distributed subject to a Software License Agreement found
1649+* in file LICENSE that is included with this distribution.
1650+\*************************************************************************/
1651+
1652+#include <sys/types.h>
1653+#include <sys/socket.h>
1654+#include <arpa/inet.h>
1655+#include <netinet/in.h>
1656+#include <fcntl.h>
1657+#include <unistd.h>
1658+#include <rtems/rtems_bsdnet.h>
1659+#include <bsp.h>
1660+#include <string.h>
1661+#include <ctype.h>
1662+#include <errno.h>
1663+#include <epicsStdlib.h>
1664+#include <epicsStdio.h>
1665+#include <epicsString.h>
1666+#include <envDefs.h>
1667+
1668+#include <osiSock.h>
1669+
1670+char *env_nfsServer;
1671+char *env_nfsPath;
1672+char *env_nfsMountPoint;
1673+int epics_initialized_environment;
1674+char *env_rtems_gdb_stub = NULL;
1675+
1676+/*
1677+ * Split argument string of form nfs_server:nfs_export:<path>
1678+ * The nfs_export component will be used as:
1679+ * - the path to the directory exported from the NFS server
1680+ * - the local mount point
1681+ * - a prefix of <path>
1682+ * For example, the argument string:
1683+ * romeo:/export/users:smith/ioc/iocexample/st.cmd
1684+ * would:
1685+ * - mount /export/users from NFS server romeo on /export/users
1686+ * - chdir to /export/users/smith/ioc/iocexample
1687+ * - read commands from st.cmd
1688+ */
1689+static void
1690+splitRtemsBsdnetBootpCmdline(void)
1691+{
1692+ char *cp1, *cp2, *cp3;
1693+
1694+ if ((cp1 = rtems_bsdnet_bootp_cmdline) == NULL)
1695+ return;
1696+ if (((cp2 = strchr(cp1, ':')) != NULL)
1697+ && (((cp3 = strchr(cp2+1, ' ')) != NULL)
1698+ || ((cp3 = strchr(cp2+1, ':')) != NULL))) {
1699+ int l1 = cp2 - cp1;
1700+ int l2 = cp3 - cp2 - 1;
1701+ int l3 = strlen(cp3) - 1;
1702+ if (l1 && l2 && l3) {
1703+ *cp2++ = '\0';
1704+ *cp3 = '\0';
1705+ env_nfsServer = cp1;
1706+ env_nfsMountPoint = env_nfsPath = epicsStrDup(cp2);
1707+ *cp3 = '/';
1708+ rtems_bsdnet_bootp_cmdline = cp2;
1709+ }
1710+ }
1711+}
1712+
1713+/*
1714+ * Split NFS mount information of the form nfs_server:host_path:local_path
1715+ */
1716+static void
1717+splitNfsMountPath(char *nfsString)
1718+{
1719+ char *cp2, *cp3;
1720+
1721+ if (nfsString == NULL)
1722+ return;
1723+ if (((cp2 = strchr(nfsString, ':')) != NULL)
1724+ && (((cp3 = strchr(cp2+1, ' ')) != NULL)
1725+ || ((cp3 = strchr(cp2+1, ':')) != NULL))) {
1726+ int l1 = cp2 - nfsString;
1727+ int l2 = cp3 - cp2 - 1;
1728+ int l3 = strlen(cp3) - 1;
1729+ if (l1 && l2 && l3) {
1730+ *cp2++ = '\0';
1731+ *cp3++ = '\0';
1732+ env_nfsServer = nfsString;
1733+ env_nfsPath = cp2;
1734+ env_nfsMountPoint = cp3;
1735+ }
1736+ }
1737+}
1738+
1739+#if defined(HAVE_MOTLOAD)
1740+
1741+/*
1742+ * Motorola MOTLOAD NVRAM Access
1743+ */
1744+static char *
1745+gev(const char *parm, volatile char *nvp)
1746+{
1747+ const char *val;
1748+ const char *name;
1749+ char *ret;
1750+ char c;
1751+
1752+ for (;;) {
1753+ if (*nvp == '\0')
1754+ return NULL;
1755+ name = parm;
1756+ while ((c = *nvp++) != '\0') {
1757+ if ((c == '=') && (*name == '\0')) {
1758+ val = (char *)nvp;
1759+ while (*nvp++ != '\0')
1760+ continue;
1761+ ret = malloc(nvp - val);
1762+ if (ret == NULL)
1763+ return NULL;
1764+ strcpy(ret, val);
1765+ return ret;
1766+ }
1767+ if (c != *name++) {
1768+ while (*nvp++ != '\0')
1769+ continue;
1770+ break;
1771+ }
1772+ }
1773+ }
1774+}
1775+
1776+static char *
1777+motScriptParm(const char *mot_script_boot, char parm)
1778+{
1779+ const char *cp;
1780+ char *ret;
1781+ int l;
1782+
1783+ while (*mot_script_boot != '\0') {
1784+ if (isspace(*(unsigned char *)mot_script_boot)
1785+ && (*(mot_script_boot+1) == '-')
1786+ && (*(mot_script_boot+2) == parm)) {
1787+ mot_script_boot += 3;
1788+ cp = mot_script_boot;
1789+ while ((*mot_script_boot != '\0') &&
1790+ !isspace(*(unsigned char *)mot_script_boot))
1791+ mot_script_boot++;
1792+ l = mot_script_boot - cp;
1793+ ret = malloc(l+1);
1794+ if (ret == NULL)
1795+ return NULL;
1796+ strncpy(ret, cp, l);
1797+ *(ret+l) = '\0';
1798+ return ret;
1799+ }
1800+ mot_script_boot++;
1801+ }
1802+ return NULL;
1803+}
1804+
1805+void
1806+setBootConfigFromNVRAM(void)
1807+{
1808+ char *cp;
1809+ const char *mot_script_boot;
1810+ char *nvp;
1811+
1812+ if (rtems_bsdnet_config.bootp != NULL)
1813+ return;
1814+
1815+# if defined(BSP_NVRAM_BASE_ADDR)
1816+ nvp = (volatile unsigned char *)(BSP_NVRAM_BASE_ADDR+0x70f8);
1817+# elif defined(BSP_I2C_VPD_EEPROM_DEV_NAME)
1818+ char gev_buf[3592];
1819+ int fd;
1820+ if ((fd = open(BSP_I2C_VPD_EEPROM_DEV_NAME, 0)) < 0) {
1821+ printf("Can't open %s: %s\n", BSP_I2C_VPD_EEPROM_DEV_NAME, strerror(errno));
1822+ return;
1823+ }
1824+ lseek(fd, 0x10f8, SEEK_SET);
1825+ if (read(fd, gev_buf, sizeof gev_buf) != sizeof gev_buf) {
1826+ printf("Can't read %s: %s\n", BSP_I2C_VPD_EEPROM_DEV_NAME, strerror(errno));
1827+ return;
1828+ }
1829+ close(fd);
1830+ nvp = gev_buf;
1831+# else
1832+# error "No way to read GEV!"
1833+# endif
1834+
1835+ mot_script_boot = gev("mot-script-boot", nvp);
1836+ if ((rtems_bsdnet_bootp_server_name = gev("mot-/dev/enet0-sipa", nvp)) == NULL)
1837+ rtems_bsdnet_bootp_server_name = motScriptParm(mot_script_boot, 's');
1838+
1839+ {
1840+ struct sockaddr_in ain;
1841+ aToIPAddr(rtems_bsdnet_bootp_server_name, 0, &ain);
1842+ rtems_bsdnet_bootp_server_address = ain.sin_addr;
1843+ }
1844+
1845+ if ((rtems_bsdnet_config.gateway = gev("mot-/dev/enet0-gipa", nvp)) == NULL)
1846+ rtems_bsdnet_config.gateway = motScriptParm(mot_script_boot, 'g');
1847+ if ((rtems_bsdnet_config.ifconfig->ip_netmask = gev("mot-/dev/enet0-snma", nvp)) == NULL)
1848+ rtems_bsdnet_config.ifconfig->ip_netmask = motScriptParm(mot_script_boot, 'm');
1849+
1850+ rtems_bsdnet_config.name_server[0] = gev("rtems-dns-server", nvp);
1851+ if (rtems_bsdnet_config.name_server[0] == NULL)
1852+ rtems_bsdnet_config.name_server[0] = rtems_bsdnet_bootp_server_name;
1853+ cp = gev("rtems-dns-domainname", nvp);
1854+ if (cp)
1855+ rtems_bsdnet_config.domainname = cp;
1856+
1857+ if ((rtems_bsdnet_config.ifconfig->ip_address = gev("mot-/dev/enet0-cipa", nvp)) == NULL)
1858+ rtems_bsdnet_config.ifconfig->ip_address = motScriptParm(mot_script_boot, 'c');
1859+ rtems_bsdnet_config.hostname = gev("rtems-client-name", nvp);
1860+ if (rtems_bsdnet_config.hostname == NULL)
1861+ rtems_bsdnet_config.hostname = rtems_bsdnet_config.ifconfig->ip_address;
1862+
1863+ if ((rtems_bsdnet_bootp_boot_file_name = gev("mot-/dev/enet0-file", nvp)) == NULL)
1864+ rtems_bsdnet_bootp_boot_file_name = motScriptParm(mot_script_boot, 'f');
1865+ rtems_bsdnet_bootp_cmdline = gev("epics-script", nvp);
1866+ splitRtemsBsdnetBootpCmdline();
1867+ splitNfsMountPath(gev("epics-nfsmount", nvp));
1868+ rtems_bsdnet_config.ntp_server[0] = gev("epics-ntpserver", nvp);
1869+ if (rtems_bsdnet_config.ntp_server[0] == NULL)
1870+ rtems_bsdnet_config.ntp_server[0] = rtems_bsdnet_bootp_server_name;
1871+ if ((cp = gev("epics-tz", nvp)) != NULL)
1872+ epicsEnvSet("TZ", cp);
1873+ env_rtems_gdb_stub = gev("gdb-start", nvp);
1874+ epics_initialized_environment = 1;
1875+}
1876+
1877+#elif defined(HAVE_PPCBUG)
1878+/*
1879+ * Motorola PPCBUG NVRAM Access
1880+ */
1881+struct ppcbug_nvram {
1882+ uint32_t PacketVersionIdentifier;
1883+ uint32_t NodeControlMemoryAddress;
1884+ uint32_t BootFileLoadAddress;
1885+ uint32_t BootFileExecutionAddress;
1886+ uint32_t BootFileExecutionDelay;
1887+ uint32_t BootFileLength;
1888+ uint32_t BootFileByteOffset;
1889+ uint32_t TraceBufferAddress;
1890+ uint32_t ClientIPAddress;
1891+ uint32_t ServerIPAddress;
1892+ uint32_t SubnetIPAddressMask;
1893+ uint32_t BroadcastIPAddressMask;
1894+ uint32_t GatewayIPAddress;
1895+ uint8_t BootpRarpRetry;
1896+ uint8_t TftpRarpRetry;
1897+ uint8_t BootpRarpControl;
1898+ uint8_t UpdateControl;
1899+ char BootFilenameString[64];
1900+ char ArgumentFilenameString[64];
1901+};
1902+
1903+static char *addr(char *cbuf, uint32_t addr)
1904+{
1905+ struct in_addr a;
1906+ if ((a.s_addr = addr) == 0)
1907+ return NULL;
1908+ return (char *)inet_ntop(AF_INET, &a, cbuf, INET_ADDRSTRLEN);
1909+}
1910+
1911+void
1912+setBootConfigFromNVRAM(void)
1913+{
1914+ static struct ppcbug_nvram nvram;
1915+ static char ip_address[INET_ADDRSTRLEN];
1916+ static char ip_netmask[INET_ADDRSTRLEN];
1917+ static char server[INET_ADDRSTRLEN];
1918+ static char gateway[INET_ADDRSTRLEN];
1919+
1920+ if (rtems_bsdnet_config.bootp != NULL)
1921+ return;
1922+
1923+ /*
1924+ * Get network configuation from PPCBUG.
1925+ * The 'correct' way to do this would be to issue a .NETCFIG PPCBUG
1926+ * system call. Unfortunately it is very difficult to issue such a
1927+ * call once RTEMS is up and running so we just copy from the 'known'
1928+ * location of the network configuration parameters.
1929+ * Care must be taken to access the NVRAM a byte at a time.
1930+ */
1931+
1932+#if defined(NVRAM_INDIRECT)
1933+ {
1934+ volatile char *addrLo = (volatile char *)0x80000074;
1935+ volatile char *addrHi = (volatile char *)0x80000075;
1936+ volatile char *data = (volatile char *)0x80000077;
1937+ int addr = 0x1000;
1938+ char *d = (char *)&nvram;
1939+
1940+ while (d < ((char *)&nvram + sizeof nvram)) {
1941+ *addrLo = addr & 0xFF;
1942+ *addrHi = (addr >> 8) & 0xFF;
1943+ *d++ = *data;
1944+ addr++;
1945+ }
1946+ }
1947+#else
1948+ {
1949+ volatile char *s = (volatile char *)0xFFE81000;
1950+ char *d = (char *)&nvram;
1951+
1952+ while (d < ((char *)&nvram + sizeof nvram))
1953+ *d++ = *s++;
1954+ }
1955+#endif
1956+ /*
1957+ * Assume that the boot server is also the name, log and ntp server!
1958+ */
1959+ rtems_bsdnet_config.name_server[0] =
1960+ rtems_bsdnet_config.ntp_server[0] =
1961+ rtems_bsdnet_bootp_server_name = addr(server, nvram.ServerIPAddress);
1962+ rtems_bsdnet_bootp_server_address.s_addr = nvram.ServerIPAddress;
1963+ /*
1964+ * Nothing better to use as host name!
1965+ */
1966+ rtems_bsdnet_config.ifconfig->ip_address =
1967+ rtems_bsdnet_config.hostname = addr(ip_address, nvram.ClientIPAddress);
1968+
1969+ rtems_bsdnet_config.gateway = addr(gateway, nvram.GatewayIPAddress);
1970+ rtems_bsdnet_config.ifconfig->ip_netmask = addr(ip_netmask, nvram.SubnetIPAddressMask);
1971+
1972+ rtems_bsdnet_bootp_boot_file_name = nvram.BootFilenameString;
1973+ rtems_bsdnet_bootp_cmdline = nvram.ArgumentFilenameString;
1974+ splitRtemsBsdnetBootpCmdline();
1975+ epics_initialized_environment = 1;
1976+}
1977+
1978+#elif defined(__mcf528x__)
1979+
1980+static char *
1981+env(const char *parm, const char *defaultValue)
1982+{
1983+ const char *cp = bsp_getbenv(parm);
1984+
1985+ if (!cp) {
1986+ if (!defaultValue)
1987+ return NULL;
1988+ cp = defaultValue;
1989+ printf ("%s environment variable missing -- using %s.\n", parm, cp);
1990+ }
1991+ return epicsStrDup(cp);
1992+}
1993+
1994+void
1995+setBootConfigFromNVRAM(void)
1996+{
1997+ const char *cp1;
1998+
1999+ if (rtems_bsdnet_config.bootp != NULL)
2000+ return;
2001+ rtems_bsdnet_config.gateway = env("GATEWAY", NULL);
2002+ rtems_bsdnet_config.ifconfig->ip_netmask = env("NETMASK", "255.255.252.0");
2003+
2004+ rtems_bsdnet_bootp_server_name = env("SERVER", "192.168.0.1");
2005+ rtems_bsdnet_config.name_server[0] = env("NAMESERVER", rtems_bsdnet_bootp_server_name);
2006+ rtems_bsdnet_config.ntp_server[0] = env("NTPSERVER", rtems_bsdnet_bootp_server_name);
2007+ cp1 = env("DOMAIN", NULL);
2008+ if (cp1 != NULL)
2009+ rtems_bsdnet_config.domainname = cp1;
2010+ rtems_bsdnet_config.hostname = env("HOSTNAME", "iocNobody");
2011+ rtems_bsdnet_config.ifconfig->ip_address = env("IPADDR0", "192.168.0.2");
2012+ rtems_bsdnet_bootp_boot_file_name = env("BOOTFILE", "uC5282App.boot");
2013+ rtems_bsdnet_bootp_cmdline = env("CMDLINE", "epics/iocBoot/iocNobody/st.cmd");
2014+ splitNfsMountPath(env("NFSMOUNT", NULL));
2015+ if ((cp1 = env("TZ", NULL)) != NULL)
2016+ epicsEnvSet("TZ", cp1);
2017+ env_rtems_gdb_stub = env("GDBSTART", NULL);
2018+ epics_initialized_environment = 1;
2019+}
2020+
2021+#elif defined(USE_MULTIBOOT) && (__RTEMS_MAJOR__>4 || (__RTEMS_MAJOR__==4 && __RTEMS_MINOR__>9))
2022+
2023+/* Try to fill out missing BOOTP/DHCP configuration from the environment */
2024+void
2025+bootpFallbackFromNVRAM(void)
2026+{
2027+#define ENV2VAR(ENV, VAR) if(!VAR) {VAR = getenv(ENV);}
2028+ ENV2VAR("epics-ip", rtems_bsdnet_config.ifconfig->ip_address);
2029+ ENV2VAR("epics-gw", rtems_bsdnet_config.gateway);
2030+ ENV2VAR("epics-mask", rtems_bsdnet_config.ifconfig->ip_netmask);
2031+ ENV2VAR("epics-dns", rtems_bsdnet_config.name_server[0]);
2032+ ENV2VAR("epics-domain", rtems_bsdnet_config.domainname);
2033+ ENV2VAR("epics-server", rtems_bsdnet_bootp_server_name);
2034+ ENV2VAR("epics-client", rtems_bsdnet_config.hostname);
2035+ ENV2VAR("epics-script", rtems_bsdnet_bootp_cmdline);
2036+ ENV2VAR("epics-ntp", rtems_bsdnet_config.ntp_server[0]);
2037+ ENV2VAR("gdb-start", env_rtems_gdb_stub);
2038+#undef ENV2VAR
2039+
2040+ if (rtems_bsdnet_config.ntp_server[0] == NULL)
2041+ rtems_bsdnet_config.ntp_server[0] = rtems_bsdnet_bootp_server_name;
2042+
2043+ splitRtemsBsdnetBootpCmdline();
2044+ splitNfsMountPath(getenv("epics-nfsmount"));
2045+}
2046+
2047+void
2048+setBootConfigFromNVRAM(void)
2049+{
2050+ const char *mboot = bsp_cmdline();
2051+ size_t blen = strlen(mboot);
2052+ char *mboot2;
2053+ char *tok, *store, *save;
2054+
2055+ store = mboot2 = malloc(blen+1);
2056+ if(!mboot2)
2057+ return;
2058+ strcpy(mboot2, mboot);
2059+
2060+ /* Populate environment with multiboot arguments.
2061+ * format of multiboot string is a space seperated list of
2062+ * sub-strings. eg.
2063+ * "progname --arg=one --other=two otherjunk"
2064+ */
2065+
2066+ for(;;mboot2=NULL) {
2067+ char *val;
2068+ /* break up by space */
2069+ tok = strtok_r(mboot2, " ", &save);
2070+ if(!tok)
2071+ break;
2072+
2073+ /* only accept arguments starting with '--' */
2074+ if(tok[0]!='-' || tok[1]!='-')
2075+ continue;
2076+ tok+=2;
2077+
2078+ /* only accept arguments with an assignment */
2079+ val = strchr(tok, '=');
2080+ if(!val)
2081+ continue;
2082+ *val++ = '\0';
2083+
2084+ epicsEnvSet(tok, val);
2085+ printk("Set '%s' = '%s'\n", tok, val);
2086+ }
2087+
2088+ free(store);
2089+
2090+ epics_initialized_environment = 1;
2091+}
2092+
2093+#else
2094+/*
2095+ * Placeholder for systems without NVRAM
2096+ */
2097+void
2098+setBootConfigFromNVRAM(void)
2099+{
2100+ /* no point in printing here as the console isn't initialized... */
2101+}
2102+#endif
2103diff --git a/RTEMS/rtems_netconfig.h b/RTEMS/rtems_netconfig.h
2104new file mode 100644
2105index 0000000..e894f94
2106--- /dev/null
2107+++ b/RTEMS/rtems_netconfig.h
2108@@ -0,0 +1,7 @@
2109+#ifndef RTEMS_NETCONF_H
2110+#define RTEMS_NETCONF_H
2111+
2112+extern int
2113+rtems_ne2kpci_driver_attach (struct rtems_bsdnet_ifconfig *config, int attach);
2114+
2115+#endif /* RTEMS_NETCONF_H */
2116diff --git a/src/osi/os/RTEMS/epicsAtomicOSD.cpp b/src/osi/os/RTEMS-kernel/epicsAtomicOSD.cpp
2117index e69de29..e69de29 100644
2118--- a/src/osi/os/RTEMS/epicsAtomicOSD.cpp
2119+++ b/src/osi/os/RTEMS-kernel/epicsAtomicOSD.cpp
2120diff --git a/src/osi/os/RTEMS/epicsAtomicOSD.h b/src/osi/os/RTEMS-kernel/epicsAtomicOSD.h
2121index fefd201..fefd201 100644
2122--- a/src/osi/os/RTEMS/epicsAtomicOSD.h
2123+++ b/src/osi/os/RTEMS-kernel/epicsAtomicOSD.h
2124diff --git a/src/osi/os/RTEMS/osdEvent.c b/src/osi/os/RTEMS-kernel/osdEvent.c
2125index 4554138..4554138 100644
2126--- a/src/osi/os/RTEMS/osdEvent.c
2127+++ b/src/osi/os/RTEMS-kernel/osdEvent.c
2128diff --git a/src/osi/os/RTEMS/osdEvent.h b/src/osi/os/RTEMS-kernel/osdEvent.h
2129index 6c53aad..6c53aad 100644
2130--- a/src/osi/os/RTEMS/osdEvent.h
2131+++ b/src/osi/os/RTEMS-kernel/osdEvent.h
2132diff --git a/src/osi/os/RTEMS/osdFindSymbol.c b/src/osi/os/RTEMS-kernel/osdFindSymbol.c
2133index 9e947f9..9e947f9 100644
2134--- a/src/osi/os/RTEMS/osdFindSymbol.c
2135+++ b/src/osi/os/RTEMS-kernel/osdFindSymbol.c
2136diff --git a/src/osi/os/RTEMS/osdMessageQueue.c b/src/osi/os/RTEMS-kernel/osdMessageQueue.c
2137index a566de6..a566de6 100644
2138--- a/src/osi/os/RTEMS/osdMessageQueue.c
2139+++ b/src/osi/os/RTEMS-kernel/osdMessageQueue.c
2140diff --git a/src/osi/os/RTEMS/osdMessageQueue.h b/src/osi/os/RTEMS-kernel/osdMessageQueue.h
2141index 0244a1f..0244a1f 100644
2142--- a/src/osi/os/RTEMS/osdMessageQueue.h
2143+++ b/src/osi/os/RTEMS-kernel/osdMessageQueue.h
2144diff --git a/src/osi/os/RTEMS/osdMutex.c b/src/osi/os/RTEMS-kernel/osdMutex.c
2145index 96fde6e..96fde6e 100644
2146--- a/src/osi/os/RTEMS/osdMutex.c
2147+++ b/src/osi/os/RTEMS-kernel/osdMutex.c
2148diff --git a/src/osi/os/RTEMS/osdMutex.h b/src/osi/os/RTEMS-kernel/osdMutex.h
2149index 7e2ecc7..7e2ecc7 100644
2150--- a/src/osi/os/RTEMS/osdMutex.h
2151+++ b/src/osi/os/RTEMS-kernel/osdMutex.h
2152diff --git a/src/osi/os/RTEMS/osdPoolStatus.c b/src/osi/os/RTEMS-kernel/osdPoolStatus.c
2153index b2f4011..b2f4011 100644
2154--- a/src/osi/os/RTEMS/osdPoolStatus.c
2155+++ b/src/osi/os/RTEMS-kernel/osdPoolStatus.c
2156diff --git a/src/osi/os/RTEMS/osdProcess.c b/src/osi/os/RTEMS-kernel/osdProcess.c
2157index 2768dbb..2768dbb 100644
2158--- a/src/osi/os/RTEMS/osdProcess.c
2159+++ b/src/osi/os/RTEMS-kernel/osdProcess.c
2160diff --git a/src/osi/os/RTEMS/osdReadline.c b/src/osi/os/RTEMS-kernel/osdReadline.c
2161index 877db53..877db53 100644
2162--- a/src/osi/os/RTEMS/osdReadline.c
2163+++ b/src/osi/os/RTEMS-kernel/osdReadline.c
2164diff --git a/src/osi/os/RTEMS/osdSignal.cpp b/src/osi/os/RTEMS-kernel/osdSignal.cpp
2165index 08dfa02..08dfa02 100644
2166--- a/src/osi/os/RTEMS/osdSignal.cpp
2167+++ b/src/osi/os/RTEMS-kernel/osdSignal.cpp
2168diff --git a/src/osi/os/RTEMS/osdSock.h b/src/osi/os/RTEMS-kernel/osdSock.h
2169index 6177c30..6177c30 100644
2170--- a/src/osi/os/RTEMS/osdSock.h
2171+++ b/src/osi/os/RTEMS-kernel/osdSock.h
2172diff --git a/src/osi/os/RTEMS/osdSpin.c b/src/osi/os/RTEMS-kernel/osdSpin.c
2173index 7a45468..7a45468 100644
2174--- a/src/osi/os/RTEMS/osdSpin.c
2175+++ b/src/osi/os/RTEMS-kernel/osdSpin.c
2176diff --git a/src/osi/os/RTEMS/osdStrtod.h b/src/osi/os/RTEMS-kernel/osdStrtod.h
2177index 39fda69..39fda69 100644
2178--- a/src/osi/os/RTEMS/osdStrtod.h
2179+++ b/src/osi/os/RTEMS-kernel/osdStrtod.h
2180diff --git a/src/osi/os/RTEMS/osdThread.c b/src/osi/os/RTEMS-kernel/osdThread.c
2181index 769e958..769e958 100644
2182--- a/src/osi/os/RTEMS/osdThread.c
2183+++ b/src/osi/os/RTEMS-kernel/osdThread.c
2184diff --git a/src/osi/os/RTEMS/osdThread.h b/src/osi/os/RTEMS-kernel/osdThread.h
2185index 4451f84..4451f84 100644
2186--- a/src/osi/os/RTEMS/osdThread.h
2187+++ b/src/osi/os/RTEMS-kernel/osdThread.h
2188diff --git a/src/osi/os/RTEMS/osdThreadExtra.c b/src/osi/os/RTEMS-kernel/osdThreadExtra.c
2189index 0a7c7ae..0a7c7ae 100644
2190--- a/src/osi/os/RTEMS/osdThreadExtra.c
2191+++ b/src/osi/os/RTEMS-kernel/osdThreadExtra.c
2192diff --git a/src/osi/os/RTEMS/osdTime.cpp b/src/osi/os/RTEMS-kernel/osdTime.cpp
2193index 1350c1c..1350c1c 100644
2194--- a/src/osi/os/RTEMS/osdTime.cpp
2195+++ b/src/osi/os/RTEMS-kernel/osdTime.cpp
2196diff --git a/src/osi/os/RTEMS/osdTime.h b/src/osi/os/RTEMS-kernel/osdTime.h
2197index 55e3bc2..55e3bc2 100644
2198--- a/src/osi/os/RTEMS/osdTime.h
2199+++ b/src/osi/os/RTEMS-kernel/osdTime.h
2200diff --git a/src/osi/os/RTEMS/osiUnistd.h b/src/osi/os/RTEMS-kernel/osiUnistd.h
2201index c0a6e22..c0a6e22 100644
2202--- a/src/osi/os/RTEMS/osiUnistd.h
2203+++ b/src/osi/os/RTEMS-kernel/osiUnistd.h
2204diff --git a/src/osi/os/RTEMS-posix/osdInterrupt.c b/src/osi/os/RTEMS-posix/osdInterrupt.c
2205new file mode 100644
2206index 0000000..4d4ead6
2207--- /dev/null
2208+++ b/src/osi/os/RTEMS-posix/osdInterrupt.c
2209@@ -0,0 +1,59 @@
2210+/*************************************************************************\
2211+* Copyright (c) 2009 UChicago Argonne LLC, as Operator of Argonne
2212+* National Laboratory.
2213+* Copyright (c) 2002 The Regents of the University of California, as
2214+* Operator of Los Alamos National Laboratory.
2215+* EPICS BASE is distributed subject to a Software License Agreement found
2216+* in file LICENSE that is included with this distribution.
2217+\*************************************************************************/
2218+/* osi/default/osdInterrupt.c */
2219+
2220+/* Author: Marty Kraimer Date: 15JUL99 */
2221+
2222+#include <stddef.h>
2223+#include <string.h>
2224+#include <stdlib.h>
2225+#include <stddef.h>
2226+#include <stdio.h>
2227+
2228+#define epicsExportSharedSymbols
2229+#include "epicsMutex.h"
2230+#include "epicsThread.h"
2231+#include "cantProceed.h"
2232+#include "errlog.h"
2233+#include "epicsInterrupt.h"
2234+
2235+#include <rtems/bspIo.h>
2236+#include <rtems.h>
2237+
2238+epicsShareFunc int epicsInterruptLock()
2239+{
2240+ rtems_interrupt_level level;
2241+
2242+ rtems_interrupt_disable (level);
2243+ return level;
2244+}
2245+
2246+epicsShareFunc void epicsInterruptUnlock(int key)
2247+{
2248+ rtems_interrupt_level level = key;
2249+
2250+ rtems_interrupt_enable (level);
2251+}
2252+
2253+epicsShareFunc int epicsInterruptIsInterruptContext()
2254+{
2255+ return rtems_interrupt_is_in_progress ();
2256+}
2257+
2258+epicsShareFunc void epicsInterruptContextMessage(const char *message)
2259+{
2260+ printk("%s", message);
2261+}
2262+
2263+
2264+
2265+
2266+
2267+
2268+
2269diff --git a/src/osi/os/RTEMS-posix/osdMessageQueue.cpp b/src/osi/os/RTEMS-posix/osdMessageQueue.cpp
2270new file mode 100644
2271index 0000000..b763da1
2272--- /dev/null
2273+++ b/src/osi/os/RTEMS-posix/osdMessageQueue.cpp
2274@@ -0,0 +1,163 @@
2275+/*************************************************************************\
2276+* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
2277+* National Laboratory.
2278+* Copyright (c) 2002 The Regents of the University of California, as
2279+* Operator of Los Alamos National Laboratory.
2280+* Copyright (c) 2017 Fritz-Haber-Institut der Max-Planck-Gesellschaft
2281+* EPICS BASE is distributed subject to a Software License Agreement found
2282+* in file LICENSE that is included with this distribution.
2283+\*************************************************************************/
2284+/*
2285+ * Author W. Eric Norum
2286+ * Heinz Junkes
2287+ *
2288+ * Adapted to rtems4.12
2289+ * -> posix message queues
2290+ * remove all internal calls (_xxx), remove e.g. Objects_Locations etc.
2291+ */
2292+
2293+/*
2294+ * We want to access information which is
2295+ * normally hidden from application programs.
2296+ */
2297+#define __RTEMS_VIOLATE_KERNEL_VISIBILITY__ 1
2298+
2299+#define epicsExportSharedSymbols
2300+#include <assert.h>
2301+#include <stdio.h>
2302+#include <stdlib.h>
2303+#include <string.h>
2304+#include <rtems.h>
2305+#include <rtems/error.h>
2306+#include "epicsMessageQueue.h"
2307+#include "errlog.h"
2308+#include <epicsAtomic.h>
2309+
2310+#include <errno.h>
2311+#include <mqueue.h>
2312+#include <fcntl.h>
2313+
2314+epicsShareFunc epicsMessageQueueId epicsShareAPI
2315+epicsMessageQueueCreate(unsigned int capacity, unsigned int maximumMessageSize)
2316+{
2317+ struct mq_attr the_attr;
2318+ epicsMessageQueueId id = (epicsMessageQueueId)calloc(1, sizeof(*id));
2319+
2320+ epicsAtomicIncrIntT(&id->idCnt);
2321+ sprintf(id->name, "MQ_%010d",epicsAtomicGetIntT(&id->idCnt));
2322+ the_attr.mq_maxmsg = capacity;
2323+ the_attr.mq_msgsize = maximumMessageSize;
2324+ id->id = mq_open(id->name, O_RDWR | O_CREAT | O_EXCL, 0644, &the_attr);
2325+ if (id->id < 0) {
2326+ errlogPrintf ("Can't create message queue: %s\n", strerror (errno));
2327+ return NULL;
2328+ }
2329+ return id;
2330+}
2331+
2332+epicsShareFunc void epicsShareAPI epicsMessageQueueDestroy(
2333+ epicsMessageQueueId id)
2334+{
2335+ int rv;
2336+ rv = mq_close(id->id);
2337+ if( rv ) {
2338+ errlogPrintf("epicsMessageQueueDestroy mq_close failed: %s\n",
2339+ strerror(rv));
2340+ }
2341+ rv = mq_unlink(id->name);
2342+ if( rv ) {
2343+ errlogPrintf("epicsMessageQueueDestroy mq_unlink %s failed: %s\n",
2344+ id->name, strerror(rv));
2345+ }
2346+ free(id);
2347+}
2348+
2349+epicsShareFunc int epicsShareAPI epicsMessageQueueTrySend(
2350+ epicsMessageQueueId id,
2351+ void *message,
2352+ unsigned int messageSize)
2353+{
2354+ struct timespec ts;
2355+ clock_gettime(CLOCK_REALTIME, &ts);
2356+ return mq_timedsend(id->id, (char const *)message, messageSize, 0, &ts);
2357+}
2358+
2359+epicsShareFunc int epicsShareAPI epicsMessageQueueSendWithTimeout(
2360+ epicsMessageQueueId id,
2361+ void *message,
2362+ unsigned int messageSize,
2363+ double timeout)
2364+{
2365+ struct timespec ts;
2366+ unsigned long micros;
2367+
2368+ // assume timeout in sec
2369+ micros = (unsigned long)(timeout * 1000000.0);
2370+ clock_gettime(CLOCK_REALTIME, &ts);
2371+ ts.tv_sec += micros / 1000000L;
2372+ ts.tv_nsec += (micros % 1000000L) * 1000L;
2373+
2374+ return mq_timedsend (id->id, (const char *)message, messageSize, 0, &ts);
2375+}
2376+
2377+epicsShareFunc int epicsShareAPI epicsMessageQueueTryReceive(
2378+ epicsMessageQueueId id,
2379+ void *message,
2380+ unsigned int size)
2381+{
2382+ struct timespec ts;
2383+ clock_gettime(CLOCK_REALTIME, &ts);
2384+ return mq_timedreceive(id->id, (char *)message, size, NULL, &ts);
2385+}
2386+
2387+epicsShareFunc int epicsShareAPI epicsMessageQueueReceiveWithTimeout(
2388+ epicsMessageQueueId id,
2389+ void *message,
2390+ unsigned int size,
2391+ double timeout)
2392+{
2393+ unsigned long micros;
2394+ struct timespec ts;
2395+
2396+ micros = (unsigned long)(timeout * 1000000.0);
2397+ clock_gettime(CLOCK_REALTIME, &ts);
2398+ ts.tv_sec += micros / 1000000L;
2399+ ts.tv_nsec += (micros % 1000000L) * 1000L;
2400+
2401+ return mq_timedreceive(id->id, (char *)message, size, NULL, &ts);
2402+}
2403+
2404+epicsShareFunc int epicsShareAPI epicsMessageQueuePending(
2405+ epicsMessageQueueId id)
2406+{
2407+ int rv;
2408+ struct mq_attr the_attr;
2409+
2410+ rv = mq_getattr(id->id, &the_attr);
2411+ if (rv) {
2412+ errlogPrintf("Epics Message queue %x (%s) get attr failed: %s\n",
2413+ (unsigned int)id->id, id->name, strerror(rv));
2414+ return -1;
2415+ }
2416+ return the_attr.mq_curmsgs;
2417+}
2418+
2419+epicsShareFunc void epicsShareAPI epicsMessageQueueShow(
2420+ epicsMessageQueueId id,
2421+ int level)
2422+{
2423+ int rv;
2424+ struct mq_attr the_attr;
2425+
2426+ rv = mq_getattr(id->id, &the_attr);
2427+ if (rv) {
2428+ errlogPrintf("Epics Message queue %x (%s) get attr failed: %s\n",
2429+ (unsigned int)id->id, id->id, strerror(rv));
2430+ }
2431+
2432+ printf("Message Queue Used:%ld Max Msg:%lu", the_attr.mq_curmsgs, the_attr.mq_maxmsg);
2433+ if (level >= 1)
2434+ printf(" Maximum size:%lu", the_attr.mq_msgsize);
2435+
2436+ printf("\n");
2437+}
2438diff --git a/src/osi/os/RTEMS-posix/osdMessageQueue.h b/src/osi/os/RTEMS-posix/osdMessageQueue.h
2439new file mode 100644
2440index 0000000..fccb2d2
2441--- /dev/null
2442+++ b/src/osi/os/RTEMS-posix/osdMessageQueue.h
2443@@ -0,0 +1,31 @@
2444+/*************************************************************************\
2445+ * * Copyright (c) 2002 The University of Chicago, as Operator of Argonne
2446+ * * National Laboratory.
2447+ * * Copyright (c) 2002 The Regents of the University of California, as
2448+ * * Operator of Los Alamos National Laboratory.
2449+ * * Copyright (c) 2017 Fritz-Haber-Institut der Max-Planck-Gesellschaft
2450+ * * EPICS BASE is distributed subject to a Software License Agreement found
2451+ * * in file LICENSE that is included with this distribution.
2452+ * \*************************************************************************/
2453+/*
2454+ * Author W. Eric Norum
2455+ * Heinz Junkes
2456+ *
2457+ * Eric's note : Very thin shims around vxWorks routines
2458+ *
2459+ * Adapted to rtems4.12
2460+ * -> posix message queues
2461+ */
2462+
2463+#include <rtems.h>
2464+#include <mqueue.h>
2465+
2466+struct epicsMessageQueueOSD {
2467+ mqd_t id;
2468+ char name[24];
2469+ int idCnt;
2470+
2471+};
2472+
2473+#define epicsMessageQueueSend(q,m,l) (mq_send((q)->id, (const char*)(m), (l), 0))
2474+#define epicsMessageQueueReceive(q,m,s) (mq_receive((q)->id, (char*)(m), (s), NULL))
2475diff --git a/src/osi/os/RTEMS-posix/osdMutex.c b/src/osi/os/RTEMS-posix/osdMutex.c
2476new file mode 100644
2477index 0000000..7f4aa62
2478--- /dev/null
2479+++ b/src/osi/os/RTEMS-posix/osdMutex.c
2480@@ -0,0 +1,6 @@
2481+#include <rtems.h>
2482+#include <rtems/error.h>
2483+#include <rtems/rtems/tasks.h>
2484+#include <rtems/score/threadimpl.h>
2485+
2486+#include "../posix/osdMutex.c"
2487diff --git a/src/osi/os/RTEMS-posix/osdPoolStatus.c b/src/osi/os/RTEMS-posix/osdPoolStatus.c
2488new file mode 100644
2489index 0000000..cdd8941
2490--- /dev/null
2491+++ b/src/osi/os/RTEMS-posix/osdPoolStatus.c
2492@@ -0,0 +1,34 @@
2493+/*************************************************************************\
2494+* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
2495+* National Laboratory.
2496+* Copyright (c) 2002 The Regents of the University of California, as
2497+* Operator of Los Alamos National Laboratory.
2498+* Copyright (c) 2017 Fritz-Haber-Institut der Max-Planck-Gesellschaft
2499+* EPICS BASE is distributed subject to a Software License Agreement found
2500+* in file LICENSE that is included with this distribution.
2501+\*************************************************************************/
2502+
2503+/*
2504+ * Heinz Junkes
2505+ * Adapted to rtems4.12
2506+ */
2507+
2508+#include <rtems.h>
2509+#include <rtems/malloc.h>
2510+#include <rtems/score/heap.h>
2511+#define epicsExportSharedSymbols
2512+#include "osiPoolStatus.h"
2513+
2514+/*
2515+ * osiSufficentSpaceInPool ()
2516+ *
2517+ */
2518+epicsShareFunc int epicsShareAPI osiSufficentSpaceInPool ( size_t contiguousBlockSize )
2519+{
2520+ unsigned long n;
2521+ Heap_Information_block info;
2522+
2523+ malloc_info( &info );
2524+ n = info.Stats.size - (unsigned long)(info.Stats.lifetime_allocated - info.Stats.lifetime_freed);
2525+ return (n > (50000 + contiguousBlockSize));
2526+}
2527diff --git a/src/osi/os/RTEMS-posix/osdSock.h b/src/osi/os/RTEMS-posix/osdSock.h
2528new file mode 100644
2529index 0000000..103cdd7
2530--- /dev/null
2531+++ b/src/osi/os/RTEMS-posix/osdSock.h
2532@@ -0,0 +1,112 @@
2533+/*************************************************************************\
2534+* Copyright (c) 2002 The University of Saskatchewan
2535+* Copyright (c) 2017 Fritz-Haber-Institut der Max-Planck-Gesellschaft
2536+* EPICS BASE is distributed subject to a Software License Agreement found
2537+* in file LICENSE that is included with this distribution.
2538+\*************************************************************************/
2539+/*
2540+ * RTEMS osdSock.h
2541+ * Author: W. Eric Norum
2542+ * Heinz Junkes
2543+ *
2544+ * Adapted to rtems4.12
2545+ */
2546+#ifndef osdSockH
2547+#define osdSockH
2548+
2549+#include <errno.h>
2550+
2551+#include <sys/types.h>
2552+#include <sys/param.h>
2553+#include <sys/time.h>
2554+#include <sys/socket.h>
2555+#include <sys/ioctl.h>
2556+#include <netinet/in.h>
2557+#include <netinet/tcp.h>
2558+#include <arpa/inet.h>
2559+#include <net/if.h>
2560+#include <netdb.h>
2561+#include <ifaddrs.h> /* getifaddrs() */
2562+#include <unistd.h>
2563+
2564+#ifdef __cplusplus
2565+extern "C" {
2566+#endif
2567+
2568+int select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
2569+
2570+#ifdef __cplusplus
2571+}
2572+#endif
2573+
2574+
2575+#ifndef IPPORT_USERRESERVED
2576+#define IPPORT_USERRESERVED 5000
2577+#endif
2578+
2579+#define USE_IFADDRS
2580+
2581+typedef int SOCKET;
2582+#define INVALID_SOCKET (-1)
2583+#define SOCKERRNO errno
2584+#define socket_ioctl(A,B,C) ioctl(A,B,C)
2585+typedef int osiSockIoctl_t;
2586+typedef socklen_t osiSocklen_t;
2587+
2588+typedef char osiSockOptMcastLoop_t;
2589+
2590+#define FD_IN_FDSET(FD) ((FD)<FD_SETSIZE)
2591+
2592+#define SOCK_EWOULDBLOCK EWOULDBLOCK
2593+#define SOCK_ENOBUFS ENOBUFS
2594+#define SOCK_ECONNRESET ECONNRESET
2595+#define SOCK_ETIMEDOUT ETIMEDOUT
2596+#define SOCK_EACCES EACCES
2597+#define SOCK_EADDRINUSE EADDRINUSE
2598+#define SOCK_EADDRNOTAVAIL EADDRNOTAVAIL
2599+#define SOCK_ECONNREFUSED ECONNREFUSED
2600+#define SOCK_ECONNABORTED ECONNABORTED
2601+#define SOCK_EINPROGRESS EINPROGRESS
2602+#define SOCK_EISCONN EISCONN
2603+#define SOCK_EALREADY EALREADY
2604+#define SOCK_EINVAL EINVAL
2605+#define SOCK_EINTR EINTR
2606+#define SOCK_EPIPE EPIPE
2607+#define SOCK_EMFILE EMFILE
2608+#define SOCK_SHUTDOWN EPIPE
2609+#define SOCK_ENOTSOCK ENOTSOCK
2610+#define SOCK_EBADF EBADF
2611+
2612+#include <sys/time.h>
2613+#include <sys/types.h>
2614+#include <unistd.h>
2615+
2616+#ifndef INADDR_LOOPBACK
2617+#define INADDR_LOOPBACK (u_long)0x7F000001
2618+#endif
2619+
2620+#ifndef INADDR_NONE
2621+# define INADDR_NONE (0xffffffff)
2622+#endif
2623+
2624+/*
2625+ * For shutdown()
2626+ */
2627+#ifndef SHUT_RD
2628+# define SHUT_RD 0
2629+#endif
2630+
2631+#ifndef SHUT_WR
2632+# define SHUT_WR 1
2633+#endif
2634+
2635+#ifndef SHUT_RDWR
2636+# define SHUT_RDWR 2
2637+#endif
2638+
2639+/*
2640+ * Ensure that we get the right network code in default/osdNetIntf.c.
2641+ */
2642+#define ifreq_size(pifreq) (pifreq->ifr_addr.sa_len + sizeof(pifreq->ifr_name))
2643+
2644+#endif /*osdSockH*/
2645diff --git a/src/osi/os/RTEMS-posix/osdThread.c b/src/osi/os/RTEMS-posix/osdThread.c
2646new file mode 100644
2647index 0000000..2b51fdb
2648--- /dev/null
2649+++ b/src/osi/os/RTEMS-posix/osdThread.c
2650@@ -0,0 +1,1042 @@
2651+/*************************************************************************\
2652+* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
2653+* National Laboratory.
2654+* Copyright (c) 2002 The Regents of the University of California, as
2655+* Operator of Los Alamos National Laboratory.
2656+* Copyright (c) 2013 ITER Organization.
2657+* Copyright (c) 2017 Fritz-Haber-Institut der Max-Planck-Gesellschaft
2658+* EPICS BASE is distributed subject to a Software License Agreement found
2659+* in file LICENSE that is included with this distribution.
2660+\*************************************************************************/
2661+
2662+/* Author: Marty Kraimer Date: 18JAN2000
2663+ Heinz Junkes Date: 06APR2017
2664+*/
2665+
2666+/* This is a posix implementation of epicsThread */
2667+#include <stddef.h>
2668+#include <stdlib.h>
2669+#include <stddef.h>
2670+#include <string.h>
2671+#include <stdio.h>
2672+#include <errno.h>
2673+#include <time.h>
2674+#include <pthread.h>
2675+#include <signal.h>
2676+#include <sched.h>
2677+#include <unistd.h>
2678+
2679+#define XSTR(x) STR(x)
2680+#define STR(x) #x
2681+
2682+#if defined(__rtems__)
2683+/* RTEMS defines _POSIX_MEMLOCK as 1 in features.h which is wrong */
2684+#undef _POSIX_MEMLOCK
2685+#endif
2686+
2687+#if defined(_POSIX_MEMLOCK) && _POSIX_MEMLOCK > 0
2688+#include <sys/mman.h>
2689+#endif
2690+
2691+#define epicsExportSharedSymbols
2692+#include "epicsStdio.h"
2693+#include "ellLib.h"
2694+#include "epicsEvent.h"
2695+#include "epicsMutex.h"
2696+#include "epicsString.h"
2697+#include "epicsThread.h"
2698+#include "cantProceed.h"
2699+#include "errlog.h"
2700+#include "epicsAssert.h"
2701+#include "epicsExit.h"
2702+
2703+epicsShareFunc void epicsThreadShowInfo(epicsThreadOSD *pthreadInfo, unsigned int level);
2704+epicsShareFunc void osdThreadHooksRun(epicsThreadId id);
2705+epicsShareFunc void osdThreadHooksRunMain(epicsThreadId id);
2706+
2707+static int mutexLock(pthread_mutex_t *id)
2708+{
2709+ int status;
2710+
2711+ while(1) {
2712+ status = pthread_mutex_lock(id);
2713+ if(status!=EINTR) return status;
2714+ fprintf(stderr,"pthread_mutex_lock returned EINTR. Violates SUSv3\n");
2715+ }
2716+}
2717+
2718+#if defined DONT_USE_POSIX_THREAD_PRIORITY_SCHEDULING
2719+#undef _POSIX_THREAD_PRIORITY_SCHEDULING
2720+#endif
2721+
2722+typedef struct commonAttr{
2723+ pthread_attr_t attr;
2724+ struct sched_param schedParam;
2725+ int maxPriority;
2726+ int minPriority;
2727+ int schedPolicy;
2728+ int usePolicy;
2729+} commonAttr;
2730+
2731+#if defined(_POSIX_THREAD_PRIORITY_SCHEDULING) && _POSIX_THREAD_PRIORITY_SCHEDULING > 0
2732+typedef struct {
2733+ int min_pri, max_pri;
2734+ int policy;
2735+ int ok;
2736+} priAvailable;
2737+#endif
2738+
2739+static pthread_key_t getpthreadInfo;
2740+static pthread_mutex_t onceLock;
2741+static pthread_mutex_t listLock;
2742+static ELLLIST pthreadList = ELLLIST_INIT;
2743+static commonAttr *pcommonAttr = 0;
2744+static int epicsThreadOnceCalled = 0;
2745+
2746
2747+static epicsThreadOSD *createImplicit(void);
2748+
2749+#define checkStatus(status, message) \
2750+ if ((status)) {\
2751+ errlogPrintf("%s error %s\n", (message), strerror((status))); \
2752+ }
2753+
2754+#define checkStatusQuit(status, message, method) \
2755+ if ((status)) { \
2756+ errlogPrintf("%s error %s\n", (message), strerror((status))); \
2757+ cantProceed((method)); \
2758+ }
2759+
2760+/* The following are for use in once, which is only invoked from epicsThreadInit
2761+ * Until epicsThreadInit completes errlogInit will not work.
2762+ * They must also be used in init_threadInfo otherwise errlogInit could get
2763+ * called recursively.
2764+ */
2765+#define checkStatusOnce(status, message) \
2766+ if ((status)) {\
2767+ fprintf(stderr, "%s error %s\n", (message), strerror((status))); \
2768+ }
2769+
2770+#define checkStatusOnceQuit(status, message, method) \
2771+ if ((status)) { \
2772+ fprintf(stderr, "%s error %s", (message), strerror((status))); \
2773+ fprintf(stderr, "in %s\n", (method)); \
2774+ fprintf(stderr, "epicsThreadInit can't proceed. Program exiting\n"); \
2775+ exit(-1); \
2776+ }
2777+
2778+epicsShareFunc int epicsThreadGetPosixPriority(epicsThreadId pthreadInfo)
2779+{
2780+ assert(epicsThreadOnceCalled);
2781+ return(epicsThreadGetPosixPriorityValue(pthreadInfo->osiPriority));
2782+}
2783+
2784+static void setSchedulingPolicy(epicsThreadOSD *pthreadInfo,int policy)
2785+{
2786+#if defined(_POSIX_THREAD_PRIORITY_SCHEDULING) && _POSIX_THREAD_PRIORITY_SCHEDULING > 0
2787+ int status;
2788+
2789+ if (!pcommonAttr->usePolicy) return;
2790+
2791+ status = pthread_attr_getschedparam(
2792+ &pthreadInfo->attr,&pthreadInfo->schedParam);
2793+ checkStatusOnce(status,"pthread_attr_getschedparam");
2794+
2795+ pthreadInfo->schedParam.sched_priority = epicsThreadGetPosixPriority(pthreadInfo);
2796+ pthreadInfo->schedPolicy = policy;
2797+ status = pthread_attr_setschedpolicy(
2798+ &pthreadInfo->attr,policy);
2799+ checkStatusOnce(status,"pthread_attr_setschedpolicy");
2800+
2801+ status = pthread_attr_setschedparam(
2802+ &pthreadInfo->attr,&pthreadInfo->schedParam);
2803+ checkStatusOnce(status,"pthread_attr_setschedparam");
2804+
2805+ status = pthread_attr_setinheritsched(
2806+ &pthreadInfo->attr,PTHREAD_EXPLICIT_SCHED);
2807+ checkStatusOnce(status,"pthread_attr_setinheritsched");
2808+#endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */
2809+}
2810+
2811
2812+static epicsThreadOSD * create_threadInfo(const char *name)
2813+{
2814+ epicsThreadOSD *pthreadInfo;
2815+
2816+ /* sizeof(epicsThreadOSD) includes one byte for the '\0' */
2817+ pthreadInfo = calloc(1,sizeof(*pthreadInfo) + strlen(name));
2818+ if(!pthreadInfo)
2819+ return NULL;
2820+
2821+ pthreadInfo->suspendEvent = epicsEventCreate(epicsEventEmpty);
2822+ if(!pthreadInfo->suspendEvent){
2823+ free(pthreadInfo);
2824+ return NULL;
2825+ }
2826+
2827+ strcpy(pthreadInfo->name, name);
2828+ return pthreadInfo;
2829+}
2830+
2831+static epicsThreadOSD * init_threadInfo(const char *name,
2832+ unsigned int priority, unsigned int stackSize,
2833+ EPICSTHREADFUNC funptr,void *parm)
2834+{
2835+ epicsThreadOSD *pthreadInfo;
2836+ int status;
2837+
2838+ pthreadInfo = create_threadInfo(name);
2839+ if(!pthreadInfo)
2840+ return NULL;
2841+
2842+ pthreadInfo->createFunc = funptr;
2843+ pthreadInfo->createArg = parm;
2844+ status = pthread_attr_init(&pthreadInfo->attr);
2845+ checkStatusOnce(status,"pthread_attr_init");
2846+ if(status) return 0;
2847+
2848+ status = pthread_attr_setdetachstate(
2849+ &pthreadInfo->attr, PTHREAD_CREATE_DETACHED);
2850+ checkStatusOnce(status,"pthread_attr_setdetachstate");
2851+#if defined (_POSIX_THREAD_ATTR_STACKSIZE)
2852+#if ! defined (OSITHREAD_USE_DEFAULT_STACK)
2853+ status = pthread_attr_setstacksize( &pthreadInfo->attr,(size_t)stackSize);
2854+ checkStatusOnce(status,"pthread_attr_setstacksize");
2855+#endif /*OSITHREAD_USE_DEFAULT_STACK*/
2856+#endif /*_POSIX_THREAD_ATTR_STACKSIZE*/
2857+ status = pthread_attr_setscope(&pthreadInfo->attr,PTHREAD_SCOPE_PROCESS);
2858+ if(errVerbose) checkStatusOnce(status,"pthread_attr_setscope");
2859+ pthreadInfo->osiPriority = priority;
2860+#if defined (__rtems__)
2861+ /*
2862+ on rtems startup (posix mode) once get called first
2863+ by POSIX_Global_construction
2864+ -> Thread_Global)construction
2865+ -> ppc_interrupt_disable
2866+ -> init(asm)
2867+ -> __do_global_ctors)aux(asm)
2868+ -> GLOBAL__sub_I_iocshPpdbbase
2869+ -> __static_initialization_adn_destruction_0
2870+ -> IochRegister
2871+ -> localRegister
2872+ -> iocshRegister
2873+ -> iocshTableLock
2874+ -> epicsThreadOnce
2875+ -> epicsThreadInit
2876+ -> Once
2877+ -> once()
2878+ *
2879+ * Then all keys etc. get cleaned and Posix_Init gets called.
2880+ epicsThreadGetIdSelf failed ... createImplicit gets called and
2881+ a new pthreadInfo is created for _main_
2882+
2883+ if (strcmp(name, "_main_")) {
2884+ fprintf(stderr," set _main_ paramtere\n");
2885+ pthreadInfo->isRealTimeScheduled = 1;
2886+ pthreadInfo->isEpicsThread = 1;
2887+ pthreadInfo->tid = pthread_self();
2888+ fprintf(stderr, "tid = 0x%x\n", pthreadInfo->tid);
2889+ pthreadInfo->osiPriority = posixThreadGetOsiPriorityValue(pthreadInfo->tid);
2890+ }
2891+ */
2892+#endif
2893+
2894+ return(pthreadInfo);
2895+}
2896+
2897+static void free_threadInfo(epicsThreadOSD *pthreadInfo)
2898+{
2899+ int status;
2900+
2901+ if(pthreadInfo->isOnThreadList) {
2902+ status = mutexLock(&listLock);
2903+ checkStatusQuit(status,"pthread_mutex_lock","free_threadInfo");
2904+ ellDelete(&pthreadList,&pthreadInfo->node);
2905+ status = pthread_mutex_unlock(&listLock);
2906+ checkStatusQuit(status,"pthread_mutex_unlock","free_threadInfo");
2907+ }
2908+ epicsEventDestroy(pthreadInfo->suspendEvent);
2909+ status = pthread_attr_destroy(&pthreadInfo->attr);
2910+ checkStatusQuit(status,"pthread_attr_destroy","free_threadInfo");
2911+ free(pthreadInfo);
2912+}
2913+
2914
2915+#if defined(_POSIX_THREAD_PRIORITY_SCHEDULING) && _POSIX_THREAD_PRIORITY_SCHEDULING > 0
2916+/*
2917+ * The actually available range priority range (at least under linux)
2918+ * may be restricted by resource limitations (but that is ignored
2919+ * by sched_get_priority_max()). See bug #835138 which is fixed by
2920+ * this code.
2921+ */
2922+static int try_pri(int pri, int policy)
2923+{
2924+struct sched_param schedp;
2925+ schedp.sched_priority = pri;
2926+ return pthread_setschedparam(pthread_self(), policy, &schedp);
2927+}
2928+
2929+static void*
2930+find_pri_range(void *arg)
2931+{
2932+priAvailable *prm = arg;
2933+int min = sched_get_priority_min(prm->policy);
2934+int max = sched_get_priority_max(prm->policy);
2935+int low, try;
2936+
2937+ if ( -1 == min || -1 == max ) {
2938+ /* something is very wrong; maintain old behavior
2939+ * (warning message if sched_get_priority_xxx() fails
2940+ * and use default policy's sched_priority [even if
2941+ * that is likely to cause epicsThreadCreate to fail
2942+ * because that priority is not suitable for SCHED_FIFO]).
2943+ */
2944+ prm->min_pri = prm->max_pri = -1;
2945+ return 0;
2946+ }
2947+
2948+
2949+ if ( try_pri(min, prm->policy) ) {
2950+ /* cannot create thread at minimum priority;
2951+ * probably no permission to use SCHED_FIFO
2952+ * at all. However, we still must return
2953+ * a priority range accepted by the SCHED_FIFO
2954+ * policy. Otherwise, epicsThreadCreate() cannot
2955+ * detect the unsufficient permission (EPERM)
2956+ * and fall back to a non-RT thread (because
2957+ * pthread_attr_setschedparam would fail with
2958+ * EINVAL due to the bad priority).
2959+ */
2960+ prm->min_pri = prm->max_pri = min;
2961+ return 0;
2962+ }
2963+
2964+
2965+ /* Binary search through available priorities.
2966+ * The actually available range may be restricted
2967+ * by resource limitations (but that is ignored
2968+ * by sched_get_priority_max() [linux]).
2969+ */
2970+ low = min;
2971+
2972+ while ( low < max ) {
2973+ try = (max+low)/2;
2974+ if ( try_pri(try, prm->policy) ) {
2975+ max = try;
2976+ } else {
2977+ low = try + 1;
2978+ }
2979+ }
2980+
2981+ prm->min_pri = min;
2982+ prm->max_pri = try_pri(max, prm->policy) ? max-1 : max;
2983+ prm->ok = 1;
2984+
2985+ return 0;
2986+}
2987+
2988+static void findPriorityRange(commonAttr *a_p)
2989+{
2990+priAvailable arg;
2991+pthread_t id;
2992+void *dummy;
2993+int status;
2994+
2995+ arg.policy = a_p->schedPolicy;
2996+ arg.ok = 0;
2997+
2998+ status = pthread_create(&id, 0, find_pri_range, &arg);
2999+ checkStatusOnceQuit(status, "pthread_create","findPriorityRange");
3000+
3001+ status = pthread_join(id, &dummy);
3002+ checkStatusOnceQuit(status, "pthread_join","findPriorityRange");
3003+ a_p->minPriority = arg.min_pri;
3004+ a_p->maxPriority = arg.max_pri;
3005+ a_p->usePolicy = arg.ok;
3006+}
3007+#endif
3008+
3009
3010+
3011+static void once(void)
3012+{
3013+ int status;
3014+ status = pthread_key_create(&getpthreadInfo,0);
3015+ checkStatusOnceQuit(status,"pthread_key_create","once");
3016+ status = pthread_mutex_init(&onceLock,0);
3017+ checkStatusOnceQuit(status,"pthread_mutex_init","once");
3018+ status = pthread_mutex_init(&listLock,0);
3019+ checkStatusOnceQuit(status,"pthread_mutex_init","once");
3020+ pcommonAttr = calloc(1,sizeof(commonAttr));
3021+ if(!pcommonAttr) checkStatusOnceQuit(errno,"calloc","once");
3022+ status = pthread_attr_init(&pcommonAttr->attr);
3023+ checkStatusOnceQuit(status,"pthread_attr_init","once");
3024+ status = pthread_attr_setdetachstate(
3025+ &pcommonAttr->attr, PTHREAD_CREATE_DETACHED);
3026+ checkStatusOnce(status,"pthread_attr_setdetachstate");
3027+ status = pthread_attr_setscope(&pcommonAttr->attr,PTHREAD_SCOPE_PROCESS);
3028+ if(errVerbose) checkStatusOnce(status,"pthread_attr_setscope");
3029+
3030+#if defined(_POSIX_THREAD_PRIORITY_SCHEDULING) && _POSIX_THREAD_PRIORITY_SCHEDULING > 0
3031+ status = pthread_attr_setschedpolicy(
3032+ &pcommonAttr->attr,SCHED_FIFO);
3033+ checkStatusOnce(status,"pthread_attr_setschedpolicy");
3034+ status = pthread_attr_getschedpolicy(
3035+ &pcommonAttr->attr,&pcommonAttr->schedPolicy);
3036+ checkStatusOnce(status,"pthread_attr_getschedpolicy");
3037+ status = pthread_attr_getschedparam(
3038+ &pcommonAttr->attr,&pcommonAttr->schedParam);
3039+ checkStatusOnce(status,"pthread_attr_getschedparam");
3040+
3041+ findPriorityRange(pcommonAttr);
3042+
3043+ if(pcommonAttr->maxPriority == -1) {
3044+ pcommonAttr->maxPriority = pcommonAttr->schedParam.sched_priority;
3045+ fprintf(stderr,"sched_get_priority_max failed set to %d\n",
3046+ pcommonAttr->maxPriority);
3047+ }
3048+ if(pcommonAttr->minPriority == -1) {
3049+ pcommonAttr->minPriority = pcommonAttr->schedParam.sched_priority;
3050+ fprintf(stderr,"sched_get_priority_min failed set to %d\n",
3051+ pcommonAttr->maxPriority);
3052+ }
3053+
3054+ if (errVerbose) {
3055+ fprintf(stderr, "LRT: min priority: %d max priority %d\n",
3056+ pcommonAttr->minPriority, pcommonAttr->maxPriority);
3057+ }
3058+#else
3059+ if(errVerbose) {
3060+ fprintf(stderr,"task priorities are not implemented\n");
3061+ }
3062+#endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */
3063+
3064+#if !defined(__rtems__)
3065+ epicsThreadOSD *pthreadInfo;
3066+ pthreadInfo = init_threadInfo("_main_",0, epicsThreadGetStackSize(epicsThreadStackSmall),0,0);
3067+ assert(pthreadInfo!=NULL);
3068+ status = pthread_setspecific(getpthreadInfo,(void *)pthreadInfo);
3069+ checkStatusOnceQuit(status,"pthread_setspecific","once");
3070+ status = mutexLock(&listLock);
3071+ checkStatusOnceQuit(status,"pthread_mutex_lock","once");
3072+ ellAdd(&pthreadList,&pthreadInfo->node);
3073+ pthreadInfo->isOnThreadList = 1;
3074+ status = pthread_mutex_unlock(&listLock);
3075+ checkStatusOnceQuit(status,"pthread_mutex_unlock","once");
3076+#endif
3077+ status = atexit(epicsExitCallAtExits);
3078+ checkStatusOnce(status,"atexit");
3079+#if !defined(__rtems__)
3080+ osdThreadHooksRunMain(pthreadInfo);
3081+#endif
3082+ epicsThreadOnceCalled = 1;
3083+}
3084+
3085+#if defined(__rtems__)
3086+epicsShareFunc
3087+void rtemsMainInit(int prio)
3088+{
3089+ int status;
3090+ epicsThreadOSD *pthreadInfo;
3091+
3092+ pthreadInfo = init_threadInfo("_main_", prio,
3093+ epicsThreadGetStackSize(epicsThreadStackSmall), 0, 0);
3094+ assert(pthreadInfo!=NULL);
3095+
3096+ pthreadInfo->isRealTimeScheduled = 1;
3097+ pthreadInfo->isEpicsThread = 1;
3098+ pthreadInfo->tid = pthread_self();
3099+ pthreadInfo->osiPriority = posixThreadGetOsiPriorityValue(pthreadInfo->tid);
3100+
3101+ status = pthread_setspecific(getpthreadInfo,(void *)pthreadInfo);
3102+ checkStatusOnceQuit(status,"pthread_setspecific","rtemsMainInit");
3103+
3104+ status = mutexLock(&listLock);
3105+ checkStatusOnceQuit(status,"pthread_mutex_lock","once");
3106+
3107+ ellAdd(&pthreadList,&pthreadInfo->node);
3108+ pthreadInfo->isOnThreadList = 1;
3109+ status = pthread_mutex_unlock(&listLock);
3110+ checkStatusOnceQuit(status,"pthread_mutex_unlock","rtemsMainInit");
3111+}
3112+#endif
3113+
3114+static void * start_routine(void *arg)
3115+{
3116+ epicsThreadOSD *pthreadInfo = (epicsThreadOSD *)arg;
3117+ int status;
3118+ sigset_t blockAllSig;
3119+
3120+ sigfillset(&blockAllSig);
3121+ pthread_sigmask(SIG_SETMASK,&blockAllSig,NULL);
3122+ status = pthread_setspecific(getpthreadInfo,arg);
3123+ checkStatusQuit(status,"pthread_setspecific","start_routine");
3124+ status = mutexLock(&listLock);
3125+ checkStatusQuit(status,"pthread_mutex_lock","start_routine");
3126+ ellAdd(&pthreadList,&pthreadInfo->node);
3127+ pthreadInfo->isOnThreadList = 1;
3128+ status = pthread_mutex_unlock(&listLock);
3129+ checkStatusQuit(status,"pthread_mutex_unlock","start_routine");
3130+ osdThreadHooksRun(pthreadInfo);
3131+
3132+ (*pthreadInfo->createFunc)(pthreadInfo->createArg);
3133+
3134+ epicsExitCallAtThreadExits ();
3135+ free_threadInfo(pthreadInfo);
3136+ return(0);
3137+}
3138+
3139+static void epicsThreadInit(void)
3140+{
3141+ static pthread_once_t once_control = PTHREAD_ONCE_INIT;
3142+ int status = pthread_once(&once_control,once);
3143+ checkStatusQuit(status,"pthread_once","epicsThreadInit");
3144+}
3145+
3146+epicsShareFunc
3147+void epicsThreadRealtimeLock(void)
3148+{
3149+#if defined(_POSIX_MEMLOCK) && _POSIX_MEMLOCK > 0
3150+ if (pcommonAttr->maxPriority > pcommonAttr->minPriority) {
3151+ int status = mlockall(MCL_CURRENT | MCL_FUTURE);
3152+
3153+ if (status) {
3154+ fprintf(stderr, "epicsThreadRealtimeLock "
3155+ "Warning: Unable to lock the virtual address space.\n"
3156+ "VM page faults may harm real-time performance.\n");
3157+ }
3158+ }
3159+#endif
3160+}
3161+
3162+epicsShareFunc unsigned int epicsShareAPI epicsThreadGetStackSize (epicsThreadStackSizeClass stackSizeClass)
3163+{
3164+#if defined (OSITHREAD_USE_DEFAULT_STACK)
3165+ return 0;
3166+#elif defined(_POSIX_THREAD_ATTR_STACKSIZE) && _POSIX_THREAD_ATTR_STACKSIZE > 0
3167+#if defined (__rtems__)
3168+ #define STACK_SIZE(f) (f * 0x1000 * sizeof(void *))
3169+#else
3170+ #define STACK_SIZE(f) (f * 0x10000 * sizeof(void *))
3171+#endif
3172+ static const unsigned stackSizeTable[epicsThreadStackBig+1] = {
3173+ STACK_SIZE(1), STACK_SIZE(2), STACK_SIZE(4)
3174+ };
3175+ if (stackSizeClass<epicsThreadStackSmall) {
3176+ errlogPrintf("epicsThreadGetStackSize illegal argument (too small)");
3177+ return stackSizeTable[epicsThreadStackBig];
3178+ }
3179+
3180+ if (stackSizeClass>epicsThreadStackBig) {
3181+ errlogPrintf("epicsThreadGetStackSize illegal argument (too large)");
3182+ return stackSizeTable[epicsThreadStackBig];
3183+ }
3184+
3185+ return stackSizeTable[stackSizeClass];
3186+#else
3187+ return 0;
3188+#endif /*_POSIX_THREAD_ATTR_STACKSIZE*/
3189+}
3190+
3191
3192+epicsShareFunc void epicsShareAPI epicsThreadOnce(epicsThreadOnceId *id, void (*func)(void *), void *arg)
3193+{
3194+ static struct epicsThreadOSD threadOnceComplete;
3195+ #define EPICS_THREAD_ONCE_DONE &threadOnceComplete
3196+ int status;
3197+
3198+ epicsThreadInit();
3199+ status = mutexLock(&onceLock);
3200+ if(status) {
3201+ fprintf(stderr,"epicsThreadOnce: pthread_mutex_lock returned %s.\n",
3202+ strerror(status));
3203+ exit(-1);
3204+ }
3205+
3206+ if (*id != EPICS_THREAD_ONCE_DONE) {
3207+ if (*id == EPICS_THREAD_ONCE_INIT) { /* first call */
3208+ *id = epicsThreadGetIdSelf(); /* mark active */
3209+ status = pthread_mutex_unlock(&onceLock);
3210+ checkStatusOnceQuit(status,"pthread_mutex_unlock", "epicsThreadOnce");
3211+ func(arg);
3212+ status = mutexLock(&onceLock);
3213+ checkStatusOnceQuit(status,"pthread_mutex_lock", "epicsThreadOnce");
3214+ *id = EPICS_THREAD_ONCE_DONE; /* mark done */
3215+ } else if (*id == epicsThreadGetIdSelf()) {
3216+ status = pthread_mutex_unlock(&onceLock);
3217+ checkStatusOnceQuit(status,"pthread_mutex_unlock", "epicsThreadOnce");
3218+ cantProceed("Recursive epicsThreadOnce() initialization\n");
3219+ } else
3220+ while (*id != EPICS_THREAD_ONCE_DONE) {
3221+ /* Another thread is in the above func(arg) call. */
3222+ status = pthread_mutex_unlock(&onceLock);
3223+ checkStatusOnceQuit(status,"pthread_mutex_unlock", "epicsThreadOnce");
3224+ epicsThreadSleep(epicsThreadSleepQuantum());
3225+ status = mutexLock(&onceLock);
3226+ checkStatusOnceQuit(status,"pthread_mutex_lock", "epicsThreadOnce");
3227+ }
3228+ }
3229+ status = pthread_mutex_unlock(&onceLock);
3230+ checkStatusOnceQuit(status,"pthread_mutex_unlock","epicsThreadOnce");
3231+}
3232+
3233+epicsShareFunc epicsThreadId epicsShareAPI epicsThreadCreate(const char *name,
3234+ unsigned int priority, unsigned int stackSize,
3235+ EPICSTHREADFUNC funptr,void *parm)
3236+{
3237+ epicsThreadOSD *pthreadInfo;
3238+ int status;
3239+ sigset_t blockAllSig, oldSig;
3240+
3241+ epicsThreadInit();
3242+ assert(pcommonAttr);
3243+ sigfillset(&blockAllSig);
3244+ pthread_sigmask(SIG_SETMASK,&blockAllSig,&oldSig);
3245+ pthreadInfo = init_threadInfo(name,priority,stackSize,funptr,parm);
3246+ if(pthreadInfo==0) return 0;
3247+ pthreadInfo->isEpicsThread = 1;
3248+ setSchedulingPolicy(pthreadInfo,SCHED_FIFO);
3249+ pthreadInfo->isRealTimeScheduled = 1;
3250+ status = pthread_create(&pthreadInfo->tid,&pthreadInfo->attr,
3251+ start_routine,pthreadInfo);
3252+ if(status==EPERM){
3253+ /* Try again without SCHED_FIFO*/
3254+ free_threadInfo(pthreadInfo);
3255+ pthreadInfo = init_threadInfo(name,priority,stackSize,funptr,parm);
3256+ if(pthreadInfo==0) return 0;
3257+ pthreadInfo->isEpicsThread = 1;
3258+ status = pthread_create(&pthreadInfo->tid,&pthreadInfo->attr,
3259+ start_routine,pthreadInfo);
3260+ }
3261+ checkStatusOnce(status,"pthread_create");
3262+ if(status) {
3263+ free_threadInfo(pthreadInfo);
3264+ return 0;
3265+ }
3266+ status = pthread_sigmask(SIG_SETMASK,&oldSig,NULL);
3267+ checkStatusOnce(status,"pthread_sigmask");
3268+ return(pthreadInfo);
3269+}
3270+
3271+/*
3272+ * Create dummy context for threads not created by epicsThreadCreate().
3273+ */
3274+static epicsThreadOSD *createImplicit(void)
3275+{
3276+ epicsThreadOSD *pthreadInfo;
3277+ char name[64];
3278+ pthread_t tid;
3279+ int status;
3280+
3281+ tid = pthread_self();
3282+ sprintf(name, "non-EPICS_%08ld", (long)tid);
3283+ pthreadInfo = create_threadInfo(name);
3284+ assert(pthreadInfo);
3285+ pthreadInfo->tid = tid;
3286+#if defined(__rtems__)
3287+ pthreadInfo->osiPriority = posixThreadGetOsiPriorityValue(tid);
3288+#endif
3289+ status = pthread_setspecific(getpthreadInfo,(void *)pthreadInfo);
3290+ checkStatus(status,"pthread_setspecific createImplicit");
3291+ if(status){
3292+ free_threadInfo(pthreadInfo);
3293+ return NULL;
3294+ }
3295+ return pthreadInfo;
3296+}
3297+
3298
3299+epicsShareFunc void epicsShareAPI epicsThreadSuspendSelf(void)
3300+{
3301+ epicsThreadOSD *pthreadInfo;
3302+
3303+ epicsThreadInit();
3304+ pthreadInfo = (epicsThreadOSD *)pthread_getspecific(getpthreadInfo);
3305+ if(pthreadInfo==NULL)
3306+ pthreadInfo = createImplicit();
3307+ pthreadInfo->isSuspended = 1;
3308+ epicsEventWait(pthreadInfo->suspendEvent);
3309+}
3310+
3311+epicsShareFunc void epicsShareAPI epicsThreadResume(epicsThreadOSD *pthreadInfo)
3312+{
3313+ assert(epicsThreadOnceCalled);
3314+ pthreadInfo->isSuspended = 0;
3315+ epicsEventSignal(pthreadInfo->suspendEvent);
3316+}
3317+
3318+epicsShareFunc void epicsShareAPI epicsThreadExitMain(void)
3319+{
3320+ epicsThreadOSD *pthreadInfo;
3321+
3322+ epicsThreadInit();
3323+ pthreadInfo = (epicsThreadOSD *)pthread_getspecific(getpthreadInfo);
3324+ if(pthreadInfo==NULL)
3325+ pthreadInfo = createImplicit();
3326+ if(pthreadInfo->createFunc) {
3327+ errlogPrintf("called from non-main thread\n");
3328+ cantProceed("epicsThreadExitMain");
3329+ }
3330+ else {
3331+ free_threadInfo(pthreadInfo);
3332+ pthread_exit(0);
3333+ }
3334+}
3335+
3336+epicsShareFunc int posixThreadGetOsiPriorityValue(pthread_t tid)
3337+{
3338+ #if defined(_POSIX_THREAD_PRIORITY_SCHEDULING) && _POSIX_THREAD_PRIORITY_SCHEDULING > 0
3339+ struct sched_param param;
3340+ int policy;
3341+
3342+ if (pthread_getschedparam(tid,&policy,&param) == 0) {
3343+ return (param.sched_priority - pcommonAttr->minPriority) * 100.0 /
3344+ (pcommonAttr->maxPriority - pcommonAttr->minPriority + 1);
3345+ }
3346+#endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */
3347+ return 0;
3348+}
3349+
3350+epicsShareFunc int epicsThreadGetPosixPriorityValue(int osiPriority)
3351+{
3352+#if defined(_POSIX_THREAD_PRIORITY_SCHEDULING) && _POSIX_THREAD_PRIORITY_SCHEDULING > 0
3353+ double maxPriority, minPriority, slope, posixPrio;
3354+
3355+ if (pcommonAttr->maxPriority==pcommonAttr->minPriority)
3356+ return pcommonAttr->maxPriority;
3357+
3358+ maxPriority = (double)pcommonAttr->maxPriority;
3359+ minPriority = (double)pcommonAttr->minPriority;
3360+ slope = (maxPriority - minPriority)/100.0;
3361+ posixPrio = (double)osiPriority * slope + minPriority;
3362+ return (int) posixPrio;
3363+#else
3364+ return 0;
3365+#endif
3366+}
3367+
3368+epicsShareFunc unsigned int epicsShareAPI epicsThreadGetPosixMaxPriorityValue()
3369+{
3370+#if defined(_POSIX_THREAD_PRIORITY_SCHEDULING) && _POSIX_THREAD_PRIORITY_SCHEDULING > 0
3371+ return pcommonAttr->maxPriority;
3372+#else
3373+ return 0;
3374+#endif
3375+}
3376+epicsShareFunc unsigned int epicsShareAPI epicsThreadGetPosixMinPriorityValue()
3377+{
3378+#if defined(_POSIX_THREAD_PRIORITY_SCHEDULING) && _POSIX_THREAD_PRIORITY_SCHEDULING > 0
3379+ return pcommonAttr->minPriority;
3380+#else
3381+ return 0;
3382+#endif
3383+}
3384+
3385+epicsShareFunc unsigned int epicsShareAPI epicsThreadGetPriority(epicsThreadId pthreadInfo)
3386+{
3387+ assert(epicsThreadOnceCalled);
3388+ return pthreadInfo->osiPriority;
3389+}
3390+
3391+epicsShareFunc unsigned int epicsShareAPI epicsThreadGetPrioritySelf(void)
3392+{
3393+ epicsThreadInit();
3394+ return epicsThreadGetPriority(epicsThreadGetIdSelf());
3395+}
3396+
3397+epicsShareFunc void epicsShareAPI epicsThreadSetPriority(epicsThreadId pthreadInfo,unsigned int priority)
3398+{
3399+#if defined(_POSIX_THREAD_PRIORITY_SCHEDULING) && _POSIX_THREAD_PRIORITY_SCHEDULING > 0
3400+ int status;
3401+#endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */
3402+
3403+ assert(epicsThreadOnceCalled);
3404+ assert(pthreadInfo);
3405+
3406+#if !defined (__rtems__)
3407+ if (!pthreadInfo->isEpicsThread) {
3408+ fprintf(stderr, "epicsThreadSetPriority called for non-EPICS thread\n");
3409+ return;
3410+ }
3411+#endif
3412+ pthreadInfo->osiPriority = priority;
3413+ if (!pthreadInfo->isRealTimeScheduled) return;
3414+
3415+#if defined (_POSIX_THREAD_PRIORITY_SCHEDULING) && _POSIX_THREAD_PRIORITY_SCHEDULING > 0
3416+ if(!pcommonAttr->usePolicy) return;
3417+ pthreadInfo->schedParam.sched_priority = epicsThreadGetPosixPriority(pthreadInfo);
3418+ status = pthread_attr_setschedparam(
3419+ &pthreadInfo->attr,&pthreadInfo->schedParam);
3420+ if(errVerbose) checkStatus(status,"pthread_attr_setschedparam");
3421+ status = pthread_setschedparam(
3422+ pthreadInfo->tid, pthreadInfo->schedPolicy, &pthreadInfo->schedParam);
3423+ if(errVerbose) checkStatus(status,"pthread_setschedparam");
3424+#endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */
3425+}
3426+
3427+epicsShareFunc epicsThreadBooleanStatus epicsShareAPI epicsThreadHighestPriorityLevelBelow(
3428+ unsigned int priority, unsigned *pPriorityJustBelow)
3429+{
3430+ unsigned newPriority = priority - 1;
3431+
3432+ epicsThreadInit();
3433+ assert(pcommonAttr);
3434+
3435+#if defined(_POSIX_THREAD_PRIORITY_SCHEDULING) && _POSIX_THREAD_PRIORITY_SCHEDULING > 0
3436+ int diff;
3437+ diff = pcommonAttr->maxPriority - pcommonAttr->minPriority;
3438+ if(diff<0) diff = -diff;
3439+ if(diff>1 && diff <100) newPriority -= 100/(diff+1);
3440+#endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */
3441+ if (newPriority <= 99) {
3442+ *pPriorityJustBelow = newPriority;
3443+ return epicsThreadBooleanStatusSuccess;
3444+ }
3445+ return epicsThreadBooleanStatusFail;
3446+}
3447+
3448+epicsShareFunc epicsThreadBooleanStatus epicsShareAPI epicsThreadLowestPriorityLevelAbove(
3449+ unsigned int priority, unsigned *pPriorityJustAbove)
3450+{
3451+ unsigned newPriority = priority + 1;
3452+
3453+ epicsThreadInit();
3454+ assert(pcommonAttr);
3455+
3456+#if defined(_POSIX_THREAD_PRIORITY_SCHEDULING) && _POSIX_THREAD_PRIORITY_SCHEDULING > 0
3457+ int diff;
3458+ diff = pcommonAttr->maxPriority - pcommonAttr->minPriority;
3459+ if(diff<0) diff = -diff;
3460+ if(diff>1 && diff <100) newPriority += 100/(diff+1);
3461+#endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */
3462+
3463+ if (newPriority <= 99) {
3464+ *pPriorityJustAbove = newPriority;
3465+ return epicsThreadBooleanStatusSuccess;
3466+ }
3467+ return epicsThreadBooleanStatusFail;
3468+}
3469+
3470
3471+epicsShareFunc int epicsShareAPI epicsThreadIsEqual(epicsThreadId p1, epicsThreadId p2)
3472+{
3473+ assert(epicsThreadOnceCalled);
3474+ assert(p1);
3475+ assert(p2);
3476+ return(pthread_equal(p1->tid,p2->tid));
3477+}
3478+
3479+epicsShareFunc int epicsShareAPI epicsThreadIsSuspended(epicsThreadId pthreadInfo) {
3480+ assert(epicsThreadOnceCalled);
3481+ assert(pthreadInfo);
3482+ return(pthreadInfo->isSuspended ? 1 : 0);
3483+}
3484+
3485+epicsShareFunc void epicsShareAPI epicsThreadSleep(double seconds)
3486+{
3487+ struct timespec delayTime;
3488+ struct timespec remainingTime;
3489+ double nanoseconds;
3490+
3491+ if (seconds > 0) {
3492+ delayTime.tv_sec = seconds;
3493+ nanoseconds = (seconds - delayTime.tv_sec) *1e9;
3494+ delayTime.tv_nsec = nanoseconds;
3495+ }
3496+ else {
3497+ delayTime.tv_sec = 0;
3498+ delayTime.tv_nsec = 0;
3499+ }
3500+ while (nanosleep(&delayTime, &remainingTime) == -1 &&
3501+ errno == EINTR)
3502+ delayTime = remainingTime;
3503+}
3504+
3505+epicsShareFunc epicsThreadId epicsShareAPI epicsThreadGetIdSelf(void) {
3506+ epicsThreadOSD *pthreadInfo;
3507+
3508+ epicsThreadInit();
3509+ pthreadInfo = (epicsThreadOSD *)pthread_getspecific(getpthreadInfo);
3510+ if(pthreadInfo==NULL)
3511+ pthreadInfo = createImplicit();
3512+ assert( pthreadInfo );
3513+ return(pthreadInfo);
3514+}
3515+
3516+epicsShareFunc pthread_t epicsThreadGetPosixThreadId ( epicsThreadId threadId )
3517+{
3518+ return threadId->tid;
3519+}
3520+
3521+epicsShareFunc epicsThreadId epicsShareAPI epicsThreadGetId(const char *name) {
3522+ epicsThreadOSD *pthreadInfo;
3523+ int status;
3524+
3525+ assert(epicsThreadOnceCalled);
3526+ status = mutexLock(&listLock);
3527+ checkStatus(status,"pthread_mutex_lock epicsThreadGetId");
3528+ if(status)
3529+ return NULL;
3530+ pthreadInfo=(epicsThreadOSD *)ellFirst(&pthreadList);
3531+ while (pthreadInfo) {
3532+ if (strcmp(name,pthreadInfo->name) == 0) break;
3533+ pthreadInfo = (epicsThreadOSD *)ellNext(&pthreadInfo->node);
3534+ }
3535+ status = pthread_mutex_unlock(&listLock);
3536+ checkStatus(status,"pthread_mutex_unlock epicsThreadGetId");
3537+
3538+ return(pthreadInfo);
3539+}
3540+
3541+epicsShareFunc const char epicsShareAPI *epicsThreadGetNameSelf()
3542+{
3543+ epicsThreadOSD *pthreadInfo;
3544+
3545+ epicsThreadInit();
3546+ pthreadInfo=(epicsThreadOSD *)pthread_getspecific(getpthreadInfo);
3547+ if(pthreadInfo==NULL)
3548+ pthreadInfo = createImplicit();
3549+ return(pthreadInfo->name);
3550+}
3551+
3552+epicsShareFunc void epicsShareAPI epicsThreadGetName(epicsThreadId pthreadInfo, char *name, size_t size)
3553+{
3554+ assert(epicsThreadOnceCalled);
3555+ strncpy(name, pthreadInfo->name, size-1);
3556+ name[size-1] = '\0';
3557+}
3558+
3559
3560+epicsShareFunc void epicsThreadMap(EPICS_THREAD_HOOK_ROUTINE func)
3561+{
3562+ epicsThreadOSD *pthreadInfo;
3563+ int status;
3564+
3565+ epicsThreadInit();
3566+ status = mutexLock(&listLock);
3567+ checkStatus(status, "pthread_mutex_lock epicsThreadMap");
3568+ if (status)
3569+ return;
3570+ pthreadInfo=(epicsThreadOSD *)ellFirst(&pthreadList);
3571+ while (pthreadInfo) {
3572+ func(pthreadInfo);
3573+ pthreadInfo = (epicsThreadOSD *)ellNext(&pthreadInfo->node);
3574+ }
3575+ status = pthread_mutex_unlock(&listLock);
3576+ checkStatus(status, "pthread_mutex_unlock epicsThreadMap");
3577+}
3578+
3579+epicsShareFunc void epicsShareAPI epicsThreadShowAll(unsigned int level)
3580+{
3581+ epicsThreadOSD *pthreadInfo;
3582+ int status;
3583+
3584+ epicsThreadInit();
3585+ epicsThreadShow(0,level);
3586+ status = mutexLock(&listLock);
3587+ checkStatus(status,"pthread_mutex_lock epicsThreadShowAll");
3588+ if(status)
3589+ return;
3590+ pthreadInfo=(epicsThreadOSD *)ellFirst(&pthreadList);
3591+ while(pthreadInfo) {
3592+ epicsThreadShowInfo(pthreadInfo,level);
3593+ pthreadInfo=(epicsThreadOSD *)ellNext(&pthreadInfo->node);
3594+ }
3595+ status = pthread_mutex_unlock(&listLock);
3596+ checkStatus(status,"pthread_mutex_unlock epicsThreadShowAll");
3597+}
3598+
3599+epicsShareFunc void epicsShareAPI epicsThreadShow(epicsThreadId showThread, unsigned int level)
3600+{
3601+ epicsThreadOSD *pthreadInfo;
3602+ int status;
3603+ int found = 0;
3604+
3605+ epicsThreadInit();
3606+ if(!showThread) {
3607+ epicsThreadShowInfo(0,level);
3608+ return;
3609+ }
3610+ status = mutexLock(&listLock);
3611+ checkStatus(status,"pthread_mutex_lock epicsThreadShow");
3612+ if(status)
3613+ return;
3614+ pthreadInfo=(epicsThreadOSD *)ellFirst(&pthreadList);
3615+ while(pthreadInfo) {
3616+ if (((epicsThreadId)pthreadInfo == showThread)
3617+ || ((epicsThreadId)pthreadInfo->tid == showThread)) {
3618+ found = 1;
3619+ epicsThreadShowInfo(pthreadInfo,level);
3620+ }
3621+ pthreadInfo=(epicsThreadOSD *)ellNext(&pthreadInfo->node);
3622+ }
3623+ status = pthread_mutex_unlock(&listLock);
3624+ checkStatus(status,"pthread_mutex_unlock epicsThreadShow");
3625+ if(status) return;
3626+ if (!found)
3627+ printf("Thread %#lx (%lu) not found.\n", (unsigned long)showThread, (unsigned long)showThread);
3628+}
3629+
3630
3631+epicsShareFunc epicsThreadPrivateId epicsShareAPI epicsThreadPrivateCreate(void)
3632+{
3633+ pthread_key_t *key;
3634+ int status;
3635+
3636+ epicsThreadInit();
3637+ key = calloc(1,sizeof(pthread_key_t));
3638+ if(!key)
3639+ return NULL;
3640+ status = pthread_key_create(key,0);
3641+ checkStatus(status,"pthread_key_create epicsThreadPrivateCreate");
3642+ if(status)
3643+ return NULL;
3644+ return((epicsThreadPrivateId)key);
3645+}
3646+
3647+epicsShareFunc void epicsShareAPI epicsThreadPrivateDelete(epicsThreadPrivateId id)
3648+{
3649+ pthread_key_t *key = (pthread_key_t *)id;
3650+ int status;
3651+
3652+ assert(epicsThreadOnceCalled);
3653+ status = pthread_key_delete(*key);
3654+ checkStatusQuit(status,"pthread_key_delete","epicsThreadPrivateDelete");
3655+ free((void *)key);
3656+}
3657+
3658+epicsShareFunc void epicsShareAPI epicsThreadPrivateSet (epicsThreadPrivateId id, void *value)
3659+{
3660+ pthread_key_t *key = (pthread_key_t *)id;
3661+ int status;
3662+
3663+ assert(epicsThreadOnceCalled);
3664+ if(errVerbose && !value)
3665+ errlogPrintf("epicsThreadPrivateSet: setting value of 0\n");
3666+ status = pthread_setspecific(*key,value);
3667+ checkStatusQuit(status,"pthread_setspecific","epicsThreadPrivateSet");
3668+}
3669+
3670+epicsShareFunc void epicsShareAPI *epicsThreadPrivateGet(epicsThreadPrivateId id)
3671+{
3672+ pthread_key_t *key = (pthread_key_t *)id;
3673+
3674+ assert(epicsThreadOnceCalled);
3675+ return pthread_getspecific(*key);
3676+}
3677+
3678+epicsShareFunc double epicsShareAPI epicsThreadSleepQuantum ()
3679+{
3680+ double hz;
3681+ hz = sysconf ( _SC_CLK_TCK );
3682+ if(hz<0)
3683+ return 0.0;
3684+ return 1.0 / hz;
3685+}
3686+
3687+epicsShareFunc int epicsThreadGetCPUs(void)
3688+{
3689+ long ret;
3690+#ifdef _SC_NPROCESSORS_ONLN
3691+ ret = sysconf(_SC_NPROCESSORS_ONLN);
3692+ if (ret > 0)
3693+ return ret;
3694+#endif
3695+#ifdef _SC_NPROCESSORS_CONF
3696+ ret = sysconf(_SC_NPROCESSORS_CONF);
3697+ if (ret > 0)
3698+ return ret;
3699+#endif
3700+ return 1;
3701+}
3702diff --git a/src/osi/os/RTEMS-posix/osdThread.h b/src/osi/os/RTEMS-posix/osdThread.h
3703new file mode 100644
3704index 0000000..ac27ff0
3705--- /dev/null
3706+++ b/src/osi/os/RTEMS-posix/osdThread.h
3707@@ -0,0 +1,55 @@
3708+/*************************************************************************\
3709+* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
3710+* National Laboratory.
3711+* Copyright (c) 2002 The Regents of the University of California, as
3712+* Operator of Los Alamos National Laboratory.
3713+* EPICS BASE Versions 3.13.7
3714+* and higher are distributed subject to a Software License Agreement found
3715+* in file LICENSE that is included with this distribution.
3716+\*************************************************************************/
3717+#ifndef osdThreadh
3718+#define osdThreadh
3719+
3720+#include <pthread.h>
3721+
3722+#include "shareLib.h"
3723+#include "ellLib.h"
3724+#include "epicsEvent.h"
3725+
3726+#ifdef __cplusplus
3727+extern "C" {
3728+#endif
3729+
3730+typedef struct epicsThreadOSD {
3731+ ELLNODE node;
3732+ pthread_t tid;
3733+ pthread_attr_t attr;
3734+ struct sched_param schedParam;
3735+ int schedPolicy;
3736+ EPICSTHREADFUNC createFunc;
3737+ void *createArg;
3738+ epicsEventId suspendEvent;
3739+ int isSuspended;
3740+ int isEpicsThread;
3741+ int isRealTimeScheduled;
3742+ int isOnThreadList;
3743+ unsigned int osiPriority;
3744+ char name[1]; /* actually larger */
3745+} epicsThreadOSD;
3746+
3747+epicsShareFunc pthread_t epicsThreadGetPosixThreadId(epicsThreadId id);
3748+epicsShareFunc int epicsThreadGetPosixPriority(epicsThreadId id);
3749+epicsShareFunc int epicsThreadGetPosixPriorityValue(int osiPriority);
3750+epicsShareFunc int posixThreadGetOsiPriorityValue(pthread_t tid);
3751+epicsShareFunc unsigned int epicsShareAPI epicsThreadGetPosixMaxPriorityValue();
3752+epicsShareFunc unsigned int epicsShareAPI epicsThreadGetPosixMinPriorityValue();
3753+
3754+#if defined(__rtems__)
3755+epicsShareFunc void rtemsMainInit(int prio);
3756+#endif
3757+
3758+#ifdef __cplusplus
3759+}
3760+#endif
3761+
3762+#endif /* osdThreadh */

Subscribers

People subscribed via source and target branches