* [Xenomai-core] Ipipe and Siemens A&D Realtime
@ 2007-04-18 15:07 Krause, Karl-Heinz
2007-04-18 17:53 ` Jan Kiszka
0 siblings, 1 reply; 7+ messages in thread
From: Krause, Karl-Heinz @ 2007-04-18 15:07 UTC (permalink / raw)
To: xenomai, xenomai
[-- Attachment #1.1: Type: text/plain, Size: 1537 bytes --]
Hi Philippe
as promised some time ago, I'd like to let you know the result of our work.
Attached are
- a few recycled slides from a presentation describing motivation, features and results
- the patch file for a adeos-ipipe-2.6.15-i386-1.3-04.patch patched kernel2.6.15.4
Since some parts of the kernel functionality (clock registration, realtime capable message queues) and
most parts of the glibc changes are also of interest for the RT_PREEMPT solution we are in contact with
Thomas Gleixner trying to leverage the work.
An update to newer versions of kernel and glibc (basically because of the PI mutexes) is planned for later,
presumably when RT_PREEMPT has become mainline status.
If you need any further information just let me know.
Karl-Heinz
Karl-Heinz Krause
Siemens AG
Automation and Drives
Advanced Technologies and Standards
A&D ATS 1
Gleiwitzer Str. 555
90475 Nürnberg, Germany
Tel.: +49 911 895-3179
Fax: +49 911 895-3715
mailto:karl-heinz.krause@domain.hid <mailto:karl-heinz.krause@domain.hid>
Siemens Aktiengesellschaft: Vorsitzender des Aufsichtsrats: Heinrich v. Pierer;
Vorstand: Klaus Kleinfeld, Vorsitzender; Johannes Feldmayer, Joe Kaeser,
Rudi Lamprecht, Eduardo Montes, Jürgen Radomski, Erich R. Reinhardt,
Hermann Requardt, Uriel J. Sharef, Klaus Wucherer
Sitz der Gesellschaft: Berlin und München
Registergericht: Berlin Charlottenburg, HRB 12300, München, HRB 6684
WEEE-Reg.-Nr. DE 23691322
[-- Attachment #1.2: Type: text/html, Size: 6740 bytes --]
[-- Attachment #2: aud_glibc.patch --]
[-- Type: application/octet-stream, Size: 120721 bytes --]
diff -Naur glibc-2.3.6_Cs/abilist/libpthread.abilist glibc-2.3.6-AuD/abilist/libpthread.abilist
--- glibc-2.3.6_Cs/abilist/libpthread.abilist 2005-01-20 03:18:22.000000000 +0100
+++ glibc-2.3.6-AuD/abilist/libpthread.abilist 2006-10-06 18:38:04.000000000 +0200
@@ -225,6 +225,10 @@
pthread_mutex_timedlock F
pthread_mutexattr_getpshared F
pthread_mutexattr_setpshared F
+ pthread_mutexattr_getprioceiling F
+ pthread_mutexattr_setprioceiling F
+ pthread_mutexattr_getprotocol F
+ pthread_mutexattr_setprotocol F
pthread_rwlock_timedrdlock F
pthread_rwlock_timedwrlock F
pthread_spin_destroy F
diff -Naur glibc-2.3.6_Cs/abilist/librt.abilist glibc-2.3.6-AuD/abilist/librt.abilist
--- glibc-2.3.6_Cs/abilist/librt.abilist 2005-01-20 03:18:22.000000000 +0100
+++ glibc-2.3.6-AuD/abilist/librt.abilist 2007-02-20 11:51:44.000000000 +0100
@@ -38,6 +38,10 @@
timer_getoverrun F
timer_gettime F
timer_settime F
+ event_create F
+ sigevent_set_notification F
+ register_clock F
+ convtime F
GLIBC_2.2 i.86-.*-linux.*/notls i.86-.*-linux.*/thread i.86-.*-linux.*/tls ia64-.*-linux.*/tls m68.*-.*-linux.*/notls powerpc-.*-linux.*/notls powerpc-.*-linux.*/thread powerpc-.*-linux.*/tls s390-.*-linux.*/tls s390x-.*-linux.*/tls sh[34].*-.*-linux.*/notls sh[34].*-.*-linux.*/thread sh[34].*-.*-linux.*/tls
GLIBC_2.2 A
GLIBC_2.3 powerpc64-.*-linux.*/thread
diff -Naur glibc-2.3.6_Cs/misc/daemon.c glibc-2.3.6-AuD/misc/daemon.c
--- glibc-2.3.6_Cs/misc/daemon.c 2005-01-20 03:18:36.000000000 +0100
+++ glibc-2.3.6-AuD/misc/daemon.c 2007-03-05 16:34:20.000000000 +0100
@@ -46,7 +46,11 @@
{
int fd;
+#ifdef CONFIG_NOMMU_USE_LOW_ADDR
+ switch (__vfork()) {
+#else
switch (__fork()) {
+#endif
case -1:
return (-1);
case 0:
diff -Naur glibc-2.3.6_Cs/nptl/Makefile glibc-2.3.6-AuD/nptl/Makefile
--- glibc-2.3.6_Cs/nptl/Makefile 2005-11-09 05:04:41.000000000 +0100
+++ glibc-2.3.6-AuD/nptl/Makefile 2006-10-05 10:59:56.000000000 +0200
@@ -56,6 +56,10 @@
pthread_mutexattr_getpshared \
pthread_mutexattr_setpshared \
pthread_mutexattr_gettype pthread_mutexattr_settype \
+ pthread_mutexattr_getprioceiling \
+ pthread_mutexattr_setprioceiling \
+ pthread_mutexattr_getprotocol \
+ pthread_mutexattr_setprotocol \
pthread_rwlock_init pthread_rwlock_destroy \
pthread_rwlock_rdlock pthread_rwlock_timedrdlock \
pthread_rwlock_wrlock pthread_rwlock_timedwrlock \
diff -Naur glibc-2.3.6_Cs/nptl/pthread_mutexattr_getprioceiling.c glibc-2.3.6-AuD/nptl/pthread_mutexattr_getprioceiling.c
--- glibc-2.3.6_Cs/nptl/pthread_mutexattr_getprioceiling.c 1970-01-01 01:00:00.000000000 +0100
+++ glibc-2.3.6-AuD/nptl/pthread_mutexattr_getprioceiling.c 2006-03-06 18:20:46.000000000 +0100
@@ -0,0 +1,37 @@
+/* Get priority ceiling setting from pthread_mutexattr_t.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Jakub Jelinek <jakub@redhat.com>, 2006.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <pthreadP.h>
+
+
+int
+pthread_mutexattr_getprioceiling (attr, prioceiling)
+ const pthread_mutexattr_t *attr;
+ int *prioceiling;
+{
+ const struct pthread_mutexattr *iattr;
+
+ iattr = (const struct pthread_mutexattr *) attr;
+
+ *prioceiling = ((iattr->mutexkind & PTHREAD_MUTEXATTR_PRIO_CEILING_MASK)
+ >> PTHREAD_MUTEXATTR_PRIO_CEILING_SHIFT);
+
+ return 0;
+}
diff -Naur glibc-2.3.6_Cs/nptl/pthread_mutexattr_getprotocol.c glibc-2.3.6-AuD/nptl/pthread_mutexattr_getprotocol.c
--- glibc-2.3.6_Cs/nptl/pthread_mutexattr_getprotocol.c 1970-01-01 01:00:00.000000000 +0100
+++ glibc-2.3.6-AuD/nptl/pthread_mutexattr_getprotocol.c 2006-03-06 18:20:46.000000000 +0100
@@ -0,0 +1,37 @@
+/* Get priority protocol setting from pthread_mutexattr_t.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Jakub Jelinek <jakub@redhat.com>, 2006.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <pthreadP.h>
+
+
+int
+pthread_mutexattr_getprotocol (attr, protocol)
+ const pthread_mutexattr_t *attr;
+ int *protocol;
+{
+ const struct pthread_mutexattr *iattr;
+
+ iattr = (const struct pthread_mutexattr *) attr;
+
+ *protocol = ((iattr->mutexkind & PTHREAD_MUTEXATTR_PROTOCOL_MASK)
+ >> PTHREAD_MUTEXATTR_PROTOCOL_SHIFT);
+
+ return 0;
+}
diff -Naur glibc-2.3.6_Cs/nptl/pthread_mutexattr_gettype.c glibc-2.3.6-AuD/nptl/pthread_mutexattr_gettype.c
--- glibc-2.3.6_Cs/nptl/pthread_mutexattr_gettype.c 2005-01-20 03:18:36.000000000 +0100
+++ glibc-2.3.6-AuD/nptl/pthread_mutexattr_gettype.c 2006-10-05 13:33:20.000000000 +0200
@@ -31,7 +31,12 @@
/* We use bit 31 to signal whether the mutex is going to be
process-shared or not. */
+ /*
+ * m.n. siemens ag mutexkind element is also used for prioceiling and protocol
+ *
*kind = iattr->mutexkind & ~0x80000000;
+ */
+ *kind = iattr->mutexkind & PTHREAD_MUTEXATTR_TYPE_MASK;
return 0;
}
diff -Naur glibc-2.3.6_Cs/nptl/pthread_mutexattr_setprioceiling.c glibc-2.3.6-AuD/nptl/pthread_mutexattr_setprioceiling.c
--- glibc-2.3.6_Cs/nptl/pthread_mutexattr_setprioceiling.c 1970-01-01 01:00:00.000000000 +0100
+++ glibc-2.3.6-AuD/nptl/pthread_mutexattr_setprioceiling.c 2006-10-06 18:13:16.000000000 +0200
@@ -0,0 +1,40 @@
+/* Change priority ceiling setting in pthread_mutexattr_t.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Jakub Jelinek <jakub@redhat.com>, 2006.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <pthreadP.h>
+
+
+int
+pthread_mutexattr_setprioceiling (attr, prioceiling)
+ pthread_mutexattr_t *attr;
+ int prioceiling;
+{
+ if (prioceiling < 0 || __builtin_expect (prioceiling > 255, 0))
+ return EINVAL;
+
+ struct pthread_mutexattr *iattr = (struct pthread_mutexattr *) attr;
+
+ iattr->mutexkind = ((iattr->mutexkind & ~PTHREAD_MUTEXATTR_PRIO_CEILING_MASK)
+ | (prioceiling << PTHREAD_MUTEXATTR_PRIO_CEILING_SHIFT));
+
+ return 0;
+}
+
diff -Naur glibc-2.3.6_Cs/nptl/pthread_mutexattr_setprotocol.c glibc-2.3.6-AuD/nptl/pthread_mutexattr_setprotocol.c
--- glibc-2.3.6_Cs/nptl/pthread_mutexattr_setprotocol.c 1970-01-01 01:00:00.000000000 +0100
+++ glibc-2.3.6-AuD/nptl/pthread_mutexattr_setprotocol.c 2006-10-06 18:13:03.000000000 +0200
@@ -0,0 +1,41 @@
+/* Change priority protocol setting in pthread_mutexattr_t.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Jakub Jelinek <jakub@redhat.com>, 2006.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <pthreadP.h>
+
+int
+pthread_mutexattr_setprotocol (attr, protocol)
+ pthread_mutexattr_t *attr;
+ int protocol;
+{
+ if (protocol != PTHREAD_PRIO_NONE
+ && protocol != PTHREAD_PRIO_INHERIT
+ && __builtin_expect (protocol != PTHREAD_PRIO_PROTECT, 0))
+ return EINVAL;
+
+ struct pthread_mutexattr *iattr = (struct pthread_mutexattr *) attr;
+
+ iattr->mutexkind = ((iattr->mutexkind & ~PTHREAD_MUTEXATTR_PROTOCOL_MASK)
+ | (protocol << PTHREAD_MUTEXATTR_PROTOCOL_SHIFT));
+
+ return 0;
+}
+
diff -Naur glibc-2.3.6_Cs/nptl/pthread_mutexattr_settype.c glibc-2.3.6-AuD/nptl/pthread_mutexattr_settype.c
--- glibc-2.3.6_Cs/nptl/pthread_mutexattr_settype.c 2005-01-20 03:18:36.000000000 +0100
+++ glibc-2.3.6-AuD/nptl/pthread_mutexattr_settype.c 2006-10-05 13:33:34.000000000 +0200
@@ -35,7 +35,13 @@
/* We use bit 31 to signal whether the mutex is going to be
process-shared or not. */
+ /*
+ * m.n. siemens ag mutexkind element is also used for prioceiling and protocol
+ *
iattr->mutexkind = (iattr->mutexkind & 0x80000000) | kind;
+ */
+ iattr->mutexkind = ((iattr->mutexkind & ~PTHREAD_MUTEXATTR_TYPE_MASK)
+ | (kind & PTHREAD_MUTEXATTR_TYPE_MASK));
return 0;
}
diff -Naur glibc-2.3.6_Cs/nptl/pthread_mutex_getprioceiling.c glibc-2.3.6-AuD/nptl/pthread_mutex_getprioceiling.c
--- glibc-2.3.6_Cs/nptl/pthread_mutex_getprioceiling.c 1970-01-01 01:00:00.000000000 +0100
+++ glibc-2.3.6-AuD/nptl/pthread_mutex_getprioceiling.c 2006-03-06 18:20:46.000000000 +0100
@@ -0,0 +1,33 @@
+/* Get current priority ceiling of pthread_mutex_t.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Jakub Jelinek <jakub@redhat.com>, 2006.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <pthreadP.h>
+
+
+int
+pthread_mutex_getprioceiling (mutex, prioceiling)
+ const pthread_mutex_t *mutex;
+ int *prioceiling;
+{
+ *prioceiling = (mutex->__data.__kind & PTHREAD_MUTEX_PRIO_CEILING_MASK)
+ >> PTHREAD_MUTEX_PRIO_CEILING_SHIFT;
+
+ return 0;
+}
diff -Naur glibc-2.3.6_Cs/nptl/pthread_mutex_init.c glibc-2.3.6-AuD/nptl/pthread_mutex_init.c
--- glibc-2.3.6_Cs/nptl/pthread_mutex_init.c 2005-01-20 03:18:36.000000000 +0100
+++ glibc-2.3.6-AuD/nptl/pthread_mutex_init.c 2006-10-05 12:29:48.000000000 +0200
@@ -44,7 +44,13 @@
memset (mutex, '\0', __SIZEOF_PTHREAD_MUTEX_T);
/* Copy the values from the attribute. */
+/*
+ *
+ * m.n. siemens ag: mutexattr may also have the shared flag
+ *
mutex->__data.__kind = imutexattr->mutexkind & ~0x80000000;
+ */
+ mutex->__data.__kind = imutexattr->mutexkind;
/* Default values: mutex not used yet. */
// mutex->__count = 0; already done by memset
diff -Naur glibc-2.3.6_Cs/nptl/pthread_mutex_setprioceiling.c glibc-2.3.6-AuD/nptl/pthread_mutex_setprioceiling.c
--- glibc-2.3.6_Cs/nptl/pthread_mutex_setprioceiling.c 1970-01-01 01:00:00.000000000 +0100
+++ glibc-2.3.6-AuD/nptl/pthread_mutex_setprioceiling.c 2006-03-06 18:20:46.000000000 +0100
@@ -0,0 +1,55 @@
+/* Set current priority ceiling of pthread_mutex_t.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Jakub Jelinek <jakub@redhat.com>, 2006.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <pthreadP.h>
+
+
+int
+pthread_mutex_setprioceiling (mutex, prioceiling, old_ceiling)
+ pthread_mutex_t *mutex;
+ int prioceiling;
+ int *old_ceiling;
+{
+ /* The low bits of __kind aren't ever changed after pthread_mutex_init,
+ so we don't need a lock yet. */
+ if ((mutex->__data.__kind & PTHREAD_MUTEX_PRIO_PROTECT_PRIVATE_NP) == 0)
+ return EINVAL;
+
+ if (prioceiling < 0 || __builtin_expect (prioceiling > 255, 0))
+ return EINVAL;
+
+ /* XXX This needs to lock with TID, but shouldn't obey priority protect
+ protocol. */
+ /* lll_xxx_mutex_lock (mutex->__data.__lock); */
+
+ if (old_ceiling != NULL)
+ *old_ceiling = (mutex->__data.__kind & PTHREAD_MUTEX_PRIO_CEILING_MASK)
+ >> PTHREAD_MUTEX_PRIO_CEILING_SHIFT;
+
+ int newkind = (mutex->__data.__kind & ~PTHREAD_MUTEX_PRIO_CEILING_MASK);
+ mutex->__data.__kind = newkind
+ | (prioceiling << PTHREAD_MUTEX_PRIO_CEILING_SHIFT);
+
+ /* XXX This needs to unlock the above special kind of lock. */
+ /* lll_xxx_mutex_unlock (mutex->__data.__lock); */
+
+ return 0;
+}
diff -Naur glibc-2.3.6_Cs/nptl/sem_open.c glibc-2.3.6-AuD/nptl/sem_open.c
--- glibc-2.3.6_Cs/nptl/sem_open.c 2005-01-20 03:18:36.000000000 +0100
+++ glibc-2.3.6-AuD/nptl/sem_open.c 2006-10-11 17:20:48.000000000 +0200
@@ -233,7 +233,6 @@
/* Determine where the shmfs is mounted. */
INTUSE(__pthread_once) (&__namedsem_once, __where_is_shmfs);
-
/* If we don't know the mount points there is nothing we can do. Ever. */
if (mountpoint.dir == NULL)
{
diff -Naur glibc-2.3.6_Cs/nptl/sysdeps/arm/pthread_spin_lock.c glibc-2.3.6-AuD/nptl/sysdeps/arm/pthread_spin_lock.c
--- glibc-2.3.6_Cs/nptl/sysdeps/arm/pthread_spin_lock.c 1970-01-01 01:00:00.000000000 +0100
+++ glibc-2.3.6-AuD/nptl/sysdeps/arm/pthread_spin_lock.c 2006-12-20 18:37:53.000000000 +0100
@@ -0,0 +1,213 @@
+/* Copyright (C) 2002,2003,2004 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+/*
+ * Manfred.Neugebauer@siemens.com 21-Feb-2006
+ * extend spinlock for use with threads with static priority
+ */
+
+#include "pthreadP.h"
+#include <pthread-errnos.h>
+
+// ARM cli / sti handling
+#if (0) // m.n. we can't disable irq / fiq at user level with the ARM architecture
+#define __ARM_INTR_DISABLE_FLAG #0x080
+#define __ARM_FIQ_DISABLE_FLAG #0x040
+/* disable IRQ (0x080) and FIQ (0x040) */
+#define MY_CLI \
+ asm("\n" \
+ "MRS r0, CPSR\n\t" \
+ "ORR r0, r0, #0x0c0\n\t" \
+ "MSR CPSR, r0\n\t" \
+ : \
+ :);
+
+/* enable IRQ (0x080) and FIQ (0x040) */
+#define MY_STI \
+ asm("\n" \
+ "MRS r0, CPSR\n\t" \
+ "EOR r0, r0, #0x0c0\n\t" \
+ "MSR CPSR, r0\n\t" \
+ : \
+ :);
+
+#else
+
+// arm cli / sti simulation:
+// first approach do an arm specific system call
+#define MY_CLI asm("svc #0x9f000a");
+#define MY_STI asm("svc #0x9f000b");
+
+#endif
+
+int
+pthread_spin_lock (lock)
+ pthread_spinlock_t *lock;
+{
+ int myTid = THREAD_GETMEM (THREAD_SELF, tid);
+
+ if (lock->__spinMagic != __AUD_SPINLOCK_MAGIC) {
+ return(EINVAL);
+ }
+ if (lock->__spinTaskid == myTid) {
+ return(EDEADLK);
+ }
+ // up to now we only allow private spinlocks
+ if (lock->__spinFlag != PTHREAD_PROCESS_PRIVATE) {
+ return(EINVAL);
+ }
+ // be safe and test for identical process id
+ if (lock->__spinProcessId != __aud_spin_process_id) {
+ return(EINVAL);
+ }
+ // T B D: prevent stacking of spinlocks
+
+ // be safe and test for the same privileg level
+ if (lock->__spinPrivLevel != __aud_spin_priv_level) {
+ return(EDEADLK);
+ }
+
+ // super user application: use cli/sti to handle static priority threads
+ if (lock->__spinPrivLevel == 0) {
+ /* disable IRQ (0x080) and FIQ (0x040) */
+ MY_CLI;
+ }
+
+ // T B D: enable interrupts again, when looping ?
+ asm ("\n"
+ "mov r1, #0\n\t"
+ "1:\t swp r2, r1, [%0]\n\t"
+ "teq r2, #1\n\t"
+ "bne 1b\n\t"
+ :
+ : "r,r" (&lock->__spinCount) );
+
+// :
+// : "r,r" (lock->__spinCount));
+ lock->__spinTaskid = myTid;
+
+ return 0;
+}
+
+int
+__aud_pthread_spin_trylock_intern(unsigned long *lockRef);
+
+int
+pthread_spin_trylock (lock)
+ pthread_spinlock_t *lock;
+{
+ int myTid = THREAD_GETMEM (THREAD_SELF, tid);
+ int retVal;
+
+ if (lock->__spinMagic != __AUD_SPINLOCK_MAGIC) {
+ return(EINVAL);
+ }
+ if (lock->__spinTaskid == myTid) {
+ return(EDEADLK);
+ }
+ // up to now we only allow private spinlocks
+ if (lock->__spinFlag != PTHREAD_PROCESS_PRIVATE) {
+ return(EINVAL);
+ }
+ // be safe and test for identical process id
+ if (lock->__spinProcessId != __aud_spin_process_id) {
+ return(EINVAL);
+ }
+ // T B D: prevent stacking of spinlocks
+
+ // be safe and test for the same privileg level
+ if (lock->__spinPrivLevel != __aud_spin_priv_level) {
+ return(EDEADLK);
+ }
+
+ // super user application: use cli/sti to handle static priority threads
+ if (lock->__spinPrivLevel == 0) {
+ /* disable IRQ (0x080) and FIQ (0x040) */
+ MY_CLI;
+ }
+
+ retVal = __aud_pthread_spin_trylock_intern(&lock->__spinCount);
+ if (retVal != 0) {
+ // we are super user, be sure we enable interrupts
+ /* enable IRQ (0x080) and FIQ (0x040) */
+ if (lock->__spinPrivLevel == 0) {
+ MY_STI;
+ }
+ return(retVal);
+ }
+
+ lock->__spinTaskid = myTid;
+
+ return 0;
+}
+
+int
+pthread_spin_unlock (lock)
+ pthread_spinlock_t *lock;
+{
+ int myTid = THREAD_GETMEM (THREAD_SELF, tid);
+
+ if (lock->__spinMagic != __AUD_SPINLOCK_MAGIC) {
+errorRetEinval:
+ if (__aud_spin_priv_level == 0) {
+ // we are super user, be sure we enable interrupts
+ /* enable IRQ (0x080) and FIQ (0x040) */
+ MY_STI;
+ }
+ return(EINVAL);
+ }
+ if (lock->__spinTaskid != myTid) {
+errorRetEdeadlk:
+ if (__aud_spin_priv_level == 0) {
+ // we are super user, be sure we enable interrupts
+ /* enable IRQ (0x080) and FIQ (0x040) */
+ MY_STI;
+ }
+ return(EDEADLK);
+ }
+ // up to now we only allow private spinlocks
+ if (lock->__spinFlag != PTHREAD_PROCESS_PRIVATE) {
+ goto errorRetEinval;
+ //return(EINVAL);
+ }
+ // be safe and test for identical process id
+ if (lock->__spinProcessId != __aud_spin_process_id) {
+ goto errorRetEinval;
+ //return(EINVAL);
+ }
+ // T B D: prevent stacking of spinlocks
+
+ // be safe and test for the same privileg level
+ if (lock->__spinPrivLevel != __aud_spin_priv_level) {
+ goto errorRetEdeadlk;
+ // return(EDEADLK);
+ }
+
+ lock->__spinCount = 1;
+ lock->__spinTaskid = -1;
+
+ // super user application: use cli/sti to handle static priority threads
+ if (lock->__spinPrivLevel == 0) {
+ /* enable IRQ (0x080) and FIQ (0x040) */
+ MY_STI;
+ }
+
+ return 0;
+}
+
diff -Naur glibc-2.3.6_Cs/nptl/sysdeps/arm/pthread_spin_lock.S glibc-2.3.6-AuD/nptl/sysdeps/arm/pthread_spin_lock.S
--- glibc-2.3.6_Cs/nptl/sysdeps/arm/pthread_spin_lock.S 2005-03-28 17:57:51.000000000 +0200
+++ glibc-2.3.6-AuD/nptl/sysdeps/arm/pthread_spin_lock.S 1970-01-01 01:00:00.000000000 +0100
@@ -1,32 +0,0 @@
-/* Copyright (C) 2003 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Phil Blundell <pb@nexus.co.uk>, 2004
-
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- The GNU C Library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with the GNU C Library; if not, write to the Free
- Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
- 02111-1307 USA. */
-
-#include <sysdep.h>
-
- .text
- .align 4
-
-ENTRY (pthread_spin_lock)
- mov r1, #1
-1: swp r2, r1, [r0]
- teq r2, #0
- bne 1b
- mov r0, #0
- PSEUDO_RET_NOERRNO
-END (pthread_spin_lock)
diff -Naur glibc-2.3.6_Cs/nptl/sysdeps/arm/pthread_spin_lockX.S glibc-2.3.6-AuD/nptl/sysdeps/arm/pthread_spin_lockX.S
--- glibc-2.3.6_Cs/nptl/sysdeps/arm/pthread_spin_lockX.S 1970-01-01 01:00:00.000000000 +0100
+++ glibc-2.3.6-AuD/nptl/sysdeps/arm/pthread_spin_lockX.S 2006-10-02 12:09:26.000000000 +0200
@@ -0,0 +1,32 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Phil Blundell <pb@nexus.co.uk>, 2004
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <sysdep.h>
+
+ .text
+ .align 4
+
+ENTRY (pthread_spin_lock)
+ mov r1, #1
+1: swp r2, r1, [r0]
+ teq r2, #0
+ bne 1b
+ mov r0, #0
+ PSEUDO_RET_NOERRNO
+END (pthread_spin_lock)
diff -Naur glibc-2.3.6_Cs/nptl/sysdeps/arm/pthread_spin_trylock.S glibc-2.3.6-AuD/nptl/sysdeps/arm/pthread_spin_trylock.S
--- glibc-2.3.6_Cs/nptl/sysdeps/arm/pthread_spin_trylock.S 2005-03-28 17:57:51.000000000 +0200
+++ glibc-2.3.6-AuD/nptl/sysdeps/arm/pthread_spin_trylock.S 2006-10-02 14:34:23.000000000 +0200
@@ -25,6 +25,8 @@
.text
.align 4
+#if (0) /* m.n. */
+
ENTRY (pthread_spin_trylock)
mov r1, #1
swp r2, r1, [r0]
@@ -33,3 +35,16 @@
movne r0, #EBUSY
PSEUDO_RET_NOERRNO
END (pthread_spin_trylock)
+
+#else
+
+ENTRY (__aud_pthread_spin_trylock_intern)
+ mov r1, #1
+ swp r2, r1, [r0]
+ teq r2, #0
+ moveq r0, #0
+ movne r0, #EBUSY
+ PSEUDO_RET_NOERRNO
+END (__aud_pthread_spin_trylock_intern)
+
+#endif
diff -Naur glibc-2.3.6_Cs/nptl/sysdeps/i386/i486/pthread_spin_trylock.S glibc-2.3.6-AuD/nptl/sysdeps/i386/i486/pthread_spin_trylock.S
--- glibc-2.3.6_Cs/nptl/sysdeps/i386/i486/pthread_spin_trylock.S 2005-01-20 03:18:37.000000000 +0100
+++ glibc-2.3.6-AuD/nptl/sysdeps/i386/i486/pthread_spin_trylock.S 2006-02-22 16:10:42.000000000 +0100
@@ -19,7 +19,7 @@
#include <pthread-errnos.h>
-
+#if (0) /* m.n. */
#ifdef UP
# define LOCK
#else
@@ -45,3 +45,26 @@
#endif
ret
.size pthread_spin_trylock,.-pthread_spin_trylock
+
+#else
+
+ .globl __aud_pthread_spin_trylock_intern
+ .type __aud_pthread_spin_trylock_intern,@function
+ .align 16
+__aud_pthread_spin_trylock_intern:
+ movl 4(%esp), %edx
+ movl $1, %eax
+ xorl %ecx, %ecx
+ LOCK
+ cmpxchgl %ecx, (%edx)
+ movl $EBUSY, %eax
+#ifdef HAVE_CMOV
+ cmovel %ecx, %eax
+#else
+ jne 0f
+ movl %ecx, %eax
+0:
+#endif
+ ret
+
+#endif
diff -Naur glibc-2.3.6_Cs/nptl/sysdeps/i386/pthread_spin_init.c glibc-2.3.6-AuD/nptl/sysdeps/i386/pthread_spin_init.c
--- glibc-2.3.6_Cs/nptl/sysdeps/i386/pthread_spin_init.c 2005-01-20 03:18:37.000000000 +0100
+++ glibc-2.3.6-AuD/nptl/sysdeps/i386/pthread_spin_init.c 2006-02-22 16:10:54.000000000 +0100
@@ -18,3 +18,56 @@
02111-1307 USA. */
/* Not needed. pthread_spin_init is an alias for pthread_spin_unlock. */
+
+/*
+ * Manfred.Neugebauer@siemens.com 21-Feb-2006
+ * extend spinlock for use with threads with static priority
+ * T B D: initialize __aud_spin_process_id and __aud_spin_priv_level
+ * when starting the application
+ */
+
+ #include "pthreadP.h"
+#include "errno.h"
+#include "unistd.h"
+
+#ifndef LOCK_PREFIX
+# ifdef UP
+# define LOCK_PREFIX /* nothing */
+# else
+# define LOCK_PREFIX "lock;"
+# endif
+#endif
+
+int __aud_spin_process_id = -1;
+int __aud_spin_priv_level = -1;
+
+int
+pthread_spin_init (__lock, __pshared)
+ pthread_spinlock_t *__lock;
+ int __pshared;
+{
+ if (__aud_spin_process_id == -1) {
+ // get process id and user id once
+ __aud_spin_priv_level = getegid();
+ __aud_spin_process_id = getpid();
+ if (__aud_spin_priv_level == 0) {
+ // when root, allow cli / sti
+ iopl(3);
+ }
+ }
+ // up to now the AuD API only supports private spinlocks
+ if (__pshared != PTHREAD_PROCESS_PRIVATE) {
+ return(EINVAL);
+ }
+ if (__lock->__spinMagic == __AUD_SPINLOCK_MAGIC) {
+ return(EBUSY);
+ }
+
+ __lock->__spinMagic = __AUD_SPINLOCK_MAGIC;
+ __lock->__spinFlag = __pshared;
+ __lock->__spinCount = 1;
+ __lock->__spinPrivLevel = __aud_spin_priv_level;
+ __lock->__spinProcessId = __aud_spin_process_id;
+
+ return 0;
+}
diff -Naur glibc-2.3.6_Cs/nptl/sysdeps/i386/pthread_spin_lock.c glibc-2.3.6-AuD/nptl/sysdeps/i386/pthread_spin_lock.c
--- glibc-2.3.6_Cs/nptl/sysdeps/i386/pthread_spin_lock.c 2005-01-20 03:18:37.000000000 +0100
+++ glibc-2.3.6-AuD/nptl/sysdeps/i386/pthread_spin_lock.c 2006-02-22 16:10:56.000000000 +0100
@@ -17,7 +17,13 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
+/*
+ * Manfred.Neugebauer@siemens.com 21-Feb-2006
+ * extend spinlock for use with threads with static priority
+ */
+
#include "pthreadP.h"
+#include <pthread-errnos.h>
#ifndef LOCK_PREFIX
# ifdef UP
@@ -32,6 +38,35 @@
pthread_spin_lock (lock)
pthread_spinlock_t *lock;
{
+ int myTid = THREAD_GETMEM (THREAD_SELF, tid);
+
+ if (lock->__spinMagic != __AUD_SPINLOCK_MAGIC) {
+ return(EINVAL);
+ }
+ if (lock->__spinTaskid == myTid) {
+ return(EDEADLK);
+ }
+ // up to now we only allow private spinlocks
+ if (lock->__spinFlag != PTHREAD_PROCESS_PRIVATE) {
+ return(EINVAL);
+ }
+ // be safe and test for identical process id
+ if (lock->__spinProcessId != __aud_spin_process_id) {
+ return(EINVAL);
+ }
+ // T B D: prevent stacking of spinlocks
+
+ // be safe and test for the same privileg level
+ if (lock->__spinPrivLevel != __aud_spin_priv_level) {
+ return(EDEADLK);
+ }
+
+ // super user application: use cli/sti to handle static priority threads
+ if (lock->__spinPrivLevel == 0) {
+ asm("cli");
+ }
+
+ // T B D: enable interrupts again, when looping
asm ("\n"
"1:\t" LOCK_PREFIX "decl %0\n\t"
"jne 2f\n\t"
@@ -42,8 +77,111 @@
"jg 1b\n\t"
"jmp 2b\n\t"
".previous"
- : "=m" (*lock)
- : "m" (*lock));
+ : "=m" (lock->__spinCount)
+ : "m" (lock->__spinCount));
+
+ lock->__spinTaskid = myTid;
+
+ return 0;
+}
+
+int
+__aud_pthread_spin_trylock_intern(unsigned long *lockRef);
+
+int
+pthread_spin_trylock (lock)
+ pthread_spinlock_t *lock;
+{
+ int myTid = THREAD_GETMEM (THREAD_SELF, tid);
+ int retVal;
+
+ if (lock->__spinMagic != __AUD_SPINLOCK_MAGIC) {
+ return(EINVAL);
+ }
+ if (lock->__spinTaskid == myTid) {
+ return(EDEADLK);
+ }
+ // up to now we only allow private spinlocks
+ if (lock->__spinFlag != PTHREAD_PROCESS_PRIVATE) {
+ return(EINVAL);
+ }
+ // be safe and test for identical process id
+ if (lock->__spinProcessId != __aud_spin_process_id) {
+ return(EINVAL);
+ }
+ // T B D: prevent stacking of spinlocks
+
+ // be safe and test for the same privileg level
+ if (lock->__spinPrivLevel != __aud_spin_priv_level) {
+ return(EDEADLK);
+ }
+
+ // super user application: use cli/sti to handle static priority threads
+ if (lock->__spinPrivLevel == 0) {
+ asm("cli");
+ }
+
+ retVal = __aud_pthread_spin_trylock_intern(&lock->__spinCount);
+ if (retVal != 0) {
+ if (lock->__spinPrivLevel == 0) {
+ asm("sti");
+ }
+ return(retVal);
+ }
+
+ lock->__spinTaskid = myTid;
+
+ return 0;
+}
+int
+pthread_spin_unlock (lock)
+ pthread_spinlock_t *lock;
+{
+ int myTid = THREAD_GETMEM (THREAD_SELF, tid);
+
+ if (lock->__spinMagic != __AUD_SPINLOCK_MAGIC) {
+errorRetEinval:
+ if (__aud_spin_priv_level == 0) {
+ // we are super user, be sure we enable interrupts
+ asm("sti");
+ }
+ return(EINVAL);
+ }
+ if (lock->__spinTaskid != myTid) {
+errorRetEdeadlk:
+ if (__aud_spin_priv_level == 0) {
+ // we are super user, be sure we enable interrupts
+ asm("sti");
+ }
+ return(EDEADLK);
+ }
+ // up to now we only allow private spinlocks
+ if (lock->__spinFlag != PTHREAD_PROCESS_PRIVATE) {
+ goto errorRetEinval;
+ //return(EINVAL);
+ }
+ // be safe and test for identical process id
+ if (lock->__spinProcessId != __aud_spin_process_id) {
+ goto errorRetEinval;
+ //return(EINVAL);
+ }
+ // T B D: prevent stacking of spinlocks
+
+ // be safe and test for the same privileg level
+ if (lock->__spinPrivLevel != __aud_spin_priv_level) {
+ goto errorRetEdeadlk;
+ // return(EDEADLK);
+ }
+
+ lock->__spinCount = 1;
+ lock->__spinTaskid = -1;
+
+ // super user application: use cli/sti to handle static priority threads
+ if (lock->__spinPrivLevel == 0) {
+ asm("sti");
+ }
+
return 0;
}
+
diff -Naur glibc-2.3.6_Cs/nptl/sysdeps/i386/pthread_spin_unlock.S glibc-2.3.6-AuD/nptl/sysdeps/i386/pthread_spin_unlock.S
--- glibc-2.3.6_Cs/nptl/sysdeps/i386/pthread_spin_unlock.S 2005-01-20 03:18:37.000000000 +0100
+++ glibc-2.3.6-AuD/nptl/sysdeps/i386/pthread_spin_unlock.S 2006-02-21 12:27:34.000000000 +0100
@@ -17,6 +17,10 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
+/*
+ * Manfred.Neugebauer@siemens.com 21-Feb-2006
+ * extend spinlock for use with threads with static priority
+ */
.globl pthread_spin_unlock
.type pthread_spin_unlock,@function
.align 16
@@ -27,6 +31,8 @@
ret
.size pthread_spin_unlock,.-pthread_spin_unlock
+#if (0) // m.n. no longer valid for a more general approach
/* The implementation of pthread_spin_init is identical. */
.globl pthread_spin_init
pthread_spin_init = pthread_spin_unlock
+#endif
diff -Naur glibc-2.3.6_Cs/nptl/sysdeps/pthread/pthread.h glibc-2.3.6-AuD/nptl/sysdeps/pthread/pthread.h
--- glibc-2.3.6_Cs/nptl/sysdeps/pthread/pthread.h 2005-11-09 05:04:44.000000000 +0100
+++ glibc-2.3.6-AuD/nptl/sysdeps/pthread/pthread.h 2006-10-05 14:09:12.000000000 +0200
@@ -60,6 +60,21 @@
#endif
};
+/* m.n. siemens ag */
+#define PTHREAD_MUTEXATTR_TYPE_MASK 0x000000ff
+#define PTHREAD_MUTEXATTR_PRIO_CEILING_MASK 0x0000ff00
+#define PTHREAD_MUTEXATTR_PRIO_CEILING_SHIFT 8
+#define PTHREAD_MUTEXATTR_PROTOCOL_MASK 0x00ff0000
+#define PTHREAD_MUTEXATTR_PROTOCOL_SHIFT 16
+#define PTHREAD_MUTEXATTR_SHARED_MASK 0x80000000
+
+enum
+{
+ PTHREAD_PRIO_NONE = 0,
+ PTHREAD_PRIO_INHERIT,
+ PTHREAD_PRIO_PROTECT
+};
+
/* Mutex initializers. */
#define PTHREAD_MUTEX_INITIALIZER \
{ { 0, 0, 0, 0, 0, 0 } }
@@ -728,6 +743,13 @@
__THROW;
#endif
+/* set / get mutextattr protocol */
+extern int pthread_mutexattr_getprotocol (const pthread_mutexattr_t *attr, int *protocol) __THROW;
+extern int pthread_mutexattr_setprotocol (pthread_mutexattr_t *attr, int protocol) __THROW;
+
+/* set / get mutexattr_prioceiling */
+extern int pthread_mutexattr_getprioceiling (const pthread_mutexattr_t *attr, int *prioceiling) __THROW;
+extern int pthread_mutexattr_setprioceiling (pthread_mutexattr_t *attr, int prioceiling) __THROW;
#if defined __USE_UNIX98 || defined __USE_XOPEN2K
/* Functions for handling read-write locks. */
diff -Naur glibc-2.3.6_Cs/nptl/sysdeps/pthread/pthread_spin_destroy.c glibc-2.3.6-AuD/nptl/sysdeps/pthread/pthread_spin_destroy.c
--- glibc-2.3.6_Cs/nptl/sysdeps/pthread/pthread_spin_destroy.c 2005-01-20 03:18:37.000000000 +0100
+++ glibc-2.3.6-AuD/nptl/sysdeps/pthread/pthread_spin_destroy.c 2006-02-22 16:11:40.000000000 +0100
@@ -17,13 +17,29 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
-#include "pthreadP.h"
+/*
+ * Manfred.Neugebauer@siemens.com 21-Feb-2006
+ * extend for more general use
+ */
+#include "pthreadP.h"
+#include "errno.h"
int
-pthread_spin_destroy (lock)
- pthread_spinlock_t *lock;
+pthread_spin_destroy (__lock)
+ pthread_spinlock_t *__lock;
{
- /* Nothing to do. */
+ if (__lock->__spinMagic != __AUD_SPINLOCK_MAGIC) {
+ return(EINVAL);
+ }
+ if (__lock->__spinCount != 1) {
+ return(EBUSY);
+ }
+ __lock->__spinMagic = 0;
+ __lock->__spinFlag = -1;
+ __lock->__spinCount = 1;
+ __lock->__spinPrivLevel = -1;
+ __lock-> __spinProcessId = -1;
+
return 0;
}
diff -Naur glibc-2.3.6_Cs/nptl/sysdeps/pthread/pthread_spin_init.c glibc-2.3.6-AuD/nptl/sysdeps/pthread/pthread_spin_init.c
--- glibc-2.3.6_Cs/nptl/sysdeps/pthread/pthread_spin_init.c 2005-01-20 03:18:37.000000000 +0100
+++ glibc-2.3.6-AuD/nptl/sysdeps/pthread/pthread_spin_init.c 2006-09-29 16:36:12.000000000 +0200
@@ -1,7 +1,6 @@
-/* pthread_spin_init -- initialize a spin lock. Generic version.
- Copyright (C) 2003 Free Software Foundation, Inc.
+/* Copyright (C) 2002 Free Software Foundation, Inc.
This file is part of the GNU C Library.
- Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003.
+ Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
@@ -18,11 +17,49 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
-#include "pthreadP.h"
+/* Not needed. pthread_spin_init is an alias for pthread_spin_unlock. */
+
+/*
+ * Manfred.Neugebauer@siemens.com 21-Feb-2006
+ * extend spinlock for use with threads with static priority
+ * T B D: initialize __aud_spin_process_id and __aud_spin_priv_level
+ * when starting the application
+ */
+
+ #include "pthreadP.h"
+#include "errno.h"
+#include "unistd.h"
+
+int __aud_spin_process_id = -1;
+int __aud_spin_priv_level = -1;
int
-pthread_spin_init (pthread_spinlock_t *lock, int pshared)
+pthread_spin_init (__lock, __pshared)
+ pthread_spinlock_t *__lock;
+ int __pshared;
{
- *lock = 0;
+ if (__aud_spin_process_id == -1) {
+ // get process id and user id once
+ __aud_spin_priv_level = getegid();
+ __aud_spin_process_id = getpid();
+ if (__aud_spin_priv_level == 0) {
+ // when root, allow cli / sti
+ iopl(3);
+ }
+ }
+ // up to now the AuD API only supports private spinlocks
+ if (__pshared != PTHREAD_PROCESS_PRIVATE) {
+ return(EINVAL);
+ }
+ if (__lock->__spinMagic == __AUD_SPINLOCK_MAGIC) {
+ return(EBUSY);
+ }
+
+ __lock->__spinMagic = __AUD_SPINLOCK_MAGIC;
+ __lock->__spinFlag = __pshared;
+ __lock->__spinCount = 1;
+ __lock->__spinPrivLevel = __aud_spin_priv_level;
+ __lock->__spinProcessId = __aud_spin_process_id;
+
return 0;
}
diff -Naur glibc-2.3.6_Cs/nptl/sysdeps/pthread/pthread_spin_unlock.c glibc-2.3.6-AuD/nptl/sysdeps/pthread/pthread_spin_unlock.c
--- glibc-2.3.6_Cs/nptl/sysdeps/pthread/pthread_spin_unlock.c 2005-01-20 03:18:37.000000000 +0100
+++ glibc-2.3.6-AuD/nptl/sysdeps/pthread/pthread_spin_unlock.c 2006-10-02 14:04:23.000000000 +0200
@@ -21,6 +21,14 @@
#include "pthreadP.h"
#include <atomic.h>
+/*
+ Siemens AG, m.n.
+ this subroutine is called in the ARM context
+ we ignore it for the AuD extende implementation
+ see nptl/sysdeps/arm/pthread_spin_lock.c for the AuD implementation ( C based)
+ */
+#if (0)
+
int
pthread_spin_unlock (pthread_spinlock_t *lock)
{
@@ -28,3 +36,5 @@
*lock = 0;
return 0;
}
+
+#endif
diff -Naur glibc-2.3.6_Cs/nptl/sysdeps/unix/sysv/linux/arm/bits/atomic.h glibc-2.3.6-AuD/nptl/sysdeps/unix/sysv/linux/arm/bits/atomic.h
--- glibc-2.3.6_Cs/nptl/sysdeps/unix/sysv/linux/arm/bits/atomic.h 2006-05-02 19:39:55.000000000 +0200
+++ glibc-2.3.6-AuD/nptl/sysdeps/unix/sysv/linux/arm/bits/atomic.h 2006-09-29 16:02:56.000000000 +0200
@@ -37,10 +37,6 @@
void __arm_link_error (void);
-#ifdef UP
-
-/* We require kernel assisted barriers for SMP safety, so it is only worth
- defining this on UP. */
#define atomic_exchange_acq(mem, newvalue) \
({ __typeof (*mem) result; \
if (sizeof (*mem) == 1) \
@@ -58,17 +54,6 @@
} \
result; })
-#else
-
-#define atomic_full_barrier() \
- __asm__ __volatile__ \
- ("mov\tip, #0xffff0fff\n\t" \
- "mov\tlr, pc\n\t" \
- "add\tpc, ip, #(0xffff0fa0 - 0xffff0fff)" \
- : : : "ip", "lr", "cc", "memory");
-
-#endif
-
/* Atomic compare and exchange. This sequence relies on the kernel to
provide a compare and exchange operation which is atomic on the
current architecture, either via cleverness on pre-ARMv6 or via
@@ -84,6 +69,8 @@
specify one to work around GCC PR rtl-optimization/21223. Otherwise
it may cause a_oldval or a_tmp to be moved to a different register. */
+/* m.n. arm with no mmu: use entry 0x0fc0 */
+#ifdef CONFIG_NOMMU_USE_LOW_ADDR
#define __arch_compare_and_exchange_val_32_acq(mem, newval, oldval) \
({ register __typeof (oldval) a_oldval asm ("r0"); \
register __typeof (oldval) a_newval asm ("r1") = (newval); \
@@ -96,6 +83,8 @@
"bne\t1f\n\t" \
"mov\t%0, %4\n\t" \
"mov\t%1, #0xffff0fff\n\t" \
+ "mov\t%1, #0x1000\n\t" \
+ "sub\t%1, #1\n\t" \
"mov\tlr, pc\n\t" \
"add\tpc, %1, #(0xffff0fc0 - 0xffff0fff)\n\t" \
"bcc\t0b\n\t" \
@@ -105,6 +94,29 @@
: "r" (a_newval), "r" (a_ptr), "r" (a_oldval2) \
: "ip", "lr", "cc", "memory"); \
a_tmp; })
+#else
+#define __arch_compare_and_exchange_val_32_acq(mem, newval, oldval) \
+ ({ register __typeof (oldval) a_oldval asm ("r0"); \
+ register __typeof (oldval) a_newval asm ("r1") = (newval); \
+ register __typeof (mem) a_ptr asm ("r2") = (mem); \
+ register __typeof (oldval) a_tmp asm ("r3"); \
+ register __typeof (oldval) a_oldval2 asm ("r4") = (oldval); \
+ __asm__ __volatile__ \
+ ("0:\tldr\t%1,[%3]\n\t" \
+ "cmp\t%1, %4\n\t" \
+ "bne\t1f\n\t" \
+ "mov\t%0, %4\n\t" \
+ "mov\t%1, #0xffff0fff\n\t" \
+ "mov\tlr, pc\n\t" \
+ "add\tpc, %1, #(0xffff0fc0 - 0xffff0fff)\n\t" \
+ "bcc\t0b\n\t" \
+ "mov\t%1, %4\n\t" \
+ "1:" \
+ : "=&r" (a_oldval), "=&r" (a_tmp) \
+ : "r" (a_newval), "r" (a_ptr), "r" (a_oldval2) \
+ : "ip", "lr", "cc", "memory"); \
+ a_tmp; })
+#endif
#define __arch_compare_and_exchange_val_64_acq(mem, newval, oldval) \
({ __arm_link_error (); oldval; })
diff -Naur glibc-2.3.6_Cs/nptl/sysdeps/unix/sysv/linux/arm/bits/pthreadtypes.h glibc-2.3.6-AuD/nptl/sysdeps/unix/sysv/linux/arm/bits/pthreadtypes.h
--- glibc-2.3.6_Cs/nptl/sysdeps/unix/sysv/linux/arm/bits/pthreadtypes.h 2005-03-28 17:57:52.000000000 +0200
+++ glibc-2.3.6-AuD/nptl/sysdeps/unix/sysv/linux/arm/bits/pthreadtypes.h 2006-10-02 16:42:23.000000000 +0200
@@ -16,6 +16,11 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
+/*
+ * Manfred.Neugebauer@siemens.com 21-Feb-2006
+ * extend structure pthread_spinlock_t for a more general use
+ */
+
#ifndef _BITS_PTHREADTYPES_H
#define _BITS_PTHREADTYPES_H 1
@@ -77,15 +82,15 @@
{
int __lock;
unsigned int __futex;
- unsigned long long int __total_seq;
- unsigned long long int __wakeup_seq;
- unsigned long long int __woken_seq;
+ __extension__ unsigned long long int __total_seq;
+ __extension__ unsigned long long int __wakeup_seq;
+ __extension__ unsigned long long int __woken_seq;
void *__mutex;
unsigned int __nwaiters;
unsigned int __broadcast_seq;
} __data;
char __size[__SIZEOF_PTHREAD_COND_T];
- long long int __align;
+ __extension__ long long int __align;
} pthread_cond_t;
typedef union
@@ -135,7 +140,19 @@
#ifdef __USE_XOPEN2K
/* POSIX spinlock data type. */
-typedef volatile int pthread_spinlock_t;
+/* m.n. extended for AuD use */
+typedef volatile struct
+{
+ long int __spinMagic;
+ long int __spinFlag;
+ long int __spinCount;
+ long int __spinPrivLevel;
+ long int __spinProcessId;
+ long int __spinTaskid;
+} pthread_spinlock_t;
+#define __AUD_SPINLOCK_MAGIC 0x25091921
+extern int __aud_spin_process_id;
+extern int __aud_spin_priv_level;
/* POSIX barriers data type. The structure of the type is
diff -Naur glibc-2.3.6_Cs/nptl/sysdeps/unix/sysv/linux/arm/sysdep-cancel.h glibc-2.3.6-AuD/nptl/sysdeps/unix/sysv/linux/arm/sysdep-cancel.h
--- glibc-2.3.6_Cs/nptl/sysdeps/unix/sysv/linux/arm/sysdep-cancel.h 2005-04-27 22:57:06.000000000 +0200
+++ glibc-2.3.6-AuD/nptl/sysdeps/unix/sysv/linux/arm/sysdep-cancel.h 2006-09-29 16:03:04.000000000 +0200
@@ -109,12 +109,24 @@
header.multiple_threads) == 0, 1)
# else
# define PSEUDO_PROLOGUE
-# define SINGLE_THREAD_P \
- mov r0, #0xffff0fff; \
- mov lr, pc; \
- sub pc, r0, #31; \
- ldr ip, [r0, #MULTIPLE_THREADS_OFFSET]; \
- teq ip, #0
+/* m.n. ARM with no MMU use 0x0fff instead of 0xffff0fff */
+#ifdef CONFIG_NOMMU_USE_LOW_ADDR
+# define SINGLE_THREAD_P \
+ mov r0, #0xffff0fff; \
+ mov r0, #0x01000; \
+ sub r0, #1; \
+ mov lr, pc; \
+ sub pc, r0, #31; \
+ ldr ip, [r0, #MULTIPLE_THREADS_OFFSET]; \
+ teq ip, #0
+#else
+# define SINGLE_THREAD_P \
+ mov r0, #0xffff0fff; \
+ mov lr, pc; \
+ sub pc, r0, #31; \
+ ldr ip, [r0, #MULTIPLE_THREADS_OFFSET]; \
+ teq ip, #0
+#endif
# define SINGLE_THREAD_P_PIC(x) SINGLE_THREAD_P
# endif
diff -Naur glibc-2.3.6_Cs/nptl/sysdeps/unix/sysv/linux/arm/vfork.S glibc-2.3.6-AuD/nptl/sysdeps/unix/sysv/linux/arm/vfork.S
--- glibc-2.3.6_Cs/nptl/sysdeps/unix/sysv/linux/arm/vfork.S 2005-04-27 22:57:06.000000000 +0200
+++ glibc-2.3.6-AuD/nptl/sysdeps/unix/sysv/linux/arm/vfork.S 2007-02-28 17:43:34.000000000 +0100
@@ -19,9 +19,13 @@
#include <tcb-offsets.h>
/* Save the PID value. */
+/* m.n. ARM with no MMU use 0x0fff instead of 0xffff0fff */
+#ifdef CONFIG_NOMMU_USE_LOW_ADDR
#define SAVE_PID \
str lr, [sp, #-4]!; /* Save LR. */ \
mov r0, #0xffff0fff; /* Point to the high page. */ \
+ mov r0, #0x1000; \
+ sub r0, #1; \
mov lr, pc; /* Save our return address. */ \
sub pc, r0, #31; /* Jump to the TLS entry. */ \
ldr lr, [sp], #4; /* Restore LR. */ \
@@ -30,6 +34,19 @@
rsbs r0, r3, #0; /* Negate it. */ \
moveq r0, #0x80000000; /* Use 0x80000000 if it was 0. */ \
str r0, [r2, #PID_OFFSET] /* Store the temporary PID. */
+#else
+#define SAVE_PID \
+ str lr, [sp, #-4]!; /* Save LR. */ \
+ mov r0, #0xffff0fff; /* Point to the high page. */ \
+ mov lr, pc; /* Save our return address. */ \
+ sub pc, r0, #31; /* Jump to the TLS entry. */ \
+ ldr lr, [sp], #4; /* Restore LR. */ \
+ mov r2, r0; /* Save the TLS addr in r2. */ \
+ ldr r3, [r2, #PID_OFFSET]; /* Load the saved PID. */ \
+ rsbs r0, r3, #0; /* Negate it. */ \
+ moveq r0, #0x80000000; /* Use 0x80000000 if it was 0. */ \
+ str r0, [r2, #PID_OFFSET] /* Store the temporary PID. */
+#endif
/* Restore the old PID value in the parent. */
#define RESTORE_PID \
diff -Naur glibc-2.3.6_Cs/nptl/sysdeps/unix/sysv/linux/convtime.c glibc-2.3.6-AuD/nptl/sysdeps/unix/sysv/linux/convtime.c
--- glibc-2.3.6_Cs/nptl/sysdeps/unix/sysv/linux/convtime.c 1970-01-01 01:00:00.000000000 +0100
+++ glibc-2.3.6-AuD/nptl/sysdeps/unix/sysv/linux/convtime.c 2007-02-20 11:43:31.000000000 +0100
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2007 Siemens AG AD ATS 11
+ * file "convtime.c"
+ */
+
+/*
+ * initial version 20-Feb-2007
+ */
+
+#include <time.h>
+#include <sys/time.h>
+
+struct timespec *convtime(struct timespec *tsp)
+{
+ struct timeval myTimeval;
+ struct timezone myTimezone;
+
+ if (tsp) {
+ gettimeofday(&myTimeval, &myTimezone);
+ /*
+ * remark: invalid values will be dectected
+ * when the information is really used
+ */
+ tsp->tv_sec += myTimeval.tv_sec;
+ tsp->tv_nsec += myTimeval.tv_usec * 1000;
+
+ if (tsp->tv_nsec > 1000000) {
+ tsp->tv_nsec -= 1000000;
+ tsp->tv_sec++;
+ }
+ }
+
+ return(tsp);
+}
diff -Naur glibc-2.3.6_Cs/nptl/sysdeps/unix/sysv/linux/event_create.c glibc-2.3.6-AuD/nptl/sysdeps/unix/sysv/linux/event_create.c
--- glibc-2.3.6_Cs/nptl/sysdeps/unix/sysv/linux/event_create.c 1970-01-01 01:00:00.000000000 +0100
+++ glibc-2.3.6-AuD/nptl/sysdeps/unix/sysv/linux/event_create.c 2006-09-29 18:22:05.000000000 +0200
@@ -0,0 +1,69 @@
+
+/******************************************************************************
+ * The event_create() function *
+ * *
+ * creates a signalling channel for a device event specified by eventid. *
+ * The evp argument, if non-NULL, points to a sigevent structure. This *
+ * structure, allocated by the application, defines the asynchronous *
+ * notification to occur when the device event occurs. If the evp argument is *
+ * NULL, the effect is as if the evp argument points to a sigevent structure *
+ * with the sigev_notify member having the value SIGEV_SIGNAL and the *
+ * sigev_signo having the value SIGALRM. *
+ ******************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <string.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include "rtime_lib.h"
+#include "fast-handlers.h"
+
+ /* The presently used version is only preliminary. */
+
+int event_create (int fildes, struct sigevent * evp, eventid_t eventid)
+{
+ struct rt_ev_desc myEvt;
+ struct sigev* handler = NULL;
+
+ /* Initialize the handler_area the first time
+ * timer_create, event_create, timer_delete is called.
+ */
+ pthread_once (&ha_once, (void (*) (void)) init_handler_area);
+
+ /* Set up internal cmd_union element. */
+ myEvt.event = (int) eventid;
+ if (evp != NULL)
+ {
+ memcpy((void *) &myEvt.sigevent, (void *) evp, (size_t) sizeof (struct sigevent));
+ if (evp->sigev_notify == SIGEV_THREAD)
+ {
+ if ((handler = setup_handler_notification(evp, &myEvt.sigevent, fildes)) == NULL)
+ return -1;
+ handler->id = eventid;
+ }
+ }
+ else
+ { /* set the default values */
+ myEvt.sigevent.sigev_notify = SIGEV_SIGNAL;
+ myEvt.sigevent.sigev_signo = SIGALRM;
+ }
+ if (ioctl (fildes, AuD_EVENT_CREATE, &myEvt) == -1)
+ {
+ clear_handler_notification(handler); /* can handle handler == NULL */
+ return -1; /* errno is set by the ioctl() function */
+ }
+ else
+ {
+ if (myEvt.sigevent.sigev_notify == SIGEV_NONE) /* equivalent to event_delete */
+ check_handler_notification(fildes, eventid);
+ }
+ return 0;
+}
+
diff -Naur glibc-2.3.6_Cs/nptl/sysdeps/unix/sysv/linux/fast_handlers.c glibc-2.3.6-AuD/nptl/sysdeps/unix/sysv/linux/fast_handlers.c
--- glibc-2.3.6_Cs/nptl/sysdeps/unix/sysv/linux/fast_handlers.c 1970-01-01 01:00:00.000000000 +0100
+++ glibc-2.3.6-AuD/nptl/sysdeps/unix/sysv/linux/fast_handlers.c 2007-01-23 14:24:40.000000000 +0100
@@ -0,0 +1,341 @@
+
+/*
+ *
+ * 22-Aug-2006 m.n. synchronize handler thread and creation thread
+ * 23-Jan-2007 m.n. user call back did not have a parameter
+ * 23-Jan-2007 m.n. we have some race conditions between delete and callback
+ * we do some tests (T B D: sequence number for events)
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <signal.h>
+#include <pthread.h>
+#include <sysdep.h>
+#include <kernel-features.h>
+#include <internaltypes.h>
+#include <nptl/pthreadP.h>
+
+
+#include "rtime_lib.h"
+#include "fast-handlers.h"
+
+
+/* Array containing the descriptors for carrier threads */
+static struct carrier carr_arr[MAX_CARR_THREADS];
+
+/* Array containing the descriptors for event instances to be signalled */
+static struct sigev sigev_arr[MAX_SIG_HANDLERS];
+static unsigned useCntGen = 0;
+
+/* Object for manageing carrier threads and event instances */
+struct gov gov;
+
+/* Once control variable for initialization of the handler area */
+pthread_once_t ha_once = PTHREAD_ONCE_INIT;
+
+/* Setup all the needed structures */
+void init_handler_area (void)
+{
+ int i;
+ struct sched_param spars_lx;
+ struct sched_param spars_rt;
+
+ /* Initializes all list heads */
+ INIT_LIST_HEAD(&gov.carr.free);
+ INIT_LIST_HEAD(&gov.sigev.free);
+ INIT_LIST_HEAD(&gov.carr.used);
+ INIT_LIST_HEAD(&gov.sigev.used);
+
+ /* Initialize the handler area mutex */
+ pthread_mutex_init (&gov.lock, NULL);
+
+ /* Initialize the default attr objects for linux and rt domains */
+ if (pthread_attr_init (&gov.def_attr_lx) != 0)
+ return;
+ if (pthread_attr_init (&gov.def_attr_rt) != 0)
+ return;
+ if (pthread_attr_setinheritsched(&gov.def_attr_lx, PTHREAD_EXPLICIT_SCHED))
+ return;
+ if (pthread_attr_setinheritsched(&gov.def_attr_rt, PTHREAD_EXPLICIT_SCHED))
+ return;
+ if (pthread_attr_setschedpolicy(&gov.def_attr_lx, SCHED_FIFO))
+ return;
+ if (pthread_attr_setschedpolicy(&gov.def_attr_rt, SCHED_FIFO))
+ return;
+ spars_lx.sched_priority = DEF_PRIO_LINUX;
+ if (pthread_attr_setschedparam (&gov.def_attr_lx, &spars_lx))
+ return;
+ spars_rt.sched_priority = DEF_PRIO_RT;
+ if (pthread_attr_setschedparam (&gov.def_attr_rt, &spars_rt))
+ return;
+
+ if (pthread_attr_setdetachstate (&gov.def_attr_lx, PTHREAD_CREATE_DETACHED) != 0)
+ return;
+ if (pthread_attr_setdetachstate (&gov.def_attr_rt, PTHREAD_CREATE_DETACHED) != 0)
+ return;
+
+ sigemptyset (&gov.sigset);
+ sigaddset (&gov.sigset, SIGTIMER);
+ /*
+ * Set up the free list for handlers and carriers
+ * If something went wrong, the lists will be empty
+ */
+ for (i = 0; i < MAX_SIG_HANDLERS; i++)
+ list_add_tail ((struct list_head *) &sigev_arr[i].sigev_list,&gov.sigev.free );
+ for (i = 0; i < MAX_CARR_THREADS; i++)
+ list_add_tail((struct list_head *) &carr_arr[i].carr_list, &gov.carr.free);
+ return ;
+}
+
+/* Waits for the specified signal on rt_sigtimedwait and afterwards
+ * calls the corresponding handler function */
+void *
+start_carrier_thread (void *carrier_addr)
+{
+ int retval = 0;
+ siginfo_t si;
+ int oldtype;
+ sigset_t ss;
+ struct carrier *myCarr = (struct carrier *) carrier_addr;
+
+ myCarr->threadActive = 1;
+
+ sigfillset (&ss);
+ pthread_sigmask (SIG_SETMASK, &ss, NULL); /* all signals blocked */
+
+ /* Endless loop of waiting for signals.
+ * The loop terminates when the thread gets canceled. */
+ while (1)
+ {
+
+ /* Allow asynchronous cancellation. */
+ oldtype = LIBC_CANCEL_ASYNC ();
+
+ INTERNAL_SYSCALL_DECL (err);
+ /* XXX The size argument hopefully will have to be changed to the
+ real size of the user-level sigset_t. */
+ INTERNAL_SYSCALL (rt_sigtimedwait, err, 4,&gov.sigset, &si, NULL, _NSIG / 8);
+ if (INTERNAL_SYSCALL_ERROR_P (retval, err))
+ {
+ errno = EINVAL;
+ return (void *) -1;
+ }
+
+ /* Restore the old type of cancellation. */
+ LIBC_CANCEL_RESET (oldtype);
+ if ((si.si_code == SI_TIMER) || (si.si_code == SI_IOEVENT))
+ {
+ void (*func_ptr) (sigval_t);
+ sigval_t myVal;
+ int myId;
+ int myValid;
+ struct sigev *requDescr = (struct sigev *) si.si_ptr;
+ /* get the parameters */
+ myVal = requDescr->hl_param;
+ func_ptr = requDescr->handler;
+ myId = requDescr->id; // is also event id
+ /* do some consistency tests */
+ myValid = 1;
+ if (si.si_code == SI_IOEVENT) {
+ /* events: test if the sequence number is valid */
+ if (!requDescr->useCnt) {
+ myValid = 0;
+ }
+ }
+ if (myId != si.si_timerid) {
+ /* timer / event id is not valid */
+ myValid = 0;
+ }
+ /* Call the user-provided function. */
+ if (myValid && func_ptr)
+ (*func_ptr) (myVal);
+ }
+ else if (si.si_code == SI_TKILL)
+ {
+ pthread_exit (NULL);
+ }
+ } /* end while */
+}
+
+
+/* unlinks element from the free list and links it into the used list
+ * return NULL if there is no element available
+ */
+
+struct list_head * get_element(struct dbl_lhd *head)
+{
+ struct list_head* el;
+ struct list_head *list = &head->free;
+ if (list->next != list)
+ {
+ el = list->next;
+ list_del(el);
+ list_add_tail(el, &head->used);
+ return el;
+ }
+ return NULL;
+}
+
+void return_element(struct list_head * el, struct dbl_lhd *head)
+{
+ list_del (el);
+ list_add_tail(el, &head->free);
+ return;
+}
+
+struct sigev* setup_handler_notification(struct sigevent *evp, struct sigevent * kevp, int type)
+{
+ pthread_attr_t * attr;
+ int prio;
+ size_t stacksize;
+ struct sched_param param;
+ struct carrier * carr;
+ struct list_head * iter;
+ struct sigev * handler;
+ pthread_t thr;
+
+
+ if ((attr = evp->sigev_notify_attributes) == NULL)
+ { /* If attr == NULL use default values. */
+ if (IS_REALTIME)
+ attr = &gov.def_attr_rt;
+ else
+ attr = &gov.def_attr_lx;
+ }
+ /* Get the scheduling priority and the stacksize. */
+ pthread_attr_getschedparam((const pthread_attr_t *) attr, ¶m);
+ pthread_attr_getstacksize((const pthread_attr_t *) attr, &stacksize);
+ prio = param.sched_priority;
+
+ pthread_mutex_lock (&gov.lock);
+ if ((handler = (struct sigev*)get_element(&gov.sigev)) == NULL) /* Install a new sigev element. */
+ goto errout_eagain;
+ handler->type = type;
+ handler->carrier = NULL;
+ useCntGen++;
+ if (!useCntGen)
+ useCntGen++;
+ handler->useCnt = useCntGen; /* prevent use in callback during delete / new create */
+ for (iter = gov.carr.used.next; iter != &gov.carr.used; iter = iter->next)
+ {
+ carr = (struct carrier *) iter;
+ if ((carr->thread_attr == attr) && (carr->prio == prio) && (carr->stacksize == stacksize)) {
+ handler->carrier = carr;
+ goto setup_kevp; /* Found matching carrier */
+ }
+ }
+ if ((carr = (struct carrier*)get_element(&gov.carr)) == NULL)
+ goto errout_eagain;
+ carr->use_count = 0;
+ carr->threadActive = 0;
+ carr->prio = prio;
+ carr->stacksize = stacksize;
+ carr->thread_attr = attr;
+ handler->carrier = carr;
+ /* Create a new carrier thread */
+ if (pthread_create (&thr, attr, start_carrier_thread, (void *) handler->carrier) != 0) {
+ goto errout;
+ }
+ /*
+ * we may have the situation that the created thread is not yet running
+ * due to its priority; let's wait
+ * we may end up with a better approach later
+ */
+ while (!carr->threadActive) {
+ struct timespec myGenSleep;
+ myGenSleep.tv_sec = 0;
+ myGenSleep.tv_nsec =100000000;
+ nanosleep(&myGenSleep, NULL);
+ }
+
+ handler->carrier->tid = libThreadId2TaskId((struct pthread *)thr);
+
+setup_kevp:
+ handler->carrier->use_count++;
+ handler->carrier = carr;
+ handler->hl_param = evp->sigev_value;
+ handler->handler = evp->sigev_notify_function;
+ pthread_mutex_unlock (&gov.lock);
+ /* set up the sigevent object used for the kernel call */
+ kevp->sigev_value.sival_ptr = handler;
+ kevp->_sigev_un._tid = handler->carrier->tid;
+ kevp->sigev_notify = SIGEV_THREAD_ID;
+ kevp->sigev_signo = SIGTIMER;
+ return handler;
+
+errout_eagain:
+ errno = EAGAIN;
+errout:
+ pthread_mutex_unlock (&gov.lock);
+ clear_handler_notification(handler);
+ return NULL;
+}
+
+void clear_handler_notification(struct sigev *el)
+{
+ if (el == NULL)
+ return;
+
+ pthread_mutex_lock (&gov.lock);
+
+ /* delete information */
+ el->handler = NULL;
+ el->id = -1;
+ el->useCnt = 0;
+ if (el->carrier->use_count-- == 1) /* zero if no thread was created yet */
+ {
+ /* To kill the thread we send SIGCANCEL */
+ INTERNAL_SYSCALL_DECL (err);
+ INTERNAL_SYSCALL (tkill, err, 2, (pid_t) el->carrier->tid, SIGCANCEL);
+ return_element((struct list_head*)(el->carrier), &gov.carr);
+ }
+ return_element((struct list_head*)el, &gov.sigev);
+ pthread_mutex_unlock (&gov.lock);
+
+ return;
+}
+
+void check_handler_notification(int type, int id)
+{
+ struct sigev * candidate;
+ struct list_head * iter;
+
+ pthread_mutex_lock (&gov.lock);
+ for (iter = gov.sigev.used.next; iter != &gov.sigev.used; iter = iter->next)
+ {
+ candidate = (struct sigev*) iter;
+ if ((candidate->type == type) && (candidate->id == id))
+ {
+ pthread_mutex_unlock (&gov.lock);
+ clear_handler_notification(candidate);
+ return;
+ }
+ }
+ pthread_mutex_unlock (&gov.lock);
+
+ return;
+}
+
+#include <fcntl.h>
+#include <sys/ioctl.h>
+
+/* test whether a thread is part of the realtime domain */
+int testAuDrealtime()
+{
+ int retVal;
+ int fd;
+ int threadState = 0;
+
+ fd = open(AuD_DRIVER_NAME, O_RDWR);
+ if (fd >= 0) {
+ retVal = ioctl(fd, AuD_IS_REALTIME, 0);
+ if (retVal > 0)
+ threadState = 1;
+ close(fd);
+ }
+
+ return(threadState);
+}
diff -Naur glibc-2.3.6_Cs/nptl/sysdeps/unix/sysv/linux/fast-handlers.h glibc-2.3.6-AuD/nptl/sysdeps/unix/sysv/linux/fast-handlers.h
--- glibc-2.3.6_Cs/nptl/sysdeps/unix/sysv/linux/fast-handlers.h 1970-01-01 01:00:00.000000000 +0100
+++ glibc-2.3.6-AuD/nptl/sysdeps/unix/sysv/linux/fast-handlers.h 2007-01-23 12:02:00.000000000 +0100
@@ -0,0 +1,106 @@
+/*
+ *
+ * 22-Aug-2006 m.n. add variable threadActive in struct carrier to synchronize
+ * handler thread and creation thread
+ */
+
+#include <signal.h>
+#include <time.h>
+#include <pthread.h>
+#include <sys/types.h>
+#include <sysdep.h>
+#include <list.h>
+
+#include "rtime_internal.h"
+
+/******** Defines *************************************************************/
+
+#define TRUE 1
+#define FALSE 0
+
+int testAuDrealtime(void);
+#define IS_REALTIME testAuDrealtime()
+
+#define TIMER_TYPE -1
+#define EVENT_TYPE 123
+
+#define DOMAIN_LINUX 0
+#define DOMAIN_RT 1
+
+#define DEF_PRIO_RT RT_PRIORITY_MIN + 1
+#define DEF_PRIO_LINUX 1
+#define DEF_STACKSIZE 0x8000
+
+/* Max Number of carrier threads */
+#define MAX_CARR_THREADS 16
+
+/* Max Number of signal handlers */
+#define MAX_SIG_HANDLERS 256
+
+// support call to get taskid from nptl thread reference
+// Note: May have to be changed for other architectures
+static inline int libThreadId2TaskId(struct pthread * th)
+{
+ return(th->tid);
+}
+
+struct dbl_lhd {
+ struct list_head free;
+ struct list_head used;
+};
+
+/* Struct gov centralizes all data for management */
+struct gov
+{
+ struct dbl_lhd carr; /* header for free and used list for carriers */
+ struct dbl_lhd sigev; /* List header for free and used list for */
+ pthread_mutex_t lock; /* Global lock */
+ pthread_attr_t def_attr_lx; /* Default attr for linux domain */
+ pthread_attr_t def_attr_rt; /* Default attr for rt domain */
+ sigset_t sigset; /* Signal set for timer signals */
+};
+
+/* Struct to manage the carrier threads */
+struct carrier
+{
+ struct list_head carr_list; /* either linked in free or used list */
+ pthread_attr_t * thread_attr; /* thread attr used for creation */
+ int use_count; /* Usage count for this thread */
+ int threadActive; /* handler thread is working */
+ pid_t tid; /* Thread ID */
+ int prio; /* Priority of this thread */
+ int stacksize; /* Stacksize of this thread */
+};
+
+/* Struct to manage signalling instances */
+struct sigev
+{
+ struct list_head sigev_list; /* either linked in free or used list */
+ int type; /* -1: timer; 0: invalid; >0: fd of event device */
+ int id; /* timer- or event-ID */
+ unsigned useCnt;
+ struct carrier * carrier; /* Links handler with carrier_thread */
+ void (*handler)(sigval_t sigval); /* handler to execute */
+ sigval_t hl_param; /* parameter for handler */
+};
+
+/* Struct to manage the usage of handlers/carriers */
+struct usage
+{
+ unsigned used;
+ unsigned free;
+ unsigned total;
+};
+
+extern pthread_once_t ha_once;
+
+//* prototypes */
+void *start_carrier_thread (void * arg);
+void init_handler_area (void);
+struct sigev* setup_handler_notification(struct sigevent*, struct sigevent*, int);
+void clear_handler_notification(struct sigev *);
+void check_handler_notification(int, int);
+
+
+
+
diff -Naur glibc-2.3.6_Cs/nptl/sysdeps/unix/sysv/linux/get_domain.c glibc-2.3.6-AuD/nptl/sysdeps/unix/sysv/linux/get_domain.c
--- glibc-2.3.6_Cs/nptl/sysdeps/unix/sysv/linux/get_domain.c 1970-01-01 01:00:00.000000000 +0100
+++ glibc-2.3.6-AuD/nptl/sysdeps/unix/sysv/linux/get_domain.c 2006-02-01 12:56:12.000000000 +0100
@@ -0,0 +1,22 @@
+
+/******************************************************************************
+ * The get_domain() function *
+ * *
+ * shall detect in which domain the current process is runnning. *
+ * *
+ * At this point of time available domains are: *
+ * - DOMAIN_LINUX (0) *
+ * - DOMAIN_RT (1) *
+ * *
+ ******************************************************************************/
+
+#include <stdio.h>
+#include "fast-handlers.h"
+
+
+int get_domain (void)
+{
+ /* This is currently only a dummy function */
+ return DOMAIN_LINUX;
+}
+
diff -Naur glibc-2.3.6_Cs/nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h glibc-2.3.6-AuD/nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h
--- glibc-2.3.6_Cs/nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h 2005-01-20 03:18:38.000000000 +0100
+++ glibc-2.3.6-AuD/nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h 2006-02-22 16:13:16.000000000 +0100
@@ -16,6 +16,11 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
+/*
+ * Manfred.Neugebauer@siemens.com 21-Feb-2006
+ * extend structure pthread_spinlock_t for a more general use
+ */
+
#ifndef _BITS_PTHREADTYPES_H
#define _BITS_PTHREADTYPES_H 1
@@ -135,7 +140,19 @@
#ifdef __USE_XOPEN2K
/* POSIX spinlock data type. */
-typedef volatile int pthread_spinlock_t;
+/* m.n. extended for AuD use */
+typedef volatile struct
+{
+ long int __spinMagic;
+ long int __spinFlag;
+ long int __spinCount;
+ long int __spinPrivLevel;
+ long int __spinProcessId;
+ long int __spinTaskid;
+} pthread_spinlock_t;
+#define __AUD_SPINLOCK_MAGIC 0x25091921
+extern int __aud_spin_process_id;
+extern int __aud_spin_priv_level;
/* POSIX barriers data type. The structure of the type is
diff -Naur glibc-2.3.6_Cs/nptl/sysdeps/unix/sysv/linux/i386/i586/dl-sysdep.h glibc-2.3.6-AuD/nptl/sysdeps/unix/sysv/linux/i386/i586/dl-sysdep.h
--- glibc-2.3.6_Cs/nptl/sysdeps/unix/sysv/linux/i386/i586/dl-sysdep.h 1970-01-01 01:00:00.000000000 +0100
+++ glibc-2.3.6-AuD/nptl/sysdeps/unix/sysv/linux/i386/i586/dl-sysdep.h 2005-01-20 03:18:38.000000000 +0100
@@ -0,0 +1,61 @@
+/* System-specific settings for dynamic linker code. IA-32 version.
+ Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _DL_SYSDEP_H
+#define _DL_SYSDEP_H 1
+
+/* This macro must be defined to either 0 or 1.
+
+ If 1, then an errno global variable hidden in ld.so will work right with
+ all the errno-using libc code compiled for ld.so, and there is never a
+ need to share the errno location with libc. This is appropriate only if
+ all the libc functions that ld.so uses are called without PLT and always
+ get the versions linked into ld.so rather than the libc ones. */
+
+#ifdef IS_IN_rtld
+# define RTLD_PRIVATE_ERRNO 1
+#else
+# define RTLD_PRIVATE_ERRNO 0
+#endif
+
+/* Traditionally system calls have been made using int $0x80. A
+ second method was introduced which, if possible, will use the
+ sysenter/syscall instructions. To signal the presence and where to
+ find the code the kernel passes an AT_SYSINFO value in the
+ auxiliary vector to the application. */
+#define NEED_DL_SYSINFO 1
+#define USE_DL_SYSINFO 1
+
+#if defined NEED_DL_SYSINFO && !defined __ASSEMBLER__
+extern void _dl_sysinfo_int80 (void) attribute_hidden;
+# define DL_SYSINFO_DEFAULT (uintptr_t) _dl_sysinfo_int80
+# define DL_SYSINFO_IMPLEMENTATION \
+ asm (".text\n\t" \
+ ".type _dl_sysinfo_int80,@function\n\t" \
+ ".hidden _dl_sysinfo_int80\n" \
+ CFI_STARTPROC "\n" \
+ "_dl_sysinfo_int80:\n\t" \
+ "int $0x80;\n\t" \
+ "ret;\n\t" \
+ CFI_ENDPROC "\n" \
+ ".size _dl_sysinfo_int80,.-_dl_sysinfo_int80\n\t" \
+ ".previous");
+#endif
+
+#endif /* dl-sysdep.h */
diff -Naur glibc-2.3.6_Cs/nptl/sysdeps/unix/sysv/linux/i386/pthread_spin_unlock.S glibc-2.3.6-AuD/nptl/sysdeps/unix/sysv/linux/i386/pthread_spin_unlock.S
--- glibc-2.3.6_Cs/nptl/sysdeps/unix/sysv/linux/i386/pthread_spin_unlock.S 2005-01-20 03:18:38.000000000 +0100
+++ glibc-2.3.6-AuD/nptl/sysdeps/unix/sysv/linux/i386/pthread_spin_unlock.S 2006-02-22 16:13:08.000000000 +0100
@@ -1 +1,7 @@
+
+#if (0)
#include <nptl/sysdeps/i386/pthread_spin_unlock.S>
+#else
+/* see nptl/sysdeps/i386/pthread_spin_lock.c for the AuD implementation ( C based) */
+.int 5
+#endif
diff -Naur glibc-2.3.6_Cs/nptl/sysdeps/unix/sysv/linux/register_clock.c glibc-2.3.6-AuD/nptl/sysdeps/unix/sysv/linux/register_clock.c
--- glibc-2.3.6_Cs/nptl/sysdeps/unix/sysv/linux/register_clock.c 1970-01-01 01:00:00.000000000 +0100
+++ glibc-2.3.6-AuD/nptl/sysdeps/unix/sysv/linux/register_clock.c 2006-09-29 18:28:03.000000000 +0200
@@ -0,0 +1,62 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <string.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <unistd.h>
+/******************************************************************************
+ * The register_clock() function *
+ * *
+ * enables a device to act as a clock. All subsequent calls needing a clock, *
+ * thus timer_create(), clock_settime(), clock_gettime() and clock_getres() *
+ * may specifiy this clockid returned by the register_clock() function. *
+ * The flags argument specifies the special properties of timers which are *
+ * created with the clockid returned by the register_clock() function. The *
+ * flags argument may have the following values: *
+ * *
+ * SYNC_TIMER *
+ * A timer is not armed automatically by a timer_settime() call. It's *
+ * start gets deferred until a subsequent clock_settime() call. This *
+ * allows to start *
+ *****************************************************************************/
+
+
+#include "rtime_lib.h"
+
+
+clockid_t register_clock (int fildes, int flags, struct timespec *res)
+{
+ struct rt_clock_desc myClock;
+ int ret_clock = 0;
+
+ myClock.clock_type = flags;
+
+ /* Clock resolution was specified by the user. */
+ if (res != NULL)
+ {
+ /* Enter the given timespec values in the corresponding cmd_union elements.
+ * Validity has not to be checked, it's done by the kernel. */
+ myClock.clock_res.tv_sec = res->tv_sec;
+ myClock.clock_res.tv_nsec = res->tv_nsec;
+ }
+
+ /* No clock resolution was specified. */
+ else
+ {
+ myClock.clock_res.tv_sec = 0;
+ myClock.clock_res.tv_nsec = 0;
+ }
+
+ if ((ret_clock = ioctl (fildes, AuD_REGISTER_CLOCK, &myClock)) == -1)
+ {
+ /* errno is set by the ioctl() function */
+ return -1;
+ }
+ return (clockid_t) ret_clock;
+}
+
diff -Naur glibc-2.3.6_Cs/nptl/sysdeps/unix/sysv/linux/rtime_internal2.h glibc-2.3.6-AuD/nptl/sysdeps/unix/sysv/linux/rtime_internal2.h
--- glibc-2.3.6_Cs/nptl/sysdeps/unix/sysv/linux/rtime_internal2.h 1970-01-01 01:00:00.000000000 +0100
+++ glibc-2.3.6-AuD/nptl/sysdeps/unix/sysv/linux/rtime_internal2.h 2006-08-30 10:59:36.000000000 +0200
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2005 by Siemens AG, AD ATS 11, 90327 Nuernberg, Germany,
+ * Manfred.Neugebauer@siemens.com, 16-Feb-2005
+ *
+ * common definitions for the interface between kernel / driver and library
+ * to support the AuD API driver related functions
+ * (realtime, synchronous timer, events)
+ *
+ * file "rtime_internal2.h"
+ *
+ */
+
+#ifndef _RTIME_INTERNAL2_H_
+#define _RTIME_INTERNAL2_H_
+
+#define SIGTIMER __SIGRTMIN // T B D: who needs this: khk driver => move to rtime_kernel.h?
+
+/* ioctls for the aud device driver */
+#define AuD_Dev_IOCTL_BASE 0x8000
+#define AuD_REGISTER_PROCESS (AuD_Dev_IOCTL_BASE + 0x00)
+#define AuD_UNREGISTER_PROCESS (AuD_Dev_IOCTL_BASE + 0x01)
+#define AuD_PROBE_REALTIME (AuD_Dev_IOCTL_BASE + 0x02)
+#define AuD_IS_REALTIME (AuD_Dev_IOCTL_BASE + 0x03)
+#define AuD_DEV_RT_PARAM (AuD_Dev_IOCTL_BASE + 0x04)
+#define AuD_REGISTER_AND_PROBE_REALTIME (AuD_Dev_IOCTL_BASE + 0x05)
+#define AuD_TEST_RT (AuD_Dev_IOCTL_BASE + 0x06)
+#define AuD_SET_DIAGNOSIS (AuD_Dev_IOCTL_BASE + 0x07)
+#define AuD_GET_VERSION (AuD_Dev_IOCTL_BASE + 0x08)
+
+/* definitions of ioctl to handle device based API extensions (synch timer, events) */
+#define AuD_API_IOCTL_BASE 0x44410000
+#define AuD_REGISTER_CLOCK (AuD_API_IOCTL_BASE + 0x08)
+#define AuD_EVENT_CREATE (AuD_API_IOCTL_BASE + 0x09)
+#define AuD_EVENT_SET_PAR (AuD_API_IOCTL_BASE + 0x0a)
+
+struct rt_clock_desc {
+ int clock_type;
+ struct timespec clock_res;
+};
+
+struct rt_ev_desc {
+ unsigned event;
+ sigevent_t sigevent;
+};
+
+#define SIGEV_SIGNAL_SV_MAGIC 0x5f6e7d00
+
+// T B D: separate events for Linux and/or realtime?
+
+struct rt_config {
+ int no_of_timers;
+ int no_of_headers;
+ int no_of_fu_req; // for delegating futex_wake requests to Linux;
+ int buf_size; // buffer size for delegated write calls
+ int md_prio; // prio of the migration_to_rt daemon
+ int td_prio; // prio of the timeout daemon of the realtime domain
+ int dd_prio; // prio of the delegation daemon futex, other syscalls
+ int cd_prio; // prio of clock sync daemon for Linux
+ int ed_prio; // prio of event proxy daemon for Linux
+};
+
+struct exec_rt_kernel {
+ unsigned version;
+ unsigned exec_flags;
+};
+
+struct aud_version {
+ unsigned version_rt;
+ unsigned version_dev;
+};
+
+struct aud_diag {
+ unsigned diag_rt;
+ unsigned diag_dev;
+};
+
+/* diagnostic flags for aud device and realtime driver */
+#define RT_FUTEX_VERBOSE_BIT 0x001
+#define RT_WRITE_VERBOSE_BIT 0x002
+#define RT_INIT_VERBOSE_BIT 0x004
+#define RT_SHUTDOWN_VERBOSE_BIT 0x008
+#define RT_CHECK_VERBOSE_BIT 0x010
+#define RT_THREAD_VERBOSE_BIT 0x020
+#define RT_TIMER_VERBOSE_BIT 0x040
+#define RT_EVENT_VERBOSE_BIT 0x080
+#define RT_MIGRATE_VERBOSE_BIT 0x100
+#define RT_FAULT_VERBOSE_BIT 0x200
+#define RT_SYSCALL_VERBOSE_BIT 0x400
+#define AUD_DEV_VERBOSE_BIT 0x800
+
+#endif //_RTIME_INTERNAL2_H_
diff -Naur glibc-2.3.6_Cs/nptl/sysdeps/unix/sysv/linux/rtime_internal.h glibc-2.3.6-AuD/nptl/sysdeps/unix/sysv/linux/rtime_internal.h
--- glibc-2.3.6_Cs/nptl/sysdeps/unix/sysv/linux/rtime_internal.h 1970-01-01 01:00:00.000000000 +0100
+++ glibc-2.3.6-AuD/nptl/sysdeps/unix/sysv/linux/rtime_internal.h 2006-10-20 18:32:42.000000000 +0200
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2004 by Siemens AG, AD ATS 11, 90327 Nuernberg, Germany,
+ * Manfred.Neugebauer@siemens.com, 23-Feb-2004
+ *
+ * These are the internal definitions to work with a realtime subsystem
+ *
+ */
+
+#ifndef _RTIME_INTERNAL_H_
+#define _RTIME_INTERNAL_H_
+
+#define __RT_PRIORITY_MAX 99
+
+#define __LINUX_PRIORITY_MIN 0
+#define __LINUX_PRIORITY_DIST 3
+#define RT_P0 __LINUX_PRIORITY_MIN + 0 * __LINUX_PRIORITY_DIST
+#define RT_P1 __LINUX_PRIORITY_MIN + 1 * __LINUX_PRIORITY_DIST
+#define RT_P2 __LINUX_PRIORITY_MIN + 2 * __LINUX_PRIORITY_DIST
+#define RT_P3 __LINUX_PRIORITY_MIN + 3 * __LINUX_PRIORITY_DIST
+#define RT_P4 __LINUX_PRIORITY_MIN + 4 * __LINUX_PRIORITY_DIST
+#define RT_P5 __LINUX_PRIORITY_MIN + 5 * __LINUX_PRIORITY_DIST
+#define RT_P6 __LINUX_PRIORITY_MIN + 6 * __LINUX_PRIORITY_DIST
+#define RT_P7 __LINUX_PRIORITY_MIN + 7 * __LINUX_PRIORITY_DIST
+#define RT_P8 __LINUX_PRIORITY_MIN + 8 * __LINUX_PRIORITY_DIST
+#define RT_P9 __LINUX_PRIORITY_MIN + 9 * __LINUX_PRIORITY_DIST
+#define RT_P10 __LINUX_PRIORITY_MIN + 10 * __LINUX_PRIORITY_DIST
+#define RT_P11 __LINUX_PRIORITY_MIN + 11 * __LINUX_PRIORITY_DIST
+#define RT_P12 __LINUX_PRIORITY_MIN + 12 * __LINUX_PRIORITY_DIST
+#define RT_P13 __LINUX_PRIORITY_MIN + 13 * __LINUX_PRIORITY_DIST
+#define RT_P14 __LINUX_PRIORITY_MIN + 14 * __LINUX_PRIORITY_DIST
+#define RT_P15 __LINUX_PRIORITY_MIN + 15 * __LINUX_PRIORITY_DIST
+#define RT_P16 __RT_PRIORITY_MAX - 15
+#define RT_P17 __RT_PRIORITY_MAX - 14
+#define RT_P18 __RT_PRIORITY_MAX - 13
+#define RT_P19 __RT_PRIORITY_MAX - 12
+#define RT_P20 __RT_PRIORITY_MAX - 11
+#define RT_P21 __RT_PRIORITY_MAX - 10
+#define RT_P22 __RT_PRIORITY_MAX - 9
+#define RT_P23 __RT_PRIORITY_MAX - 8
+#define RT_P24 __RT_PRIORITY_MAX - 7
+#define RT_P25 __RT_PRIORITY_MAX - 6
+#define RT_P26 __RT_PRIORITY_MAX - 5
+#define RT_P27 __RT_PRIORITY_MAX - 4
+#define RT_P28 __RT_PRIORITY_MAX - 3
+#define RT_P29 __RT_PRIORITY_MAX - 2
+#define RT_P30 __RT_PRIORITY_MAX - 1
+#define RT_P31 __RT_PRIORITY_MAX - 0
+
+#define RT_PRIORITY_MIN RT_P16
+
+#define AuD_DRIVER_NAME "/dev/auddriver"
+
+/*
+ * The flags RT_SOFT and RT_HARD are used in ioctl and aud_rt_hdr.state.
+ * The remainder are flags in aud_rt_hdr.state only
+ */
+
+#define RT_SOFT 0x0010
+#define RT_HARD 0x0020
+
+#define RT_INSTALLED 0x0040
+#define RT_SHUTDOWN 0x0100
+#define RT_FAILED 0x0200
+#define RT_MASK (RT_SOFT | RT_HARD)
+
+/*
+ * prefered definitions of a set of realtime signals
+ */
+#define SIGRT0 __SIGRTMIN + 8
+#define SIGRT1 __SIGRTMIN + 9
+#define SIGRT2 __SIGRTMIN + 10
+#define SIGRT3 __SIGRTMIN + 11
+#define SIGRT4 __SIGRTMIN + 12
+#define SIGRT5 __SIGRTMIN + 13
+#define SIGRT6 __SIGRTMIN + 14
+#define SIGRT7 __SIGRTMIN + 15
+#define SIGRT8 __SIGRTMIN + 16
+#define SIGRT9 __SIGRTMIN + 17
+#define SIGRT10 __SIGRTMIN + 18
+#define SIGRT11 __SIGRTMIN + 19
+#define SIGRT12 __SIGRTMIN + 20
+#define SIGRT13 __SIGRTMIN + 21
+#define SIGRT14 __SIGRTMIN + 22
+#define SIGRT15 __SIGRTMIN + 23
+
+#define EXEC_T_STRUCT_VERSION 0x01072006
+
+typedef struct rt_exec_t_struct {
+ unsigned version;
+ unsigned exec_flags;
+} rt_exec_t;
+
+#define AuD_CLOCK_SYNC_TYPE 0x0008
+
+/* The final definition of this data type may look different.
+ * It'll be used for the event_create() function. */
+typedef unsigned int eventid_t;
+
+// from "asm-generic/siginfo.h" user segment
+// open issue: is '-8' a valid information?
+#define SI_IOEVENT (-8)
+#define si_eventid _sifields._timer._tid
+
+ // add on to siginfo.h for A&D API
+#define SIGEV_SIGNAL_SV (SIGEV_THREAD_ID | 0x10)
+ // end A&D API add on
+
+#endif //_RTIME_INTERNAL_H_
diff -Naur glibc-2.3.6_Cs/nptl/sysdeps/unix/sysv/linux/rtime_lib.h glibc-2.3.6-AuD/nptl/sysdeps/unix/sysv/linux/rtime_lib.h
--- glibc-2.3.6_Cs/nptl/sysdeps/unix/sysv/linux/rtime_lib.h 1970-01-01 01:00:00.000000000 +0100
+++ glibc-2.3.6-AuD/nptl/sysdeps/unix/sysv/linux/rtime_lib.h 2006-08-15 12:11:18.000000000 +0200
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2005 by Siemens AG, AD ATS 11, 90327 Nuernberg, Germany,
+ * Manfred.Neugebauer@siemens.com, 16-Feb-2005
+ *
+ * definitions for the kernel (realtime) driver interface to support
+ * the AuD API driver related functions
+ * (realtime, synchronous timer, events)
+ * ==> entry for the library part
+ *
+ * file "rtime_lib.h"
+ *
+ */
+
+#ifndef _RTIME_LIB_H_
+#define _RTIME_LIB_H_
+
+#define AuD_DRIVER_VERBOSE "AuDDrvVerbose"
+
+/* we have common defines with rtime_kernel.h */
+#include "rtime_internal2.h"
+
+#endif //_RTIME_LIB_H_
diff -Naur glibc-2.3.6_Cs/nptl/sysdeps/unix/sysv/linux/sigevent_set_notification.c glibc-2.3.6-AuD/nptl/sysdeps/unix/sysv/linux/sigevent_set_notification.c
--- glibc-2.3.6_Cs/nptl/sysdeps/unix/sysv/linux/sigevent_set_notification.c 1970-01-01 01:00:00.000000000 +0100
+++ glibc-2.3.6-AuD/nptl/sysdeps/unix/sysv/linux/sigevent_set_notification.c 2007-01-24 14:22:21.000000000 +0100
@@ -0,0 +1,39 @@
+
+/******************************************************************************
+ * The sigevent_set_notification() function *
+ * *
+ * refines the signal delivery attributes of a sigevent object. *
+ * *
+ ******************************************************************************/
+
+#include <stdio.h>
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+
+#include "fast-handlers.h"
+
+/* Header file rtime_kernel.h has to be included first in order to use the
+ * notification type SIGEV_SIGNAL_SV.
+ * Eventually this has to go into siginfo.h */
+#include "rtime_lib.h"
+
+
+int sigevent_set_notification (struct sigevent * evp, int cycle, int signo, pthread_t thread)
+{
+ /* Set given signo in sigevent structure */
+ evp->sigev_signo = signo;
+
+ /* Set the notification type for super vision (SV) */
+ evp->sigev_notify = SIGEV_SIGNAL_SV;
+
+ /* Provide the argument cycle for the kernel */
+ evp->sigev_value.sival_int = cycle;
+
+ /* Reference to specified thread */
+ //evp->_sigev_un._tid = ((struct pthread *)thread)->tid;
+ evp->_sigev_un._tid = libThreadId2TaskId((struct pthread *) thread);
+
+ return 0;
+}
+
diff -Naur glibc-2.3.6_Cs/nptl/sysdeps/unix/sysv/linux/timer_create.c glibc-2.3.6-AuD/nptl/sysdeps/unix/sysv/linux/timer_create.c
--- glibc-2.3.6_Cs/nptl/sysdeps/unix/sysv/linux/timer_create.c 2005-01-20 03:18:37.000000000 +0100
+++ glibc-2.3.6-AuD/nptl/sysdeps/unix/sysv/linux/timer_create.c 2007-01-23 16:33:16.000000000 +0100
@@ -1,229 +1,46 @@
-/* Copyright (C) 2003,2004 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
-
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public License as
- published by the Free Software Foundation; either version 2.1 of the
- License, or (at your option) any later version.
-
- The GNU C Library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with the GNU C Library; see the file COPYING.LIB. If not,
- write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+/******************************************************************************
+ *
+ ******************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
#include <errno.h>
#include <pthread.h>
#include <signal.h>
-#include <stdlib.h>
-#include <string.h>
#include <time.h>
#include <sysdep.h>
#include <kernel-features.h>
#include <internaltypes.h>
-#include <nptl/pthreadP.h>
-#include "kernel-posix-timers.h"
+#include "fast-handlers.h"
+
-#ifdef __NR_timer_create
-# ifndef __ASSUME_POSIX_TIMERS
-static int compat_timer_create (clockid_t clock_id, struct sigevent *evp,
- timer_t *timerid);
-# define timer_create static compat_timer_create
-# include <nptl/sysdeps/pthread/timer_create.c>
-# undef timer_create
-
-/* Nonzero if the system calls are not available. */
-int __no_posix_timers attribute_hidden;
-# endif
-
-# ifdef timer_create_alias
-# define timer_create timer_create_alias
-# endif
-
-
-int
-timer_create (clock_id, evp, timerid)
- clockid_t clock_id;
- struct sigevent *evp;
- timer_t *timerid;
+int timer_create (clockid_t clock_id, struct sigevent * evp, timer_t * timerid)
{
-# undef timer_create
-# ifndef __ASSUME_POSIX_TIMERS
- if (__no_posix_timers >= 0)
-# endif
- {
- /* If the user wants notification via a thread we need to handle
- this special. */
- if (evp == NULL
- || __builtin_expect (evp->sigev_notify != SIGEV_THREAD, 1))
- {
- struct sigevent local_evp;
+ struct sigev * handler = NULL;
+ struct sigevent k_sig_event, *kevp;
- /* We avoid allocating too much memory by basically
- using struct timer as a derived class with the
- first two elements being in the superclass. We only
- need these two elements here. */
- struct timer *newp = (struct timer *) malloc (offsetof (struct timer,
- thrfunc));
- if (newp == NULL)
- /* No more memory. */
- return -1;
-
- if (evp == NULL)
- {
- /* The kernel has to pass up the timer ID which is a
- userlevel object. Therefore we cannot leave it up to
- the kernel to determine it. */
- local_evp.sigev_notify = SIGEV_SIGNAL;
- local_evp.sigev_signo = SIGALRM;
- local_evp.sigev_value.sival_ptr = newp;
-
- evp = &local_evp;
- }
-
- kernel_timer_t ktimerid;
- int retval = INLINE_SYSCALL (timer_create, 3, clock_id, evp,
- &ktimerid);
-
-# ifndef __ASSUME_POSIX_TIMERS
- if (retval != -1 || errno != ENOSYS)
-# endif
- {
-# ifndef __ASSUME_POSIX_TIMERS
- __no_posix_timers = 1;
-# endif
-
- if (retval != -1)
- {
- newp->sigev_notify = (evp != NULL
- ? evp->sigev_notify : SIGEV_SIGNAL);
- newp->ktimerid = ktimerid;
-
- *timerid = (timer_t) newp;
- }
- else
- {
- /* Cannot allocate the timer, fail. */
- free (newp);
- retval = -1;
- }
-
- return retval;
- }
-
- free (newp);
-
-# ifndef __ASSUME_POSIX_TIMERS
- /* When we come here the syscall does not exist. Make sure we
- do not try to use it again. */
- __no_posix_timers = -1;
-# endif
- }
- else
+ /* Initialize the handler_area the first time
+ * timer_create, event_create, timer_delete is called.
+ */
+ pthread_once (&ha_once, (void (*) (void)) init_handler_area);
+
+ kevp = evp;
+ if (evp->sigev_notify == SIGEV_THREAD)
{
-# ifndef __ASSUME_POSIX_TIMERS
- /* Make sure we have the necessary kernel support. */
- if (__no_posix_timers == 0)
- {
- INTERNAL_SYSCALL_DECL (err);
- struct timespec ts;
- int res;
- res = INTERNAL_SYSCALL (clock_getres, err, 2,
- CLOCK_REALTIME, &ts);
- __no_posix_timers = (INTERNAL_SYSCALL_ERROR_P (res, err)
- ? -1 : 1);
- }
-
- if (__no_posix_timers > 0)
-# endif
- {
- /* Create the helper thread. */
- pthread_once (&__helper_once, __start_helper_thread);
- if (__helper_tid == 0)
- {
- /* No resources to start the helper thread. */
- __set_errno (EAGAIN);
- return -1;
- }
-
- struct timer *newp;
- newp = (struct timer *) malloc (sizeof (struct timer));
- if (newp == NULL)
- return -1;
-
- /* Copy the thread parameters the user provided. */
- newp->sival = evp->sigev_value;
- newp->thrfunc = evp->sigev_notify_function;
-
- /* We cannot simply copy the thread attributes since the
- implementation might keep internal information for
- each instance. */
- (void) pthread_attr_init (&newp->attr);
- if (evp->sigev_notify_attributes != NULL)
- {
- struct pthread_attr *nattr;
- struct pthread_attr *oattr;
-
- nattr = (struct pthread_attr *) &newp->attr;
- oattr = (struct pthread_attr *) evp->sigev_notify_attributes;
-
- nattr->schedparam = oattr->schedparam;
- nattr->schedpolicy = oattr->schedpolicy;
- nattr->flags = oattr->flags;
- nattr->guardsize = oattr->guardsize;
- nattr->stackaddr = oattr->stackaddr;
- nattr->stacksize = oattr->stacksize;
- }
-
- /* In any case set the detach flag. */
- (void) pthread_attr_setdetachstate (&newp->attr,
- PTHREAD_CREATE_DETACHED);
-
- /* Create the event structure for the kernel timer. */
- struct sigevent sev;
- sev.sigev_value.sival_ptr = newp;
- sev.sigev_signo = SIGTIMER;
- sev.sigev_notify = SIGEV_SIGNAL | SIGEV_THREAD_ID;
- /* This is the thread ID of the helper thread. */
- sev._sigev_un._pad[0] = __helper_tid;
-
- /* Create the timer. */
- INTERNAL_SYSCALL_DECL (err);
- int res;
- res = INTERNAL_SYSCALL (timer_create, err, 3, clock_id, &sev,
- &newp->ktimerid);
- if (! INTERNAL_SYSCALL_ERROR_P (res, err))
- {
- *timerid = (timer_t) newp;
- return 0;
- }
-
- /* Free the resources. */
- free (newp);
-
- __set_errno (INTERNAL_SYSCALL_ERRNO (res, err));
-
- return -1;
- }
+ if ((handler = setup_handler_notification(evp, &k_sig_event, TIMER_TYPE)) == NULL)
+ return -1; /* errno is set by setup_handler_notification() */
+ kevp = &k_sig_event; /* we have to use the modified sigevent object */
}
- }
-
-# ifndef __ASSUME_POSIX_TIMERS
- /* Compatibility code. */
- return compat_timer_create (clock_id, evp, timerid);
-# endif
+ /* The kernel handles the default values if evp */
+ if (INLINE_SYSCALL (timer_create, 3, clock_id, kevp, timerid) != 0)
+ {
+ clear_handler_notification(handler); /* can handle handler == NULL */
+ return -1;
+ }
+ if (handler != NULL)
+ handler->id = (int)*timerid;
+return 0;
}
-#else
-# ifdef timer_create_alias
-# define timer_create timer_create_alias
-# endif
-/* The new system calls are not available. Use the userlevel
- implementation. */
-# include <nptl/sysdeps/pthread/timer_create.c>
-#endif
+
diff -Naur glibc-2.3.6_Cs/nptl/sysdeps/unix/sysv/linux/timer_delete.c glibc-2.3.6-AuD/nptl/sysdeps/unix/sysv/linux/timer_delete.c
--- glibc-2.3.6_Cs/nptl/sysdeps/unix/sysv/linux/timer_delete.c 2005-01-20 03:18:37.000000000 +0100
+++ glibc-2.3.6-AuD/nptl/sysdeps/unix/sysv/linux/timer_delete.c 2006-07-14 17:51:40.000000000 +0200
@@ -1,94 +1,28 @@
-/* Copyright (C) 2003 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public License as
- published by the Free Software Foundation; either version 2.1 of the
- License, or (at your option) any later version.
+/******************************************************************************
+ *
+ ******************************************************************************/
- The GNU C Library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with the GNU C Library; see the file COPYING.LIB. If not,
- write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
-
-#include <errno.h>
+#include <stdio.h>
#include <stdlib.h>
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
#include <time.h>
#include <sysdep.h>
#include <kernel-features.h>
-#include "kernel-posix-timers.h"
-
+#include <internaltypes.h>
+#include "fast-handlers.h"
-#ifdef __NR_timer_delete
-# ifndef __ASSUME_POSIX_TIMERS
-static int compat_timer_delete (timer_t timerid);
-# define timer_delete static compat_timer_delete
-# include <nptl/sysdeps/pthread/timer_delete.c>
-# undef timer_delete
-# endif
-# ifdef timer_delete_alias
-# define timer_delete timer_delete_alias
-# endif
-
-
-int
-timer_delete (timerid)
- timer_t timerid;
+int timer_delete (timer_t timerid) /* Delete the kernel timer object. */
{
-# undef timer_delete
-# ifndef __ASSUME_POSIX_TIMERS
- if (__no_posix_timers >= 0)
-# endif
- {
- struct timer *kt = (struct timer *) timerid;
-
- /* Delete the kernel timer object. */
- int res = INLINE_SYSCALL (timer_delete, 1, kt->ktimerid);
-
- if (res == 0)
+ if (INLINE_SYSCALL (timer_delete, 1, timerid) != 0)
{
-# ifndef __ASSUME_POSIX_TIMERS
- /* We know the syscall support is available. */
- __no_posix_timers = 1;
-# endif
-
- /* Free the memory. */
- (void) free (kt);
-
- return 0;
- }
-
- /* The kernel timer is not known or something else bad happened.
- Return the error. */
-# ifndef __ASSUME_POSIX_TIMERS
- if (errno != ENOSYS)
- {
- __no_posix_timers = 1;
-# endif
- return -1;
-# ifndef __ASSUME_POSIX_TIMERS
+ /* errno is set by the INLINE_SYSCALL */
+ return -1;
}
-
- __no_posix_timers = -1;
-# endif
- }
-
-# ifndef __ASSUME_POSIX_TIMERS
- return compat_timer_delete (timerid);
-# endif
+ check_handler_notification(TIMER_TYPE, (int) timerid);
+ return 0;
}
-#else
-# ifdef timer_delete_alias
-# define timer_delete timer_delete_alias
-# endif
-/* The new system calls are not available. Use the userlevel
- implementation. */
-# include <nptl/sysdeps/pthread/timer_delete.c>
-#endif
+
diff -Naur glibc-2.3.6_Cs/nptl/sysdeps/unix/sysv/linux/timer_getoverr.c glibc-2.3.6-AuD/nptl/sysdeps/unix/sysv/linux/timer_getoverr.c
--- glibc-2.3.6_Cs/nptl/sysdeps/unix/sysv/linux/timer_getoverr.c 2005-01-20 03:18:37.000000000 +0100
+++ glibc-2.3.6-AuD/nptl/sysdeps/unix/sysv/linux/timer_getoverr.c 2006-10-05 14:50:08.000000000 +0200
@@ -17,65 +17,19 @@
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
+/*
+ * m.n. siemens ag, this call is not part of the AuD API
+ * we provide this error stub to handle linking of posix test programs
+ */
#include <errno.h>
#include <time.h>
#include <sysdep.h>
#include <kernel-features.h>
#include "kernel-posix-timers.h"
-
-#ifdef __NR_timer_getoverrun
-# ifndef __ASSUME_POSIX_TIMERS
-static int compat_timer_getoverrun (timer_t timerid);
-# define timer_getoverrun static compat_timer_getoverrun
-# include <nptl/sysdeps/pthread/timer_getoverr.c>
-# undef timer_getoverrun
-# endif
-
-# ifdef timer_getoverrun_alias
-# define timer_getoverrun timer_getoverrun_alias
-# endif
-
-
int
timer_getoverrun (timerid)
timer_t timerid;
{
-# undef timer_getoverrun
-# ifndef __ASSUME_POSIX_TIMERS
- if (__no_posix_timers >= 0)
-# endif
- {
- struct timer *kt = (struct timer *) timerid;
-
- /* Get the information from the kernel. */
- int res = INLINE_SYSCALL (timer_getoverrun, 1, kt->ktimerid);
-
-# ifndef __ASSUME_POSIX_TIMERS
- if (res != -1 || errno != ENOSYS)
- {
- /* We know the syscall support is available. */
- __no_posix_timers = 1;
-# endif
- return res;
-# ifndef __ASSUME_POSIX_TIMERS
- }
-# endif
-
-# ifndef __ASSUME_POSIX_TIMERS
- __no_posix_timers = -1;
-# endif
- }
-
-# ifndef __ASSUME_POSIX_TIMERS
- return compat_timer_getoverrun (timerid);
-# endif
+ return(ENOSYS);
}
-#else
-# ifdef timer_getoverrun_alias
-# define timer_getoverrun timer_getoverrun_alias
-# endif
-/* The new system calls are not available. Use the userlevel
- implementation. */
-# include <nptl/sysdeps/pthread/timer_getoverr.c>
-#endif
diff -Naur glibc-2.3.6_Cs/nptl/sysdeps/unix/sysv/linux/timer_gettime.c glibc-2.3.6-AuD/nptl/sysdeps/unix/sysv/linux/timer_gettime.c
--- glibc-2.3.6_Cs/nptl/sysdeps/unix/sysv/linux/timer_gettime.c 2005-01-20 03:18:37.000000000 +0100
+++ glibc-2.3.6-AuD/nptl/sysdeps/unix/sysv/linux/timer_gettime.c 2006-02-01 12:56:18.000000000 +0100
@@ -1,83 +1,28 @@
-/* Copyright (C) 2003 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
-
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public License as
- published by the Free Software Foundation; either version 2.1 of the
- License, or (at your option) any later version.
-
- The GNU C Library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with the GNU C Library; see the file COPYING.LIB. If not,
- write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
-#include <errno.h>
+/******************************************************************************
+ *
+ ******************************************************************************/
+
+#include <stdio.h>
#include <stdlib.h>
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
#include <time.h>
#include <sysdep.h>
#include <kernel-features.h>
-#include "kernel-posix-timers.h"
+#include <internaltypes.h>
-#ifdef __NR_timer_gettime
-# ifndef __ASSUME_POSIX_TIMERS
-static int compat_timer_gettime (timer_t timerid, struct itimerspec *value);
-# define timer_gettime static compat_timer_gettime
-# include <nptl/sysdeps/pthread/timer_gettime.c>
-# undef timer_gettime
-# endif
-
-# ifdef timer_gettime_alias
-# define timer_gettime timer_gettime_alias
-# endif
-
-
-int
-timer_gettime (timerid, value)
- timer_t timerid;
- struct itimerspec *value;
+
+int timer_gettime (timer_t timerid, struct itimerspec * value)
{
-# undef timer_gettime
-# ifndef __ASSUME_POSIX_TIMERS
- if (__no_posix_timers >= 0)
-# endif
- {
- struct timer *kt = (struct timer *) timerid;
-
- /* Delete the kernel timer object. */
- int res = INLINE_SYSCALL (timer_gettime, 2, kt->ktimerid, value);
-
-# ifndef __ASSUME_POSIX_TIMERS
- if (res != -1 || errno != ENOSYS)
- {
- /* We know the syscall support is available. */
- __no_posix_timers = 1;
-# endif
- return res;
-# ifndef __ASSUME_POSIX_TIMERS
+ int retval = 0;
+ if ((retval = INLINE_SYSCALL (timer_gettime, 2, timerid, value)) != 0)
+ {
+ /* errno is set by the INLINE_SYSCALL */
+ return -1;/* errno is set by the function thread_alloc() */
}
-# endif
-
-# ifndef __ASSUME_POSIX_TIMERS
- __no_posix_timers = -1;
-# endif
- }
-
-# ifndef __ASSUME_POSIX_TIMERS
- return compat_timer_gettime (timerid, value);
-# endif
+ return 0;
}
-#else
-# ifdef timer_gettime_alias
-# define timer_gettime timer_gettime_alias
-# endif
-/* The new system calls are not available. Use the userlevel
- implementation. */
-# include <nptl/sysdeps/pthread/timer_gettime.c>
-#endif
+
diff -Naur glibc-2.3.6_Cs/nptl/sysdeps/unix/sysv/linux/timer_settime.c glibc-2.3.6-AuD/nptl/sysdeps/unix/sysv/linux/timer_settime.c
--- glibc-2.3.6_Cs/nptl/sysdeps/unix/sysv/linux/timer_settime.c 2005-01-20 03:18:37.000000000 +0100
+++ glibc-2.3.6-AuD/nptl/sysdeps/unix/sysv/linux/timer_settime.c 2006-02-01 12:56:18.000000000 +0100
@@ -1,88 +1,29 @@
-/* Copyright (C) 2003 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public License as
- published by the Free Software Foundation; either version 2.1 of the
- License, or (at your option) any later version.
+/******************************************************************************
+ *
+ ******************************************************************************/
- The GNU C Library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with the GNU C Library; see the file COPYING.LIB. If not,
- write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
-
-#include <errno.h>
+#include <stdio.h>
#include <stdlib.h>
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
#include <time.h>
#include <sysdep.h>
#include <kernel-features.h>
-#include "kernel-posix-timers.h"
-
+#include <internaltypes.h>
-#ifdef __NR_timer_settime
-# ifndef __ASSUME_POSIX_TIMERS
-static int compat_timer_settime (timer_t timerid, int flags,
- const struct itimerspec *value,
- struct itimerspec *ovalue);
-# define timer_settime static compat_timer_settime
-# include <nptl/sysdeps/pthread/timer_settime.c>
-# undef timer_settime
-# endif
-# ifdef timer_settime_alias
-# define timer_settime timer_settime_alias
-# endif
-
-int
-timer_settime (timerid, flags, value, ovalue)
- timer_t timerid;
- int flags;
- const struct itimerspec *value;
- struct itimerspec *ovalue;
+int timer_settime (timer_t timerid, int flags, const struct itimerspec * value, struct itimerspec * ovalue)
{
-# undef timer_settime
-# ifndef __ASSUME_POSIX_TIMERS
- if (__no_posix_timers >= 0)
-# endif
- {
- struct timer *kt = (struct timer *) timerid;
-
- /* Delete the kernel timer object. */
- int res = INLINE_SYSCALL (timer_settime, 4, kt->ktimerid, flags,
- value, ovalue);
-
-# ifndef __ASSUME_POSIX_TIMERS
- if (res != -1 || errno != ENOSYS)
- {
- /* We know the syscall support is available. */
- __no_posix_timers = 1;
-# endif
- return res;
-# ifndef __ASSUME_POSIX_TIMERS
+ int retval = 0;
+ /* Set the time of the next expiration of the timer specified by timerid. */
+ if ((retval = INLINE_SYSCALL (timer_settime, 4, timerid,
+ flags, value, ovalue)) != 0)
+ {
+ /* errno is set by the INLINE_SYSCALL */
+ return -1;
}
-# endif
-
-# ifndef __ASSUME_POSIX_TIMERS
- __no_posix_timers = -1;
-# endif
- }
-
-# ifndef __ASSUME_POSIX_TIMERS
- return compat_timer_settime (timerid, flags, value, ovalue);
-# endif
+ return 0;
}
-#else
-# ifdef timer_settime_alias
-# define timer_settime timer_settime_alias
-# endif
-/* The new system calls are not available. Use the userlevel
- implementation. */
-# include <nptl/sysdeps/pthread/timer_settime.c>
-#endif
diff -Naur glibc-2.3.6_Cs/nptl/Versions glibc-2.3.6-AuD/nptl/Versions
--- glibc-2.3.6_Cs/nptl/Versions 2005-01-20 03:18:36.000000000 +0100
+++ glibc-2.3.6-AuD/nptl/Versions 2006-10-06 18:37:31.000000000 +0200
@@ -150,6 +150,9 @@
GLIBC_2.2 {
pthread_mutexattr_getpshared; pthread_mutexattr_setpshared;
+ # m.n. siemens ag: ad api
+ pthread_mutexattr_getprioceiling; pthread_mutexattr_setprioceiling;
+ pthread_mutexattr_getprotocol; pthread_mutexattr_setprotocol;
pthread_condattr_getpshared; pthread_condattr_setpshared;
diff -Naur glibc-2.3.6_Cs/rt/Makefile glibc-2.3.6-AuD/rt/Makefile
--- glibc-2.3.6_Cs/rt/Makefile 2005-01-20 03:18:40.000000000 +0100
+++ glibc-2.3.6-AuD/rt/Makefile 2007-02-20 11:28:23.000000000 +0100
@@ -19,6 +19,18 @@
#
# Sub-makefile for real-time portion of the library.
#
+
+#
+# m.n. 31-Jan-2006
+# add: fast_handlers event_create register_clock sigevent_set_notification
+# remove: timer_getoverr
+#
+
+#
+# m.n. 20-Feb-2007
+# add: convtime
+#
+
subdir := rt
headers := aio.h mqueue.h bits/mqueue.h
@@ -31,7 +43,9 @@
clock_getres clock_gettime clock_settime \
clock_nanosleep
timer-routines := timer_create timer_delete timer_getoverr \
- timer_gettime timer_settime
+ timer_gettime timer_settime fast_handlers \
+ event_create register_clock sigevent_set_notification \
+ convtime
shm-routines := shm_open shm_unlink
mq-routines := mq_open mq_close mq_unlink mq_getattr mq_setattr \
mq_notify mq_send mq_receive mq_timedsend \
diff -Naur glibc-2.3.6_Cs/rt/Versions glibc-2.3.6-AuD/rt/Versions
--- glibc-2.3.6_Cs/rt/Versions 2005-01-20 03:18:40.000000000 +0100
+++ glibc-2.3.6-AuD/rt/Versions 2007-02-20 19:30:03.000000000 +0100
@@ -14,8 +14,12 @@
shm_open; shm_unlink;
# t*
+ # m.n. skip timer_getoverrun
timer_create; timer_delete; timer_getoverrun; timer_gettime;
timer_settime;
+ # m.n. add AuD API
+ event_create; sigevent_set_notification; register_clock;
+ convtime;
}
GLIBC_2.3.4 {
# m*
diff -Naur glibc-2.3.6_Cs/sysdeps/generic/libc-start.c glibc-2.3.6-AuD/sysdeps/generic/libc-start.c
--- glibc-2.3.6_Cs/sysdeps/generic/libc-start.c 2005-11-09 05:04:59.000000000 +0100
+++ glibc-2.3.6-AuD/sysdeps/generic/libc-start.c 2007-02-15 14:09:46.000000000 +0100
@@ -176,6 +176,7 @@
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS, 0))
GLRO(dl_debug_printf) ("\ninitialize program: %s\n\n", argv[0]);
#endif
+
if (init)
(*init) (
#ifdef INIT_MAIN_ARGS
@@ -239,3 +240,10 @@
exit (result);
}
+
+int printAddress(char *string, unsigned ref)
+{
+//asm("swi 0x9f0080");
+return(1);
+}
+
diff -Naur glibc-2.3.6_Cs/sysdeps/generic/libc-tls.c glibc-2.3.6-AuD/sysdeps/generic/libc-tls.c
--- glibc-2.3.6_Cs/sysdeps/generic/libc-tls.c 2005-11-09 05:04:59.000000000 +0100
+++ glibc-2.3.6-AuD/sysdeps/generic/libc-tls.c 2007-02-19 14:19:08.000000000 +0100
@@ -106,11 +106,12 @@
GL(dl_tls_static_nelem) = GL(dl_tls_max_dtv_idx);
}
+extern const char *_dl_platform;
void
__libc_setup_tls (size_t tcbsize, size_t tcbalign)
{
void *tlsblock;
- size_t memsz = 0;
+ size_t memsz = 256; // m.n. make sure that we always allocate tls memory */
size_t filesz = 0;
void *initimage = NULL;
size_t align = 0;
@@ -125,6 +126,7 @@
{
/* Remember the values we need. */
memsz = phdr->p_memsz;
+//m.n. memsz += phdr->p_memsz;
filesz = phdr->p_filesz;
initimage = (void *) phdr->p_vaddr;
align = phdr->p_align;
@@ -157,7 +159,7 @@
tcb_offset = roundup (memsz + GL(dl_tls_static_size), tcbalign);
tlsblock = __sbrk (tcb_offset + tcbsize + max_align);
# elif TLS_DTV_AT_TP
- tcb_offset = roundup (tcbsize, align ?: 1);
+ tcb_offset = roundup (tcbsize, align ? : 1);
tlsblock = __sbrk (tcb_offset + memsz + max_align
+ TLS_PRE_TCB_SIZE + GL(dl_tls_static_size));
tlsblock += TLS_PRE_TCB_SIZE;
@@ -166,7 +168,6 @@
is defined add another #elif here and in the following #ifs. */
# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
# endif
-
/* Align the TLS block. */
tlsblock = (void *) (((uintptr_t) tlsblock + max_align - 1)
& ~(max_align - 1));
@@ -190,7 +191,6 @@
memcpy (static_dtv[2].pointer, initimage, filesz);
/* Install the pointer to the dtv. */
-
/* Initialize the thread pointer. */
# if TLS_TCB_AT_TP
INSTALL_DTV ((char *) tlsblock + tcb_offset, static_dtv);
@@ -256,6 +256,20 @@
__pthread_initialize_minimal (void)
{
__libc_setup_tls (TLS_INIT_TCB_SIZE, TLS_INIT_TCB_ALIGN);
+
+ /*
+ * m.n. siemens ag: we need an extended minimal tls init:
+ * pid and tid are are required by e.g., raise()
+ */
+ /* We must prevent gcc from being clever and move any of the
+ following code ahead of the __libc_setup_tls call. This function
+ will initialize the thread register which is subsequently
+ used. */
+ __asm __volatile ("");
+ /* Minimal initialization of the thread descriptor. */
+ struct pthread *pd = THREAD_SELF;
+ INTERNAL_SYSCALL_DECL (err);
+ pd->pid = pd->tid = INTERNAL_SYSCALL (set_tid_address, err, 1, &pd->tid);
}
#elif defined NONTLS_INIT_TP
@@ -270,3 +284,4 @@
}
#endif
+
diff -Naur glibc-2.3.6_Cs/sysdeps/posix/clock_getres.c glibc-2.3.6-AuD/sysdeps/posix/clock_getres.c
--- glibc-2.3.6_Cs/sysdeps/posix/clock_getres.c 2005-01-20 03:18:46.000000000 +0100
+++ glibc-2.3.6-AuD/sysdeps/posix/clock_getres.c 2006-10-10 17:39:01.000000000 +0200
@@ -70,7 +70,11 @@
!= CLOCK_THREAD_CPUTIME_ID)
#endif
{
+#ifdef SYSDEP_GETRES // m.n. siemens ag: support sync clock
+ goto doSyscallGetres;
+#else
__set_errno (EINVAL);
+#endif
break;
}
diff -Naur glibc-2.3.6_Cs/sysdeps/unix/arm/sysdep.S glibc-2.3.6-AuD/sysdeps/unix/arm/sysdep.S
--- glibc-2.3.6_Cs/sysdeps/unix/arm/sysdep.S 2006-01-06 17:15:35.000000000 +0100
+++ glibc-2.3.6-AuD/sysdeps/unix/arm/sysdep.S 2007-02-02 18:57:50.000000000 +0100
@@ -1,6 +1,4 @@
-/* Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 2002, 2003,
- 2004, 2005
- Free Software Foundation, Inc.
+/* Copyright (C) 1991,92,93,94,95,96,97,98,2002,03 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -47,6 +45,11 @@
mov r1, r0
mov r0, #0xffff0fff
+#ifdef CONFIG_NOMMU_USE_LOW_ADDR
+/* m.n. arm without mmu needs an entry at the first memory page */
+ mov r0, #0x1000
+ sub r0, #0x1
+#endif
mov lr, pc
sub pc, r0, #31
diff -Naur glibc-2.3.6_Cs/sysdeps/unix/clock_gettime.c glibc-2.3.6-AuD/sysdeps/unix/clock_gettime.c
--- glibc-2.3.6_Cs/sysdeps/unix/clock_gettime.c 2005-01-20 03:18:49.000000000 +0100
+++ glibc-2.3.6-AuD/sysdeps/unix/clock_gettime.c 2006-07-18 07:59:26.000000000 +0200
@@ -15,6 +15,10 @@
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
+/*
+ * Manfred.Neugebauer, Siemens AG, AD ATS 11, 90327 Nuernberg, Germany, 30-March-2004
+ * allow a system call with an arbitrary clock id
+ */
#include <errno.h>
#include <stdint.h>
@@ -71,7 +75,11 @@
!= CLOCK_THREAD_CPUTIME_ID)
#endif
{
+#ifdef SYSDEP_GETTIME
+ goto doSyscallGettime;
+#else
__set_errno (EINVAL);
+#endif
break;
}
diff -Naur glibc-2.3.6_Cs/sysdeps/unix/clock_settime.c glibc-2.3.6-AuD/sysdeps/unix/clock_settime.c
--- glibc-2.3.6_Cs/sysdeps/unix/clock_settime.c 2005-01-20 03:18:49.000000000 +0100
+++ glibc-2.3.6-AuD/sysdeps/unix/clock_settime.c 2006-07-18 08:07:14.000000000 +0200
@@ -15,6 +15,10 @@
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
+/*
+ * Manfred.Neugebauer, Siemens AG, AD ATS 11, 90327 Nuernberg, Germany, 30-March-2004
+ * allow a system call with an arbitrary clock id
+ */
#include <errno.h>
#include <time.h>
@@ -75,7 +79,11 @@
!= CLOCK_THREAD_CPUTIME_ID)
#endif
{
+#ifdef SYSDEP_SETTIME
+ goto doSyscallSettime;
+#else
__set_errno (EINVAL);
+#endif
retval = -1;
break;
}
diff -Naur glibc-2.3.6_Cs/sysdeps/unix/sysv/linux/arm/aeabi_read_tp.S glibc-2.3.6-AuD/sysdeps/unix/sysv/linux/arm/aeabi_read_tp.S
--- glibc-2.3.6_Cs/sysdeps/unix/sysv/linux/arm/aeabi_read_tp.S 2005-11-03 15:44:57.000000000 +0100
+++ glibc-2.3.6-AuD/sysdeps/unix/sysv/linux/arm/aeabi_read_tp.S 2007-02-01 13:45:07.000000000 +0100
@@ -41,11 +41,16 @@
equivalent helper function (which clobbers fewer registers than
a normal function call) in a high page of memory; tail call to the
helper. */
-
+/* m.n. arm without mmu can"t access top memory */
.hidden __aeabi_read_tp
ENTRY (__aeabi_read_tp)
mov r0, #0xffff0fff
+#ifdef CONFIG_NOMMU_USE_LOW_ADDR
+ ldr r0, __aeabi_read_tp_offset
+#endif
sub pc, r0, #31
+__aeabi_read_tp_offset:
+.int 0x0fff
END (__aeabi_read_tp)
#endif
diff -Naur glibc-2.3.6_Cs/sysdeps/unix/sysv/linux/arm/eabi/sigrestorer.S glibc-2.3.6-AuD/sysdeps/unix/sysv/linux/arm/eabi/sigrestorer.S
--- glibc-2.3.6_Cs/sysdeps/unix/sysv/linux/arm/eabi/sigrestorer.S 2006-01-06 17:15:36.000000000 +0100
+++ glibc-2.3.6-AuD/sysdeps/unix/sysv/linux/arm/eabi/sigrestorer.S 2006-09-21 14:47:46.000000000 +0200
@@ -36,7 +36,8 @@
.pad #12
nop
ENTRY(__default_sa_restorer)
- mov r7, $SYS_ify(sigreturn)
+/* mov r7, SYS_ify(sigreturn) */
+ ldr r7, = SYS_ify(sigreturn) /* m.n. assembler problem ?? */
swi 0x0
.fnend
@@ -47,7 +48,8 @@
.pad #168
nop
ENTRY(__default_rt_sa_restorer)
- mov r7, $SYS_ify(rt_sigreturn)
+/* mov r7, $SYS_ify(rt_sigreturn) */
+ ldr r7, = SYS_ify(rt_sigreturn) /* m.n. assembler problem ?? */
swi 0x0
.fnend
diff -Naur glibc-2.3.6_Cs/sysdeps/unix/sysv/linux/arm/eabi/sysdep.h glibc-2.3.6-AuD/sysdeps/unix/sysv/linux/arm/eabi/sysdep.h
--- glibc-2.3.6_Cs/sysdeps/unix/sysv/linux/arm/eabi/sysdep.h 2006-03-24 20:31:33.000000000 +0100
+++ glibc-2.3.6-AuD/sysdeps/unix/sysv/linux/arm/eabi/sysdep.h 2006-09-29 17:11:16.000000000 +0200
@@ -26,7 +26,7 @@
#include <arm/sysdep.h>
#if __NR_SYSCALL_BASE != 0
-# error Kernel headers are too old
+//m.n.# error Kernel headers are too old
#endif
/* Don't use stime, even if the kernel headers define it. We have
@@ -70,7 +70,8 @@
The assembler will convert the literal pool load to a move for most
syscalls. */
-
+
+// m.n. we have problems with linux kernel 2.6.14 header files
#undef DO_CALL
#define DO_CALL(syscall_name, args) \
DOARGS_##args \
diff -Naur glibc-2.3.6_Cs/sysdeps/unix/sysv/linux/arm/sysdep.h glibc-2.3.6-AuD/sysdeps/unix/sysv/linux/arm/sysdep.h
--- glibc-2.3.6_Cs/sysdeps/unix/sysv/linux/arm/sysdep.h 2006-01-06 17:15:35.000000000 +0100
+++ glibc-2.3.6-AuD/sysdeps/unix/sysv/linux/arm/sysdep.h 2006-10-06 15:02:38.000000000 +0200
@@ -205,7 +205,7 @@
#define INTERNAL_SYSCALL_DECL(err) do { } while (0)
#undef INTERNAL_SYSCALL_RAW
-#define INTERNAL_SYSCALL_RAW(name, err, nr, args...) \
+#define INTERNAL_SYSCALL_RAWx(name, err, nr, args...) \
({ unsigned int _sys_result; \
{ \
register int _a1 asm ("a1"); \
@@ -218,13 +218,19 @@
} \
(int) _sys_result; })
+// m.n. we have two versions of INTERNAL_SYSCALL_RAW: one here
+// the other in subdirectory sysdeps/unix/sysv/linux/eabi
+// the last one uses r7 to pass the kernel call id
+// we are not yet sure whether we can use it
+// so we stay with the old idea and give RAW a separate name
+// to prevent overwriting
#undef INTERNAL_SYSCALL
#define INTERNAL_SYSCALL(name, err, nr, args...) \
- INTERNAL_SYSCALL_RAW(SYS_ify(name), err, nr, args)
+ INTERNAL_SYSCALL_RAWx(SYS_ify(name), err, nr, args)
#undef INTERNAL_SYSCALL_ARM
#define INTERNAL_SYSCALL_ARM(name, err, nr, args...) \
- INTERNAL_SYSCALL_RAW(__ARM_NR_##name, err, nr, args)
+ INTERNAL_SYSCALL_RAWx(__ARM_NR_##name, err, nr, args)
#undef INTERNAL_SYSCALL_ERROR_P
#define INTERNAL_SYSCALL_ERROR_P(val, err) \
diff -Naur glibc-2.3.6_Cs/sysdeps/unix/sysv/linux/bits/stat.h glibc-2.3.6-AuD/sysdeps/unix/sysv/linux/bits/stat.h
--- glibc-2.3.6_Cs/sysdeps/unix/sysv/linux/bits/stat.h 2005-01-20 03:18:50.000000000 +0100
+++ glibc-2.3.6-AuD/sysdeps/unix/sysv/linux/bits/stat.h 2006-10-25 18:24:10.000000000 +0200
@@ -125,7 +125,7 @@
unsigned long int st_ctimensec; /* Nsecs of last status change. */
#endif
__ino64_t st_ino; /* File serial number. */
- };
+ } __attribute__((packed)); /* m.n. for ARM */
#endif
/* Tell code we have these members. */
diff -Naur glibc-2.3.6_Cs/sysdeps/unix/sysv/linux/clock_getres.c glibc-2.3.6-AuD/sysdeps/unix/sysv/linux/clock_getres.c
--- glibc-2.3.6_Cs/sysdeps/unix/sysv/linux/clock_getres.c 2005-01-20 03:18:49.000000000 +0100
+++ glibc-2.3.6-AuD/sysdeps/unix/sysv/linux/clock_getres.c 2006-10-10 17:50:52.000000000 +0200
@@ -27,6 +27,7 @@
# define SYSDEP_GETRES \
case CLOCK_REALTIME: \
case CLOCK_MONOTONIC: \
+ doSyscallGetres: \
retval = INLINE_SYSCALL (clock_getres, 2, clock_id, res); \
break
#elif defined __NR_clock_getres
@@ -35,11 +36,14 @@
/* The REALTIME and MONOTONIC clock might be available. Try the
syscall first. */
+/* m.n. siemens ag: support sync clock */
# define SYSDEP_GETRES \
case CLOCK_REALTIME: \
case CLOCK_MONOTONIC: \
{ \
- int e = EINVAL; \
+ int e; \
+ doSyscallGetres: \
+ e = EINVAL; \
\
if (!__libc_missing_posix_timers) \
{ \
diff -Naur glibc-2.3.6_Cs/sysdeps/unix/sysv/linux/clock_gettime.c glibc-2.3.6-AuD/sysdeps/unix/sysv/linux/clock_gettime.c
--- glibc-2.3.6_Cs/sysdeps/unix/sysv/linux/clock_gettime.c 2005-01-20 03:18:49.000000000 +0100
+++ glibc-2.3.6-AuD/sysdeps/unix/sysv/linux/clock_gettime.c 2006-07-18 07:49:38.000000000 +0200
@@ -15,6 +15,10 @@
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
+/*
+ * Manfred.Neugebauer, Siemens AG, AD ATS 11, 90327 Nuernberg, Germany, 30-March-2004
+ * allow a system call with an arbitrary clock id
+ */
#include <sysdep.h>
@@ -27,6 +31,7 @@
# define SYSDEP_GETTIME \
case CLOCK_REALTIME: \
case CLOCK_MONOTONIC: \
+ doSyscallGettime: \
retval = INLINE_SYSCALL (clock_gettime, 2, clock_id, tp); \
break
#elif defined __NR_clock_gettime
@@ -40,6 +45,7 @@
case CLOCK_MONOTONIC: \
{ \
int e = EINVAL; \
+ doSyscallGettime: \
\
if (!__libc_missing_posix_timers) \
{ \
diff -Naur glibc-2.3.6_Cs/sysdeps/unix/sysv/linux/clock_settime.c glibc-2.3.6-AuD/sysdeps/unix/sysv/linux/clock_settime.c
--- glibc-2.3.6_Cs/sysdeps/unix/sysv/linux/clock_settime.c 2005-01-20 03:18:49.000000000 +0100
+++ glibc-2.3.6-AuD/sysdeps/unix/sysv/linux/clock_settime.c 2006-07-18 07:52:26.000000000 +0200
@@ -15,6 +15,10 @@
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
+/*
+ * Manfred.Neugebauer, Siemens AG, AD ATS 11, 90327 Nuernberg, Germany, 30-March-2004
+ * allow a system call with an arbitrary clock id
+ */
#include <sysdep.h>
@@ -26,6 +30,7 @@
kernel. */
# define SYSDEP_SETTIME \
case CLOCK_REALTIME: \
+ doSyscallSettime: \
retval = INLINE_SYSCALL (clock_settime, 2, clock_id, tp); \
break
#elif defined __NR_clock_settime
@@ -37,6 +42,7 @@
case CLOCK_REALTIME: \
{ \
int e = EINVAL; \
+ doSyscallSettime: \
\
if (!__libc_missing_posix_timers) \
{ \
diff -Naur glibc-2.3.6_Cs/sysdeps/unix/sysv/linux/i386/sysdep.h glibc-2.3.6-AuD/sysdeps/unix/sysv/linux/i386/sysdep.h
--- glibc-2.3.6_Cs/sysdeps/unix/sysv/linux/i386/sysdep.h 2005-11-09 05:05:53.000000000 +0100
+++ glibc-2.3.6-AuD/sysdeps/unix/sysv/linux/i386/sysdep.h 2007-01-24 11:43:21.000000000 +0100
@@ -37,8 +37,10 @@
#undef SYS_ify
#define SYS_ify(syscall_name) __NR_##syscall_name
+// m.n. we also want to have the fast kernel access for timer functions
+// we add "defined IS_IN_librt"
#if defined USE_DL_SYSINFO \
- && (!defined NOT_IN_libc || defined IS_IN_libpthread)
+ && (!defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt)
# define I386_USE_SYSENTER 1
#else
# undef I386_USE_SYSENTER
[-- Attachment #3: aud-realtime.ppt --]
[-- Type: application/vnd.ms-powerpoint, Size: 248832 bytes --]
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [Xenomai-core] Ipipe and Siemens A&D Realtime
2007-04-18 15:07 [Xenomai-core] Ipipe and Siemens A&D Realtime Krause, Karl-Heinz
@ 2007-04-18 17:53 ` Jan Kiszka
2007-04-19 8:54 ` Krause, Karl-Heinz
0 siblings, 1 reply; 7+ messages in thread
From: Jan Kiszka @ 2007-04-18 17:53 UTC (permalink / raw)
To: Krause, Karl-Heinz; +Cc: xenomai
[-- Attachment #1: Type: text/plain, Size: 1642 bytes --]
Krause, Karl-Heinz wrote:
> Hi Philippe
>
>
>
> as promised some time ago, I'd like to let you know the result of our work.
>
> Attached are
>
> - a few recycled slides from a presentation describing motivation, features and results
>
> - the patch file for a adeos-ipipe-2.6.15-i386-1.3-04.patch patched kernel2.6.15.4
You attached the glibc patches, but your ipipe variant is missing. Could
you also explain a bit what kind of optimisations your ipipe version
contains, maybe they are of generic interest and we can discuss a
potential integration? And a description of the features/hooks it adds
would be good as well. That might help to restart a discussion if there
is more common ground and a chance to merge.
>
> Since some parts of the kernel functionality (clock registration, realtime capable message queues) and
>
> most parts of the glibc changes are also of interest for the RT_PREEMPT solution we are in contact with
>
> Thomas Gleixner trying to leverage the work.
>
> An update to newer versions of kernel and glibc (basically because of the PI mutexes) is planned for later,
>
> presumably when RT_PREEMPT has become mainline status.
>
Hmm, so your approach is locked to 2.6.15 for now? What is blocking
kernel / ipipe updates?
>
>
> If you need any further information just let me know.
>
According to your slides, you did a lot of concrete testing. Do you
happen to have comparative numbers of recent Xenomai's POSIX skin as
well (forgetting about the ABI issue for the moment)? Or do you have a
releasable test suite?
Jan
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 250 bytes --]
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [Xenomai-core] Ipipe and Siemens A&D Realtime
2007-04-18 17:53 ` Jan Kiszka
@ 2007-04-19 8:54 ` Krause, Karl-Heinz
2007-04-19 12:39 ` Jan Kiszka
0 siblings, 1 reply; 7+ messages in thread
From: Krause, Karl-Heinz @ 2007-04-19 8:54 UTC (permalink / raw)
To: jan.kiszka; +Cc: xenomai
[-- Attachment #1: Type: text/plain, Size: 3874 bytes --]
Hi Jan
Sorry for attaching the wrong patch. Here is the right one.
>From all the ipipe patches/hooks we use only a few one.
The ipipe changes we did fall into two categories
- one additional hook in entry.s which checks at system call exit whether
the thread has to migrate to the realtime domain
- optimizations for a dual domain system concerning the dispatching of
events and interrupt handling.
So if just that kind of dual domain system is of interest, the patches may be of general interest and we are willing to support it.
To allow for a possible integration we made it configurable as follows
[ ] interrupt pipeline
[ ] rtx domain system
[ ] fast rtx dual domain system
Common for both is the check for preemption which we have in the optimized handle_irq routine as well as in sync_stage.
More generic are the patches we made for the POSIX message queues and for saving/restoring the fpu context
We are not specifically locked to 2.6.15.4 and we don't expect any surprises if we would upgrade. (Of course we know that we have to do some additions to hook into PI mutexes, despite the fact that for priority changes itself the domain boundary is already transparent). It is only caused by our general policy to keep the number of different versions minimal, since we cannot simply forget older versions, we have to maintain it.(It is not only a kernel for x86, it is for ARM with and without MMU and for MIPS as well and it is the complete tool chain). So we always will do some skipping and we haven't decided yet what our next version will be.
Concerning testing we took mainly the existing POSIX test suites which we
had to make suitable for static priorities > 0. We added a few tests for checking the transparency of the domain boundary for POSIX message queues, futexes and priority changes and we combined them with performance measurement that is all.
Just let me know what else you need.
Karl-Heinz
-----Ursprüngliche Nachricht-----
Von: jan.kiszka@domain.hid [mailto:jan.kiszka@domain.hid
Gesendet: Mittwoch, 18. April 2007 19:54
An: Krause, Karl-Heinz
Cc: xenomai@xenomai.org
Betreff: Re: [Xenomai-core] Ipipe and Siemens A&D Realtime
Krause, Karl-Heinz wrote:
> Hi Philippe
>
>
>
> as promised some time ago, I'd like to let you know the result of our work.
>
> Attached are
>
> - a few recycled slides from a presentation describing motivation, features and results
>
> - the patch file for a adeos-ipipe-2.6.15-i386-1.3-04.patch patched kernel2.6.15.4
You attached the glibc patches, but your ipipe variant is missing. Could
you also explain a bit what kind of optimisations your ipipe version
contains, maybe they are of generic interest and we can discuss a
potential integration? And a description of the features/hooks it adds
would be good as well. That might help to restart a discussion if there
is more common ground and a chance to merge.
>
> Since some parts of the kernel functionality (clock registration, realtime capable message queues) and
>
> most parts of the glibc changes are also of interest for the RT_PREEMPT solution we are in contact with
>
> Thomas Gleixner trying to leverage the work.
>
> An update to newer versions of kernel and glibc (basically because of the PI mutexes) is planned for later,
>
> presumably when RT_PREEMPT has become mainline status.
>
Hmm, so your approach is locked to 2.6.15 for now? What is blocking
kernel / ipipe updates?
>
>
> If you need any further information just let me know.
>
According to your slides, you did a lot of concrete testing. Do you
happen to have comparative numbers of recent Xenomai's POSIX skin as
well (forgetting about the ABI issue for the moment)? Or do you have a
releasable test suite?
Jan
[-- Attachment #2: aud_kernel.patch --]
[-- Type: application/octet-stream, Size: 345391 bytes --]
diff -N -a -u -r linux-2.6.15.4/arch/i386/kernel/entry.S aud_linux/arch/i386/kernel/entry.S
--- linux-2.6.15.4/arch/i386/kernel/entry.S 2007-04-16 22:23:50.000000000 +0200
+++ aud_linux/arch/i386/kernel/entry.S 2007-04-10 20:49:26.000000000 +0200
@@ -93,6 +93,16 @@
js bypass1 ; \
jne bypass2 ; \
movl ORIG_EAX(%esp),%eax
+#ifdef CONFIG_RTX_DOMAIN
+#define CATCH_ROOT_LEAVE_SYSCALL(bypass1,bypass2) \
+ call __ipipe_syscall_exit ; \
+ testl %eax,%eax ; \
+ js bypass1 ; \
+ jne bypass2 ; \
+ movl ORIG_EAX(%esp),%eax
+#else
+#define CATCH_ROOT_LEAVE_SYSCALL(bypass1,bypass2)
+#endif /* CONFIG_RTX_DOMAIN */
#define PUSH_XCODE(v) pushl $ ex_/**/v
#define HANDLE_EXCEPTION(code) movl %code,%ecx ; \
call __ipipe_handle_exception ; \
@@ -141,6 +151,7 @@
#define TEST_PREEMPTIBLE(regs) testl $IF_MASK,EFLAGS(regs)
#define restore_nmi restore_all
#define CATCH_ROOT_SYSCALL(bypass1,bypass2)
+#define CATCH_ROOT_LEAVE_SYSCALL(bypass1,bypass2)
#define PUSH_XCODE(v) pushl $v
#define HANDLE_EXCEPTION(code) call *%code
#define DIVERT_EXCEPTION(code)
@@ -282,6 +293,7 @@
jae syscall_badsys
call *sys_call_table(,%eax,4)
movl %eax,EAX(%esp)
+ CATCH_ROOT_LEAVE_SYSCALL(sysenter_tail,sysenter_exit)
sysenter_tail:
CLI
movl TI_flags(%ebp), %ecx
@@ -301,7 +313,7 @@
pushl %eax # save orig_eax
SAVE_ALL
GET_THREAD_INFO(%ebp)
- CATCH_ROOT_SYSCALL(syscall_exit,restore_raw)
+ CATCH_ROOT_SYSCALL(syscall_exit,restore_raw)
# system call tracing in operation / emulation
/* Note, _TIF_SECCOMP is bit number 8, and so it needs testw and not testb */
testw $(_TIF_SYSCALL_EMU|_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
@@ -311,6 +323,7 @@
syscall_call:
call *sys_call_table(,%eax,4)
movl %eax,EAX(%esp) # store the return value
+ CATCH_ROOT_LEAVE_SYSCALL(syscall_exit,restore_raw)
syscall_exit:
CLI # make sure we don't miss an interrupt
# setting need_resched or sigpending
diff -N -a -u -r linux-2.6.15.4/arch/i386/kernel/ipipe-root.c aud_linux/arch/i386/kernel/ipipe-root.c
--- linux-2.6.15.4/arch/i386/kernel/ipipe-root.c 2007-04-16 22:23:50.000000000 +0200
+++ aud_linux/arch/i386/kernel/ipipe-root.c 2007-04-10 20:49:26.000000000 +0200
@@ -19,6 +19,9 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Architecture-dependent I-PIPE support for x86.
+ *
+ * 2006-11-20: Karl-Heinz Krause Copyright (c) 2006 Siemens AG
+ * Support for fast dual domain system added
*/
#include <linux/config.h>
@@ -60,6 +63,18 @@
fastcall void smp_invalidate_interrupt(struct pt_regs *regs);
fastcall void smp_call_function_interrupt(struct pt_regs *regs);
+#ifdef CONFIG_RTX_FAST
+
+static int __ipipe_ack_common_irq(unsigned irq)
+{
+ irq_desc_t *desc = irq_desc + irq;
+
+ desc->handler->ack(irq);
+ return 1;
+}
+
+#else
+
static int __ipipe_ack_common_irq(unsigned irq)
{
irq_desc_t *desc = irq_desc + irq;
@@ -76,6 +91,8 @@
return 1;
}
+#endif /* CONFIG_RTX_FAST */
+
#ifdef CONFIG_X86_LOCAL_APIC
static void __ipipe_null_handler(unsigned irq, void *cookie)
@@ -233,12 +250,12 @@
for (irq = 0; irq < NR_IRQS; irq++) {
/* Fails for IPIPE_CRITICAL_IPI but that's ok. */
- ipipe_virtualize_irq(ipipe_root_domain,
+ ipipe_virtualize_irq(ipipe_root_domain,
irq,
(ipipe_irq_handler_t)&do_IRQ,
NULL,
&__ipipe_ack_common_irq,
- IPIPE_STDROOT_MASK);
+ IPIPE_STDROOT_MASK);
}
#ifdef CONFIG_X86_LOCAL_APIC
@@ -332,6 +349,42 @@
#endif /* CONFIG_IPIPE_TRACE_IRQSOFF */
}
+#ifdef CONFIG_RTX_FAST
+
+/*
+ * System call support for the fast two domain system called rtx domain system. It consists of a realtime
+ * domain (rtx_domain)and the Linux domain (ipipe_root_domain). Both domains provide exactly the same
+ * low level system call interface. The routing of the system calls is provided by the two hooks
+ * CATCH_ROOT_SYSCALL and CATCH_ROOT_LEAVE_SYSCALL in entry.S
+ * The hook CATCH_ROOT_SYSCALL is the original ipipe hook, but the implementation of __ipipe_syscall_root
+ * is optimized to speed up system call execution in both domains. CATCH_ROOT_LEAVE_SYSCALL is new.
+ * It only can get executed in entry.S while in the realtime domain. The event handlers for both hooks
+ * may lead to a migration to the other domain, but that is completely transparent to the code.
+ * It is done via the ipipe patches in the linux scheduler and the corresponding functions in the realtime
+ * scheduler which in turn use ipipe VIRQs for notification.
+ */
+extern struct ipipe_domain *__rtx_domain;
+extern int (*rtx_preemption_handling)(void);
+
+asmlinkage int __ipipe_syscall_root(struct pt_regs regs)
+{
+
+ if (current->array != NULL)
+ return 0; // thread executes under Linux
+ // if running in the rtx_domain, the handler is installed
+ return (__rtx_domain->evhand[IPIPE_EVENT_SYSCALL](IPIPE_EVENT_SYSCALL, __rtx_domain, ®s));
+}
+
+
+asmlinkage int __ipipe_syscall_exit(struct pt_regs regs)
+{
+ if (ipipe_root_domain->evhand[IPIPE_EVENT_SYSCALL_EX] == NULL)
+ return 0; // a realtime domain is not installed yet
+ return (ipipe_root_domain->evhand[IPIPE_EVENT_SYSCALL_EX](IPIPE_EVENT_SYSCALL_EX, ipipe_root_domain , ®s));
+}
+
+#else /*CONFIG_RTX_FAST */
+
asmlinkage int __ipipe_syscall_root(struct pt_regs regs)
{
ipipe_declare_cpuid;
@@ -372,6 +425,53 @@
return 0;
}
+#ifdef CONFIG_RTX_DOMAIN
+
+/*
+ * m.n. ipipe interaction after a system call
+ * syscall was done, we do some exit stuff
+ * return value > 0 and == 0 should be identically
+ */
+asmlinkage int __ipipe_syscall_exit(struct pt_regs regs)
+{
+ ipipe_declare_cpuid;
+ unsigned long flags;
+
+ __fixup_if(®s);
+
+ /* This routine either returns:
+ 0, >0 -- no tail work should be performed;
+ <0 -- the tail work has to be performed (for handling signals etc). */
+
+ if (__ipipe_event_pipelined_p(IPIPE_EVENT_SYSCALL_EX) &&
+ __ipipe_dispatch_event(IPIPE_EVENT_SYSCALL_EX,®s) > 0) {
+ /* We might enter here over a non-root domain and exit
+ * over the root one as a result of the syscall
+ * (i.e. by recycling the register set of the current
+ * context across the migration), so we need to fixup
+ * the interrupt flag upon return too, so that
+ * __ipipe_unstall_iret_root() resets the correct
+ * stall bit on exit. */
+ __fixup_if(®s);
+
+ if (ipipe_current_domain == ipipe_root_domain && !in_atomic()) {
+ /* Sync pending VIRQs before _TIF_NEED_RESCHED
+ * is tested. */
+ ipipe_lock_cpu(flags);
+ if ((ipipe_root_domain->cpudata[cpuid].irq_pending_hi & IPIPE_IRQMASK_VIRT) != 0)
+ __ipipe_sync_pipeline(IPIPE_IRQMASK_VIRT);
+ ipipe_unlock_cpu(flags);
+ return -1;
+ }
+ return 1;
+ }
+
+ return 0;
+}
+
+#endif /* CONFIG_RTX_DOMAIN */
+#endif /* CONFIG_RTX_FAST */
+
static fastcall void do_machine_check_vector(struct pt_regs *regs, long error_code)
{
#ifdef CONFIG_X86_MCE
@@ -446,6 +546,87 @@
return 0;
}
+#ifdef CONFIG_RTX_FAST
+
+/*
+ * __ipipe_handle_irq() derived from the original __ipipe_handle_irq()
+ * This is an optimized version for the rtx domain system.
+ * Interrupt logging for the realtime domain is completely avoided. As a consequence
+ * no stalling of the rtx_domain is possible. The realtime system must work with
+ * spin_lock_irq_hw/spin_unlock_irq_hw. Because the IPIPE_WIRED_MASK option is not necessary
+ * for speeding up the path to ISR entry, IPIPE_WIRED_MASK has a changed semantics.
+ * It now means that an interrupt is dedicated exclusively to the realtime domain. This
+ * allows to cut the round trip time significantly. In case the two domains need to
+ * work on the same device, the corresponding driver parts must cooperate anyway.
+ * In this case it is assumed, that the Linux part of the driver is notified via a virtual interrupt.
+ * Therefore, if the interrupt is dedicated exlusively to the device, the IPIPE_WIRED_MASK can also be used
+ * When registering an ISR, the corresponding optimized virtualize_irq routine ignores a
+ * specified acknowledge_handler and fills in acknowledge routines as specified below.
+ * HW-Interrupt exclusively dedicated to realtime:
+ * - the acknowledge handler of the root_domain entry contains desc->handler->ack()
+ * - the acknowledge handler of a realtime entry contains desc->handler->end()
+ * Interrupt shared between the two domains e.g. __ipipe_tick_irq:
+ * - the acknowledge handler of the root_domain entry contains desc->handler->ack()
+ * - the acknowledge handler of the realtime entry contains no_ack()
+ * Virtual interrupt:
+ * - the acknowledge handler of the root_domain entry contains no_ack()
+ * - the acknowledge handler of the realtime entry contains no_ack()
+ *
+ * The realtime domain is assumed to be a natively preemptable system (no explicit preempt enable/disable).
+ * Therefore a check for task switch (rtx_preemption_handling()) must be done after every ISR handling
+ * This switch covers both preemption scenarios
+ * -- linux->realtime and
+ * -- realtime->realtime.
+ */
+
+int __ipipe_handle_irq(struct pt_regs regs)
+{
+ unsigned irq = regs.orig_eax;
+ ipipe_declare_cpuid;
+ struct ipipe_domain *interrupted_dom;
+
+ ipipe_load_cpuid();
+
+ irq &= 0xff; // HW interrupts are "signed"
+ if (test_bit(IPIPE_HANDLE_FLAG, &ipipe_root_domain->irqs[irq].control))
+ {
+ ipipe_root_domain->cpudata[cpuid].irq_counters[irq].total_hits++;
+ ipipe_root_domain->cpudata[cpuid].irq_counters[irq].pending_hits++;
+ __ipipe_set_irq_bit(ipipe_root_domain, cpuid, irq);
+ if (irq == __ipipe_tick_irq)
+ { // Emulate a loss of tick for Linux in case of pending_hits > 1. Drift will be compensated by the timer support code.
+ ipipe_root_domain->cpudata[cpuid].irq_counters[irq].pending_hits = 1;
+ __ipipe_tick_regs[cpuid].eflags = regs.eflags;
+ __ipipe_tick_regs[cpuid].eip = regs.eip;
+ __ipipe_tick_regs[cpuid].xcs = regs.xcs;
+#if defined(CONFIG_SMP) && defined(CONFIG_FRAME_POINTER)
+ __ipipe_tick_regs[cpuid].ebp = regs.ebp; // Linux profiling code needs this.
+#endif /* CONFIG_SMP && CONFIG_FRAME_POINTER */
+ }
+ }
+ ipipe_root_domain->irqs[irq].acknowledge(irq);
+ if (__rtx_domain && __rtx_domain->irqs[irq].handler)
+ {
+ interrupted_dom = ipipe_percpu_domain[cpuid];
+ ipipe_percpu_domain[cpuid] = __rtx_domain;
+ __rtx_domain->irqs[irq].handler(irq, __rtx_domain->irqs[irq].cookie);
+ __rtx_domain->irqs[irq].acknowledge(irq);
+ rtx_preemption_handling();
+ ipipe_percpu_domain[cpuid] = interrupted_dom;
+ }
+ if ((ipipe_percpu_domain[cpuid] != ipipe_root_domain)||test_bit(IPIPE_STALL_FLAG, &ipipe_root_domain->cpudata[cpuid].status))
+ return 0;
+ __ipipe_sync_stage(IPIPE_IRQMASK_ANY);
+#ifdef CONFIG_SMP
+ /* Prevent a spurious rescheduling from being triggered on preemptible kernels along the way out through ret_from_intr. */
+ if (regs.orig_eax < 0)
+ __set_bit(IPIPE_STALL_FLAG, &ipipe_root_domain->cpudata[cpuid].status);
+#endif /* CONFIG_SMP */
+ return 1;
+}
+
+#else /* CONFIG_RTX_FAST */
+
/* __ipipe_handle_irq() -- IPIPE's generic IRQ handler. An optimistic
interrupt protection log is maintained here for each domain. Hw
interrupts are off on entry. */
@@ -467,7 +648,6 @@
m_ack = 1;
this_domain = ipipe_percpu_domain[cpuid];
-
if (test_bit(IPIPE_STICKY_FLAG, &this_domain->irqs[irq].control))
head = &this_domain->p_link;
else {
@@ -487,7 +667,6 @@
s_ack = m_ack;
pos = head;
-
while (pos != &__ipipe_pipeline) {
next_domain = list_entry(pos, struct ipipe_domain, p_link);
@@ -576,6 +755,8 @@
return 1;
}
+#endif /* CONFIG_RTX_FAST */
+
EXPORT_SYMBOL_GPL(irq_desc);
EXPORT_SYMBOL_GPL(default_ldt);
EXPORT_SYMBOL_GPL(__switch_to);
diff -N -a -u -r linux-2.6.15.4/arch/i386/kernel/process.c aud_linux/arch/i386/kernel/process.c
--- linux-2.6.15.4/arch/i386/kernel/process.c 2007-04-16 22:23:50.000000000 +0200
+++ aud_linux/arch/i386/kernel/process.c 2007-04-10 20:49:26.000000000 +0200
@@ -722,6 +722,11 @@
handle_io_bitmap(next, tss);
disable_tsc(prev_p, next_p);
+
+#ifdef CONFIG_RTX_DOMAIN
+ if (next_p->fpu_counter)
+ math_state_restore();
+#endif /* CONFIG_RTX_DOMAIN */
return prev_p;
}
diff -N -a -u -r linux-2.6.15.4/arch/i386/kernel/traps.c aud_linux/arch/i386/kernel/traps.c
--- linux-2.6.15.4/arch/i386/kernel/traps.c 2007-04-16 22:23:50.000000000 +0200
+++ aud_linux/arch/i386/kernel/traps.c 2007-04-10 20:49:26.000000000 +0200
@@ -978,6 +978,8 @@
return stack32;
}
+
+
/*
* 'math_state_restore()' saves the current math information in the
* old math state array, and gets the new ones from the current task
@@ -988,7 +990,11 @@
* Must be called with kernel preemption disabled (in this case,
* local interrupts are disabled at the call-site in entry.S).
*/
-asmlinkage void math_state_restore(struct pt_regs regs)
+
+
+
+
+asmlinkage void math_state_restore(void)
{
struct thread_info *thread = current_thread_info();
struct task_struct *tsk = thread->task;
@@ -1003,6 +1009,12 @@
local_irq_restore_hw_cond(flags);
}
+#ifdef CONFIG_RTX_DOMAIN
+
+EXPORT_SYMBOL (math_state_restore);
+
+#endif /* CONFIG_RTX_DOMAIN */
+
#ifndef CONFIG_MATH_EMULATION
asmlinkage void math_emulate(long arg)
diff -N -a -u -r linux-2.6.15.4/drivers/aud/auddevice/auddevice.c aud_linux/drivers/aud/auddevice/auddevice.c
--- linux-2.6.15.4/drivers/aud/auddevice/auddevice.c 1970-01-01 01:00:00.000000000 +0100
+++ aud_linux/drivers/aud/auddevice/auddevice.c 2007-04-10 20:49:26.000000000 +0200
@@ -0,0 +1,632 @@
+/*
+ * rtime/auddevice/auddevice.c
+ *
+ * 2007-19-01: Karl-Heinz.Krause@siemens.com
+ * Copyright (c) 2007 Siemens AG
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*
+ * AuD-Device-Driver for Linux
+ * This file provides for the ioctl-based user API to manage the realtime extensions
+ */
+
+
+
+#include "../include/rt_timer.h"
+#include "../include/rt_buffer.h"
+
+#include <linux/unistd.h>
+
+
+static int init_AuD_dev(void);
+static void exit_AuD_dev(void);
+
+MODULE_AUTHOR("Karl-Heinz Krause");
+MODULE_DESCRIPTION (AuD_DRIVER_NAME);
+MODULE_LICENSE("GPL"); /* "Proprietary" returns warning during loading */
+
+unsigned dev_version = 0x05042007;
+unsigned long aud_diagnostic = RT_FAULT_VERBOSE_BIT
+// | RT_SHUTDOWN_VERBOSE_BIT
+// | RT_INIT_VERBOSE_BIT
+// | RT_EVENT_VERBOSE_BIT
+// | RT_MIGRATE_VERBOSE_BIT
+// | RT_CHECK_VERBOSE_BIT
+// | AUD_DEV_VERBOSE_BIT
+// | RT_SYSCALL_VERBOSE_BIT
+// | RT_THREAD_VERBOSE_BIT
+// | RT_TIMER_VERBOSE_BIT
+// | RT_FUTEX_VERBOSE_BIT
+// | RT_EXCEPTION_VERBOSE
+ ;
+
+
+struct rt_link_desc *rtlpr;
+extern struct ipipe_domain *ipipe_root_domain;
+
+static int AuD_dev_major = 220; // major number of the device
+static int AuD_dev_open_cnt = 0;
+static int AuD_rt_open_cnt = 0;
+int set_execution_environment(int);
+unsigned get_exec_domain(void);
+int probe_realtime(void);
+void init_sync_clock_management(void);
+void init_event_management(void);
+void init_io_management(void);
+int sched_setscheduler(struct task_struct*, int, struct sched_param *);
+int (*rt_subscribe_tick_ptr)(void) = NULL;
+
+
+static long AuD_dev_ioctl (struct file *, unsigned int, unsigned long);
+static int AuD_dev_open (struct inode *, struct file *);
+static int AuD_dev_release (struct inode *, struct file *);
+static ssize_t AuD_dev_read(struct file *, char *, size_t, loff_t *);
+
+
+/*
+ * This structure holds all the setup parameters for the realtime system
+ * It gets initialized with default values, but may be overriden later via
+ * an ioctl(,AuD_DEV_RT_PARAM, )
+ * It must be in line with the structure rt_config in rttime_lib.h which holds the
+ * requested values only
+ */
+
+struct rt_config_cntrl aud_config = {
+ .no_of_timers.max = 100,
+ .no_of_timers.val = 40,
+ .no_of_timers.min = 5,
+ .no_of_sigq.max = 128,
+ .no_of_sigq.val = 32,
+ .no_of_sigq.min = 8,
+ .no_of_headers.max = 10,
+ .no_of_headers.val = 2,
+ .no_of_headers.min = 1,
+ .no_of_fu_req.max = 100,
+ .no_of_fu_req.val = 40,
+ .no_of_fu_req.min = 10,
+ .buf_size.max = 16384,
+ .buf_size.val = 4096,
+ .buf_size.min = 2048,
+ // all priorities according to POSIX
+ .td_prio.max = 95,
+ .td_prio.val = 80, // timer daemon: priority relevant for realtime
+ .td_prio.min = 70,
+ .md_prio.max = 99,
+ .md_prio.val = 99, // migration action should have highest prio
+ .md_prio.min = 95,
+ .dd_prio.max = 99,
+ .dd_prio.val = 94, // to_lx daemon: only Linux priority
+ .dd_prio.min = 68,
+ .cd_prio.max = 95, // clock daemon für registered CLOCK_SYNCs Linux priority
+ .cd_prio.val = 85, // is the only parameter needed for a Linux only system
+ .cd_prio.min = 65,
+ .ed_prio.max = 95, // event daemon in case a event is registered
+ .ed_prio.val = 85, // to be sent in Linux from an ISR
+ .ed_prio.min = 65,
+};
+
+#define NO_OF_TIMERS 73
+#define NO_OF_LIST_HEADERS 16
+#define TIMEOUT_PRIO 90
+#define MIGRATION_PRIO 90
+#define WRITE_PRIO 90
+#define DELEGATION_PRIO 90
+
+/*
+ * NOTE:
+ * read, write, poll, fsync, readv, writev, unlocked_ioctl and compat_ioctl
+ * can be called without the big kernel lock held in all filesystems.
+ */
+static struct file_operations AuD_dev_fops = {
+ .read = AuD_dev_read,
+ .unlocked_ioctl = AuD_dev_ioctl,
+ .open = AuD_dev_open,
+ .release = AuD_dev_release,
+};
+
+
+struct dom_hdr aud_rt_hdr;
+unsigned long aud_lx_tgid = 0; // the linux tgid of the process which registered with RT_HARD set
+
+int check_par(int new_val, confpar_t *op)
+{
+ if (new_val == 0)
+ return 0; // keep current value
+ if ((new_val > op->max) || (new_val < op->min))
+ return -EINVAL;
+ op->val = new_val; // set to new value
+ return 0;
+}
+
+
+int parameterize_configuration(struct rt_config *ncfg)
+{
+
+ if (check_par(ncfg->no_of_timers, &aud_config.no_of_timers))
+ return -EINVAL;
+ if (check_par(ncfg->no_of_sigq, &aud_config.no_of_sigq))
+ return -EINVAL;
+ if (check_par(ncfg->no_of_headers, &aud_config.no_of_headers))
+ return -EINVAL;
+ if (check_par(ncfg->no_of_fu_req, &aud_config.no_of_fu_req))
+ return -EINVAL;
+ if (check_par(ncfg->buf_size, &aud_config.buf_size))
+ return -EINVAL;
+ if (check_par(ncfg->td_prio, &aud_config.td_prio))
+ return -EINVAL;
+ if (check_par(ncfg->md_prio, &aud_config.md_prio))
+ return -EINVAL;
+ if (check_par(ncfg->dd_prio, &aud_config.dd_prio))
+ return -EINVAL;
+ if (check_par(ncfg->ed_prio, &aud_config.ed_prio))
+ return -EINVAL;
+ if (check_par(ncfg->cd_prio, &aud_config.cd_prio))
+ return -EINVAL;
+ return 0;
+}
+
+/*
+ * Checks the exit state of the Linux threads.
+ * When detecting that there is only one thread
+ * without PF_EXITING flag set, then it must be the
+ * reader thread (displays RT kernel messages and
+ * printf) which is created on startup.
+ */
+static int main_exit_done(task_t *t)
+{
+ int pid = t->pid;
+ unsigned no_exit_cnt = 0;
+
+ do {
+ if (!(t->flags & PF_EXITING))
+ no_exit_cnt++;
+ t = next_thread(t);
+ } while (t->pid != pid && no_exit_cnt <= 1);
+
+ if (no_exit_cnt == 1) // only the reader thread is still active
+ return 1;
+ return 0;
+}
+
+
+/*
+ * Called by the hook in do_exit of the Linux domain.
+ * The hook gets called when the auddriver is installed.
+ * The check for event notifications needs to be done for all processes
+ */
+
+
+static int aud_lx_sysexit(unsigned event, struct ipipe_domain *ipd, void *data)
+{
+ int last_user_thread = 0;
+ struct list_head *lp;
+
+ rt_delete_event_notification(0);
+ if (!(IS_HARD_REALTIME_PROCESS(current)))
+ return 0;
+ if (RT_SHUTDOWN_VERBOSE)
+ printkGen("pid %d called do_exit flags %#x\n", current->pid, (unsigned)current->signal->flags);
+ if (current->signal->flags & SIGNAL_GROUP_EXIT)
+ rtlpr->rt_shutdown_realtime();
+ else
+ {
+ lp = &aud_rt_hdr.rt_tl;
+ read_lock_irq(&tasklist_lock);
+ local_irq_disable_hw();
+ if ((list_empty(lp) || ((RT_CHECK_VERBOSE) && (lp->next == lp->prev))) // maybe the do_check_rt thread
+ && (main_exit_done(pid_task(current->pids[PIDTYPE_TGID].pid_list.next, PIDTYPE_TGID))))
+ last_user_thread = 1;
+ local_irq_enable_hw();
+ read_unlock_irq(&tasklist_lock);
+ if (last_user_thread)
+ rtlpr->rt_shutdown_realtime();
+ }
+ return 0;
+}
+
+
+static int register_process(rt_exec_t *arg)
+{
+ int error;
+ struct exec_rt_kernel cmd_par;
+ struct reg_proc *reg;
+ struct list_head *curr, *head;
+
+ if (THREAD_IS_REALTIME)
+ return -EINVAL;
+ if (!arg)
+ return -EINVAL;
+ if ((error = copy_from_user(&cmd_par, (char*)arg, sizeof(struct exec_rt_kernel))))
+ return (error);
+ error = -EINVAL;
+ if ((!cmd_par.exec_flags) || ((cmd_par.exec_flags & ~RT_MASK) != 0))
+ return -EINVAL;
+ down(&aud_rt_hdr.dev_sem);
+ if (cmd_par.exec_flags)
+ {
+ if ((cmd_par.exec_flags == RT_HARD) && (rtlpr == NULL)) // rtlpr is the indicator for the
+ goto errout; // presence of the realtime module
+ if ((aud_lx_tgid) && (aud_rt_hdr.state == RT_INSTALLED))
+ {
+ error = -EBUSY; // only one process is allowed
+ goto errout;
+ }
+ aud_lx_tgid = current->tgid;
+ aud_rt_hdr.rt_proc = current;
+ aud_rt_hdr.state = cmd_par.exec_flags;
+ AuD_rt_open_cnt = 1;
+ }
+ else
+ { // asks only for memory residence
+ head = &aud_rt_hdr.reg_list;
+ for (curr = head->next; curr != head; curr = curr->next)
+ if (current->tgid == ((struct reg_proc *)curr)->tgid)
+ {
+ error = -EBUSY; // got already registered
+ goto errout;
+ }
+ if ((reg = (struct reg_proc *) KMALLOC(sizeof(struct reg_proc), GFP_KERNEL)) == NULL)
+ {
+ error = -EAGAIN; // no memory
+ goto errout;
+ }
+ reg->tgid = current->tgid;
+ list_add_tail(®->p_link, &aud_rt_hdr.reg_list);
+ }
+ error = 0;
+errout:
+ up(&aud_rt_hdr.dev_sem);
+ return error;
+}
+
+int probe_realtime()
+{
+ struct list_head *curr, *head;
+ pid_t pid;
+ int ret = 0;
+
+ if (THREAD_IS_REALTIME) // in case the auddriver is extended to allow
+ return -EINVAL; // access from realtime
+ if (aud_rt_hdr.state == RT_INSTALLED)
+ return -EBUSY;
+ down(&aud_rt_hdr.dev_sem);
+ if (current->tgid == aud_lx_tgid)
+ {
+ if ((rtlpr != NULL) && (aud_rt_hdr.state & RT_HARD))
+ {
+ if ((rtlpr->rt_init_realtime()) == 0)
+ {
+ aud_rt_hdr.to_lx_prio = aud_config.dd_prio.val;
+ if ((pid = kernel_thread(rtlpr->do_execute_in_lx, 0, 0))> 0) // daemon for FUTEX_WAKE actions
+ {
+ aud_rt_hdr.to_rt_prio = aud_config.md_prio.val;
+ if ((pid = kernel_thread(rtlpr->do_migrate_to_rt, 0, 0)) > 0)// daemon puts client threads into the realtime runqueue
+ {
+ aud_rt_hdr.td_prio = aud_config.td_prio.val;
+ if ((pid = kernel_thread(rtlpr->do_timer_rt, 0, 0)) > 0) // timeout daemon for the realtime domain
+ {
+ down(&aud_rt_hdr.setup_sm); // to be continued from the timer daemon
+ if (RT_CHECK_VERBOSE)
+ pid = kernel_thread(rtlpr->do_check_rt, 0, 0); // kernel thread for checking out timer functions
+ }
+ }
+ }
+ }
+ if (aud_rt_hdr.state == RT_INSTALLED)
+ {
+ set_execution_environment(RT_HARD); // installs realtime ISRs for dual domain drivers
+ ret = RT_HARD;
+ }
+ else
+ ret = -1;
+ }
+ else
+ ret = RT_SOFT; // no realtime module installed
+ }
+ else
+ { // memory residency: it can get released afterwards
+ head = &aud_rt_hdr.reg_list;
+ ret = -EINVAL; // in case it is a regular process
+ for (curr = head->next; curr != head; curr = curr->next)
+ if (current->tgid == ((struct reg_proc *)curr)->tgid)
+ {
+ list_del_init(curr);
+ KFREE(curr);
+ ret = 0; // it needs proactive mlockall() only
+ break;
+ }
+ }
+ up(&aud_rt_hdr.dev_sem);
+ return ret;
+}
+
+
+
+/*
+ * ioctl is called via the f_ops ioctl_unlocked. Attention: change in parameter list
+ * */
+
+static long AuD_dev_ioctl (struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ int ret = 0;
+ struct rt_config new_config;
+ struct aud_version version_all;
+ struct list_head *curr, *head;
+
+ if (THREAD_IS_REALTIME)
+ if (!((cmd == AuD_IS_REALTIME) || (cmd == AuD_TEST_RT)))
+ return -EINVAL; // no command allowed which uses Linux semaphore
+ switch(cmd) {
+
+ case AuD_REGISTER_PROCESS:
+ if (AUD_DEV_VERBOSE)
+ printkGen("pid: %d registered process\n", current->pid);
+ return(register_process((rt_exec_t *)arg));
+ case AuD_REGISTER_AND_PROBE_REALTIME:
+ if (AUD_DEV_VERBOSE)
+ printkGen("pid: %d registered and probe\n", current->pid);
+ if ((ret = register_process((rt_exec_t *)arg)) < 0)
+ return ret;
+ case AuD_PROBE_REALTIME:
+ if (AUD_DEV_VERBOSE)
+ printkGen("pid: %d probed realtime\n", current->pid);
+ return(probe_realtime());
+ case AuD_IS_REALTIME:
+ return(THREAD_IS_REALTIME);
+ case AuD_TEST_RT:
+ if (current->tgid != aud_lx_tgid)
+ return -EINVAL;
+ if (aud_rt_hdr.timer_daemon)
+ return RT_HARD;
+ return RT_SOFT;
+ case AuD_SET_DIAGNOSIS:
+ down(&aud_rt_hdr.dev_sem);
+ {
+ if (arg == 0)
+ aud_diagnostic = 0;
+ else
+ aud_diagnostic |= arg;
+ }
+ break;
+ case AuD_GET_VERSION:
+ down(&aud_rt_hdr.dev_sem);
+ version_all.version_dev = dev_version;
+ if (rtlpr)
+ version_all.version_rt = rtlpr->rt_version;
+ else
+ version_all.version_rt = 0;
+ ret = copy_to_user((struct aud_version *)arg, &version_all, sizeof(struct aud_version));
+ break;
+ case AuD_UNREGISTER_PROCESS:
+ down(&aud_rt_hdr.dev_sem);
+ if (current->tgid == aud_lx_tgid)
+ { // a hard realtime process is installed
+ if (aud_rt_hdr.timer_daemon)
+ ret = -EBUSY; // only shutdown is possible
+ else
+ {
+ aud_lx_tgid = 0;
+ aud_rt_hdr.state = 0;
+ }
+ }
+ else
+ {
+ head = &aud_rt_hdr.reg_list;
+ for (curr = head->next; curr != head; curr = curr->next)
+ if (current->tgid == ((struct reg_proc *)curr)->tgid)
+ {
+ list_del_init(curr);
+ KFREE(curr);
+ ret = 1;
+ break;
+ }
+ }
+ break;
+ case AuD_DEV_RT_PARAM:
+ down(&aud_rt_hdr.dev_sem);
+ if (!arg)
+ {
+ ret = -EINVAL;
+ break;
+ }
+ if ((ret = copy_from_user(&new_config, (struct rt_config *)arg, sizeof(struct rt_config))) == 0)
+ ret = parameterize_configuration(&new_config);
+ break;
+ default:
+ return -EINVAL; /* wrong command encoding */
+ }
+ up(&aud_rt_hdr.dev_sem);
+ return(ret);
+}
+
+
+static ssize_t AuD_dev_read(struct file *filep, char __user *buff, size_t len, loff_t *ppos)
+{
+ int loclen = 0;
+
+ if ((aud_rt_hdr.pid_wr) && (aud_rt_hdr.pid_wr != current->pid))
+ return -EPERM;
+ aud_rt_hdr.pid_wr = current->pid;
+ if (aud_rt_hdr.rt_proc != current)
+ {
+ aud_rt_hdr.rt_proc = current;
+ return -EAGAIN;
+ }
+read_buffer:
+ if ((loclen = rtlpr->rt_read_buffer((char* ) buff, (size_t) len)) > 0)
+ {
+ if (AUD_DEV_VERBOSE)
+ printkGen("pid: %d reads write buffer buff=%p:len=%d:\n", current->pid, buff, loclen);
+ return loclen;
+ }
+ if (aud_rt_hdr.state == RT_INSTALLED)
+ {
+ down(&aud_rt_hdr.write_sm); // wait for a buffer to be read
+ goto read_buffer;
+ }
+ if (AUD_DEV_VERBOSE)
+ printkGen("pid: %d returns from write buffer with ENXIO for termination\n", current->pid);
+ return -ENXIO;
+}
+
+
+static int AuD_dev_open (struct inode *inode, struct file *filp)
+{
+ int ret;
+
+
+ down(&aud_rt_hdr.dev_sem); // prevent parallel access
+ if (filp->f_flags & O_EXCL)
+ {
+ printkGen("%s:file can't get opened exclusively\n", AuD_DRIVER_NAME);
+ ret = -EINVAL;
+ goto EndOpen;
+ }
+ if ((ret = rt_allow_access(filp, RT_IO_IOCTL))< 0)
+ goto EndOpen;
+ if (AUD_DEV_VERBOSE)
+ printkGen("pid %d opened auddriver open_cnt: %d maj: %x\n", current->pid, AuD_dev_open_cnt, inode->i_rdev );
+ AuD_dev_open_cnt++;
+ if (current->tgid == aud_lx_tgid)
+ AuD_rt_open_cnt++;
+ ret = 0;
+
+EndOpen:
+ up(&aud_rt_hdr.dev_sem);
+ return(ret);
+}
+
+/*
+ * gets called when the last close() on a filp gets executed *
+ */
+static int AuD_dev_release (struct inode *inode, struct file *filp)
+{
+ if (AUD_DEV_VERBOSE)
+ printkGen("%s executes release\n", AuD_DRIVER_NAME);
+
+ AuD_dev_open_cnt--;
+ rt_allow_access(filp, 0);
+ if (IS_HARD_REALTIME_PROCESS(current))
+ { // no close from another process can lead to
+ AuD_rt_open_cnt--; // to a shutdown of the realtime system
+ if ((AuD_rt_open_cnt == 0) && (aud_rt_hdr.timer_daemon))
+ {
+ if (RT_SHUTDOWN_VERBOSE)
+ printkGen("release calls shutdown\n");
+ rtlpr->rt_shutdown_realtime();
+ }
+ }
+ return 0;
+}
+
+/*
+ * is called when module gets loaded
+ */
+
+int init_AuD_dev(void)
+{
+ int result;
+
+ if (AUD_DEV_VERBOSE)
+ printkGen("init %s\n", AuD_DRIVER_NAME);
+
+ result = register_chrdev(AuD_dev_major, AuD_DRIVER_NAME, &AuD_dev_fops);
+ if (result < 0) /* Major-number received ? */
+ {
+ printkGen("[%s]: can't register auddriver (major=%d)\n", AuD_DRIVER_NAME, AuD_dev_major);
+ return(result);
+ }
+ init_sync_clock_management();
+ init_event_management();
+ init_io_management();
+
+ INIT_LIST_HEAD(&aud_rt_hdr.reg_list);
+ sema_init(&aud_rt_hdr.dev_sem, 1);
+ AuD_dev_open_cnt = 0;
+ AuD_rt_open_cnt = 0;
+ // catching the exit systemcall is also needed to check
+ // for existing event notifications in the lx domain
+ // without having a RT domain
+ ipipe_catch_event(ipipe_root_domain, IPIPE_EVENT_SELF|IPIPE_EVENT_EXIT, aud_lx_sysexit);
+ return 0;
+}
+
+
+void exit_AuD_dev(void)
+{
+ ipipe_catch_event(ipipe_root_domain, IPIPE_EVENT_EXIT, NULL);
+ if (AUD_DEV_VERBOSE)
+ printkGen("[%s]: cleanup_module ...\n", AuD_DRIVER_NAME);
+ unregister_chrdev(AuD_dev_major, AuD_DRIVER_NAME); /* Deregistrieren des Treibers */
+
+}
+
+
+
+#define MAX_PRINT_BUFF 128
+
+int printkGen(char *format, ...)
+{
+ int len, len1 = 0;
+ char myPrintBuff[MAX_PRINT_BUFF + 16];
+
+ va_list args;
+ va_start(args, format);
+
+#ifdef CONFIG_SMP
+ // Prefix the processor id.
+ len1 = sprintf(myPrintBuff, "cpu=%d:", smp_processor_id());
+#endif
+ len = vsnprintf(myPrintBuff + len1, MAX_PRINT_BUFF, format, args);
+ va_end(args);
+ len += len1;
+
+ if (RT_DOMAIN) {
+ if (aud_rt_hdr.state & RT_INSTALLED) {
+ rtlpr->rt_write_buffered(PROP_STD_KERNEL, myPrintBuff, len);
+ }
+ else {
+ goto doPrintk; // during startup and shutdown we rely on ipipe
+ }
+ }
+ else {
+doPrintk:
+ printk("RT_DRV:%s", myPrintBuff);
+ }
+ return(len);
+}
+
+
+
+
+/* **************************************************************** */
+/* if a module acts as a driver it needs modul_init / modul_exit */
+/* for a module only init_module / cleanup_module is sufficient */
+/* ******************************************************************** */
+
+module_init(init_AuD_dev);
+module_exit(exit_AuD_dev);
+
+// export some symbols
+EXPORT_SYMBOL_GPL(printkGen);
+EXPORT_SYMBOL(aud_config);
+EXPORT_SYMBOL(aud_rt_hdr);
+EXPORT_SYMBOL(aud_lx_tgid);
+EXPORT_SYMBOL(rt_subscribe_tick_ptr);
+EXPORT_SYMBOL(aud_diagnostic);
+EXPORT_SYMBOL(rtlpr);
+
+
diff -N -a -u -r linux-2.6.15.4/drivers/aud/auddevice/.cdtproject aud_linux/drivers/aud/auddevice/.cdtproject
--- linux-2.6.15.4/drivers/aud/auddevice/.cdtproject 1970-01-01 01:00:00.000000000 +0100
+++ aud_linux/drivers/aud/auddevice/.cdtproject 2007-04-10 21:08:18.000000000 +0200
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse-cdt version="2.0"?>
+
+<cdtproject id="org.eclipse.cdt.make.core.make">
+<extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
+<extension id="org.eclipse.cdt.core.domsourceindexer" point="org.eclipse.cdt.core.CIndexer"/>
+<data>
+<item id="scannerConfiguration">
+<autodiscovery enabled="false" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile"/>
+<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">
+<buildOutputProvider>
+<openAction enabled="false" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+</item>
+</data>
+</cdtproject>
diff -N -a -u -r linux-2.6.15.4/drivers/aud/auddevice/io_base.c aud_linux/drivers/aud/auddevice/io_base.c
--- linux-2.6.15.4/drivers/aud/auddevice/io_base.c 1970-01-01 01:00:00.000000000 +0100
+++ aud_linux/drivers/aud/auddevice/io_base.c 2007-04-10 20:49:26.000000000 +0200
@@ -0,0 +1,491 @@
+/*
+ * rtime/auddevice/io_base.c
+ *
+ * 2007-19-01: Karl-Heinz.Krause@siemens.com
+ * Copyright (c) 2007 Siemens AG
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *
+ * This file contains all routines which support device drivers in a dual domain environment
+ */
+
+#include "../include/rt_timer.h"
+#include <linux/interrupt.h>
+
+int request_irq(unsigned int, irqreturn_t (*handler)(int, void *, struct pt_regs *), unsigned long, const char *, void *);
+void free_irq(unsigned int, void *);
+
+#define RT_IO_ENTRIES 12
+#define NO_OF_CALLBACKS 12
+
+extern struct rt_link_desc *rtlpr;
+extern struct dom_hdr aud_rt_hdr;
+struct ipipe_domain aud_domain;
+extern struct ipipe_domain *ipipe_root_domain;
+
+struct isr_cntrl {
+ struct list_head link;
+ unsigned int irq;
+ irqreturn_t (*handler)(int, void *, struct pt_regs *);
+ unsigned long irqflags;
+ const char *devname ;
+ void * dev_id;
+ irqreturn_t (*nonrt_handler)(int, void *, struct pt_regs *);
+ int install_state;
+};
+
+
+struct rt_io_acc_list {
+ struct semaphore sem;
+ struct rt_io_acc acc_entries[RT_IO_ENTRIES];
+ void(*driver_callback[NO_OF_CALLBACKS])(int);
+};
+
+struct rt_io_acc_list io_acc;
+
+struct isr_hdr {
+ struct list_head hdr_link;
+ struct semaphore dev_sem;
+};
+
+struct isr_hdr isr_cntrl_hdr;
+
+void init_io_management(void)
+{
+ int i;
+
+ sema_init(&io_acc.sem, 1);
+ sema_init(&isr_cntrl_hdr.dev_sem, 1);
+ INIT_LIST_HEAD(&isr_cntrl_hdr.hdr_link);
+ for (i = 0; i < NO_OF_CALLBACKS; i++)
+ io_acc.driver_callback[i] = NULL;
+ for (i = 0; i < RT_IO_ENTRIES; i++)
+ {
+ io_acc.acc_entries[i].filp = NULL;
+ io_acc.acc_entries[i].allowed_calls = 0;
+ }
+}
+
+int install_handler(struct isr_cntrl* ctp)
+{
+ if (ctp->install_state == RT_HARD)
+ {
+ if (request_irq(ctp->irq, ctp->nonrt_handler, ctp->irqflags, ctp->devname, ctp->dev_id))
+ {
+ if (RT_FAULT_VERBOSE)
+ printkGen("could not install nonrt_handler as Lx-ISR for irq: %d\n", ctp->irq );
+ return -EFAULT;
+ }
+ if (RT_INIT_VERBOSE)
+ printkGen("pid %d registered nonrt_handler for irq %d for lx domain\n", current->pid, ctp->irq);
+ if (ipipe_virtualize_irq(&aud_domain, ctp->irq, (ipipe_irq_handler_t)ctp->handler, &ctp->dev_id, NULL, IPIPE_PASS_MASK | IPIPE_HANDLE_MASK))
+ {
+ if (RT_FAULT_VERBOSE)
+ printkGen("could not install handler as RT-ISR for irq: %d\n", ctp->irq);
+ return -EFAULT;
+ }
+ if (RT_INIT_VERBOSE)
+ printkGen("pid %d registered handler for irq %d for rt domain\n", current->pid, ctp->irq);
+ }
+ else
+ {
+ if (request_irq(ctp->irq, ctp->handler, ctp->irqflags, ctp->devname, ctp->dev_id))
+ {
+ if (RT_FAULT_VERBOSE)
+ printkGen("could not install handler as Lx-ISR\n");
+ return -EFAULT;
+ }
+ if (RT_INIT_VERBOSE)
+ printkGen("pid %d registered handler for irq %d for lx domain\n", current->pid, ctp->irq);
+ }
+ return 0;
+}
+
+/*
+ * Depending on the requirements a driver may need to split up its work having a realtime part constituted by the "handler" and
+ * an additional non realtime part constituted by a "nonrt_handler"
+ * In a system with a realtime domain the handler gets installed in the realtime domain, whereas in a
+ * Linux-only system the "handler" gets installed as Linux handler. The "handler" has to call the "nonrt_handler"
+ * which executes always as Linux handler. Therefore the "nonrt_handler" has to be activated through two different mechanismn.
+ * This function hides the differences. In case "handler" decides that it has to activate the
+ * "nonrt_handler" for subsequent work, it always calls execute_nonrt_handler
+ */
+
+int execute_nonrt_handler(int irq)
+{
+ struct isr_cntrl *ctp;
+ struct list_head *head, *lp;
+
+ if (RT_EXEC)
+ return 0; // ipipe provides for interrupt propagation
+ head = &isr_cntrl_hdr.hdr_link;
+ for (lp = isr_cntrl_hdr.hdr_link.next; lp != head; lp = lp->next)
+ {
+ ctp = (struct isr_cntrl*)lp;
+ if (ctp->irq == irq)
+ {
+ ctp->nonrt_handler(ctp->irq, (void*)ctp->dev_id, NULL );
+ return 0;
+ }
+ }
+ return -ENODEV;
+}
+
+
+#ifdef CONFIG_SMP
+/*
+ * This routine is called by a driver that registers/unregisters an IRQ
+ * for the RT domain.
+ * This IRQ is pinned to CPU0 as long as the driver is getting unregistered.
+*/
+static int rt_set_irq_affinity(int irq, cpumask_t cpu_mask)
+{
+ cpumask_t ret_mask;
+
+ if (num_online_cpus() == 1)
+ return 0;
+ ret_mask = ipipe_set_irq_affinity(irq, cpu_mask);
+ if (cpus_equal(ret_mask, CPU_MASK_NONE))
+ {
+ return -EINVAL;
+ }
+ return(0);
+}
+
+/*
+ * This routine is executed when initializing the RT domain.
+ * The affinity of all external interrupts (except of those that are
+ * registered by the RT domain) is changed, excluding CPU0.
+ *
+ */
+void rt_pin_irqs(void)
+{
+ struct list_head *head, *lp;
+ struct isr_cntrl *ctp;
+ cpumask_t rt_irq_mask = {{ [0 ... BITS_TO_LONGS(NR_CPUS)-1] = 1UL }};
+ cpumask_t rt_irq_lx_mask = cpu_online_map;
+ int irq;
+
+ if (num_online_cpus() == 1)
+ return;
+ cpus_andnot(rt_irq_lx_mask, rt_irq_lx_mask, rt_irq_mask); // exclude CPU0
+
+ head = &isr_cntrl_hdr.hdr_link;
+ down(&isr_cntrl_hdr.dev_sem);
+
+ for (irq=0; irq < IPIPE_NR_XIRQS; irq++)
+ {
+ for (lp = isr_cntrl_hdr.hdr_link.next; lp != head; lp = lp->next)
+ {
+ ctp = (struct isr_cntrl*)lp;
+ if (ctp->irq == irq)
+ break;
+ }
+ if (lp == head)
+ {
+ rt_set_irq_affinity(irq, rt_irq_lx_mask);
+ }
+ }
+ up(&isr_cntrl_hdr.dev_sem);
+}
+
+/*
+ * This routine is executed when shutting down the RT domain.
+ * The affinity of all external interrupts is set to the
+ * CPUs currently online.
+ *
+ */
+void rt_unpin_irqs(void)
+{
+ cpumask_t rt_irq_lx_mask = cpu_online_map;
+ int irq;
+
+ if (num_online_cpus() == 1)
+ return;
+ for (irq=0; irq < IPIPE_NR_XIRQS; irq++)
+ {
+ rt_set_irq_affinity(irq, rt_irq_lx_mask);
+ }
+}
+#endif
+
+
+
+/*
+ * Calling rt_request_irq() indicates, that an ISR for the realtime domain should be installed
+ * If no realtime domain is present, this call gets mapped to a regular request_irq() meaning the ISR gets installed
+ * for the Linux domain. In case a driver has a non realtime part, it gets always handled in the Linux domain by the nonrt_handler
+ */
+
+int rt_request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *),
+ unsigned long irqflags, const char * devname, void *dev_id,
+ int (*nonrt_handler)(int, void *, struct pt_regs * ))
+{
+ struct list_head *head, *lp;
+ struct isr_cntrl *ctp;
+#ifdef CONFIG_SMP
+ cpumask_t rt_irq_cpumask = {{ [0 ... BITS_TO_LONGS(NR_CPUS)-1] = 1UL }}; // CPU0
+#endif
+
+ if (!handler)
+ return -EINVAL;
+ if (irq >= IPIPE_VIRQ_BASE)
+ return -EINVAL; // virtual interrupts don't go this path it is for test purposes only
+ if (irq == __ipipe_tick_irq) // subscribing to the timer tick doesn't go through this interface
+ {
+ if (THREAD_IS_REALTIME) // __ipipe_tick_irq handler can only get installed while in the RT domain
+ ipipe_virtualize_irq(&aud_domain, irq, (ipipe_irq_handler_t)handler, NULL, NULL, IPIPE_PASS_MASK | IPIPE_HANDLE_MASK);
+ return 0;
+ }
+ if (!nonrt_handler)
+ return -ENODEV; // for the time being we don't support exclusive RT_ISR IRQs
+
+ head = &isr_cntrl_hdr.hdr_link;
+ down(&isr_cntrl_hdr.dev_sem); // to also synchronize it with potentially state changing actions
+ for (lp = isr_cntrl_hdr.hdr_link.next; lp != head; lp = lp->next)
+ {
+ printkGen("head: %p lp: %p\n", head, lp);
+ ctp = (struct isr_cntrl*)lp;
+ if (ctp->irq == irq)
+ {
+ up(&isr_cntrl_hdr.dev_sem);
+ return -EBUSY; // shortcut for the time being
+ }
+ }
+ if ((ctp = (struct isr_cntrl *)KMALLOC(sizeof(struct isr_cntrl), GFP_KERNEL)) == NULL)
+ return -EAGAIN;
+ INIT_LIST_HEAD(&ctp->link);
+ ctp->dev_id = dev_id;
+ ctp->devname = devname;
+ ctp->handler = handler;
+ ctp->irq = irq;
+ ctp->irqflags = irqflags;
+ ctp->nonrt_handler = nonrt_handler;
+ if (aud_rt_hdr.state == RT_INSTALLED)
+ ctp->install_state = RT_HARD;
+ else
+ ctp->install_state = 0;
+ if (ctp->irq < IPIPE_VIRQ_BASE)
+ install_handler(ctp); // virtual interrupts get only registered
+#ifdef CONFIG_SMP
+ if (rt_set_irq_affinity(irq, rt_irq_cpumask)) // IRQ is pinned to CPU0
+ printkGen("set irq affinity (register) failed irq=%d cpumask=%d\n", irq, rt_irq_cpumask);
+#endif
+ list_add_tail(&ctp->link, &isr_cntrl_hdr.hdr_link);
+ up(&isr_cntrl_hdr.dev_sem);
+ return 0;
+}
+
+void rt_do_free_irq(struct isr_cntrl *ctp)
+{
+ if (ctp->install_state == RT_HARD)
+ {
+ ipipe_virtualize_irq(&aud_domain, ctp->irq, NULL, NULL, NULL, IPIPE_PASS_MASK); // remove realtime isr
+ if ((RT_SHUTDOWN_VERBOSE)|| (RT_SHUTDOWN_VERBOSE))
+ printkGen("pid %d unregistered isr for irq %d for rt domain\n", current->pid, ctp->irq);
+ }
+ free_irq(ctp->irq, ctp->dev_id); // remove Linux isr
+ if ((RT_SHUTDOWN_VERBOSE)|| (RT_SHUTDOWN_VERBOSE))
+ printkGen("pid %d unregistered isr for irq %d for LX domain\n", current->pid, ctp->irq);
+}
+
+void rt_free_irq(int irq)
+{
+ struct list_head *head, *lp;
+ struct isr_cntrl *ctp;
+
+ if (irq == __ipipe_tick_irq)
+ {
+ if (THREAD_IS_REALTIME)
+ ipipe_virtualize_irq(&aud_domain, __ipipe_tick_irq, NULL, NULL, NULL, IPIPE_PASS_MASK);
+ return;
+ }
+ head = &isr_cntrl_hdr.hdr_link;
+ down(&isr_cntrl_hdr.dev_sem); // to synchronize it with potentially state changing actions
+ for (lp = isr_cntrl_hdr.hdr_link.next; lp != head; lp = lp->next)
+ {
+ ctp = (struct isr_cntrl*)lp;
+ if (ctp->irq == irq)
+ {
+ list_del(lp);
+ rt_do_free_irq(ctp);
+#ifdef CONFIG_SMP
+ if (rt_set_irq_affinity(irq, cpu_online_map)) // unpinning the IRQ
+ printkGen("set irq affinity (unregister) failed irq=%d cpumask=%d\n", irq, cpu_online_map);
+#endif
+ KFREE(ctp);
+ up(&isr_cntrl_hdr.dev_sem);
+ return;
+ }
+ }
+ up(&isr_cntrl_hdr.dev_sem);
+ return;
+}
+
+
+/*
+ * Possible environments
+ * Linux only: flags = 0
+ * hard realtime: flags = RT_HARD
+ * A change from Linux only to hard realtime or vice versa leads to execution of the registered callback routines.
+ */
+
+int set_execution_environment(int flags)
+{
+ int i;
+ struct list_head *head, *lp;
+ struct isr_cntrl *ctp;
+
+ /* This is the old version of the register/unregister driver API which is going to get deprecated */
+
+ for (i = 0; i < NO_OF_CALLBACKS; i++)
+ if (io_acc.driver_callback[i] != NULL)
+ io_acc.driver_callback[i](flags);
+
+/* This is the new version of the driver API which doesn't require register/unregister anymore */
+
+ head = &isr_cntrl_hdr.hdr_link;
+ down(&isr_cntrl_hdr.dev_sem);
+ for (lp = isr_cntrl_hdr.hdr_link.next; lp != head; lp = lp->next)
+ {
+ ctp = (struct isr_cntrl*)lp;
+ rt_do_free_irq(ctp);
+ ctp->install_state = flags;
+ install_handler(ctp);
+ }
+ up(&isr_cntrl_hdr.dev_sem);
+ return(0);
+}
+
+ /* This is the old version of the register/unregister driver API which is going to get deprecated */
+
+int rt_register_notify(void(*callback)(int arg))
+{
+ int i;
+
+ down(&io_acc.sem);
+ for (i = 0; i < NO_OF_CALLBACKS; i++)
+ if (io_acc.driver_callback[i] == NULL)
+ {
+ io_acc.driver_callback[i] = callback;
+ up(&io_acc.sem);
+ if (aud_rt_hdr.timer_daemon)
+ callback(RT_HARD);
+ return(0);
+ }
+ up(&io_acc.sem);
+ return -1;
+}
+
+int rt_unregister_notify(void(*callback)(int arg))
+{
+ int i;
+
+ down(&io_acc.sem);
+ for (i = 0; i < NO_OF_CALLBACKS; i++)
+ if (io_acc.driver_callback[i] == callback)
+ {
+ io_acc.driver_callback[i] = NULL;
+ up(&io_acc.sem);
+ return(io_acc.driver_callback[i] != NULL);
+ }
+ up(&io_acc.sem);
+ return -1;
+}
+
+ /* End of the old version of the register/unregister driver API which is going to get deprecated */
+
+
+int rt_allow_access (struct file *fp, int flags)
+{
+ int i;
+ int error = 0;
+
+ if ((flags & ~(RT_IO_ALLOWED)) || (fp == NULL))
+ return -EINVAL;
+ down(&io_acc.sem);
+ for (i = 0; i < RT_IO_ENTRIES; i++) // look for an existing entry
+ if (io_acc.acc_entries[i].filp == fp)
+ { // an existing entry may only get deleted
+ if (!flags)
+ {
+ io_acc.acc_entries[i].allowed_calls = 0;
+ io_acc.acc_entries[i].filp = NULL;
+ }
+ if (flags != io_acc.acc_entries[i].allowed_calls)
+ error = -EINVAL;
+ up(&io_acc.sem);
+ return (error);
+ }
+ if (flags == 0)
+ {
+ up(&io_acc.sem);
+ return -EINVAL;
+ }
+ for (i = 0; i < RT_IO_ENTRIES; i++) // look for an emtpty entry and set it up
+ if (io_acc.acc_entries[i].filp == NULL)
+ {
+ if (io_acc.acc_entries[i].filp == NULL)
+ {
+ io_acc.acc_entries[i].allowed_calls = flags;
+ io_acc.acc_entries[i].filp = fp;
+ up(&io_acc.sem);
+ return (0);
+ }
+ up(&io_acc.sem);
+ continue;
+ }
+ up(&io_acc.sem);
+ return -ENOMEM;
+}
+
+
+int if_rt_domain(void)
+{
+ if (aud_rt_hdr.state & RT_INSTALLED)
+ return 1;
+ return 0;
+}
+
+
+/*
+ * This routine is executed from the realtime domain
+ * Currently it is assumed that for the realtime process the fdtable doesn't need to be relocated.
+ * The RCU lock free stuff may get inserted later
+ * as long as all the other routines maintain the right sequence between changing .filp and
+ * .allowed_calls there should be no race problems
+ */
+
+struct file* rt_fcheck_files(struct file *filp, int flags)
+{
+ int i;
+
+ for (i = 0; i < RT_IO_ENTRIES; i++)
+ if ((io_acc.acc_entries[i].filp == filp) && (io_acc.acc_entries[i].allowed_calls & flags))
+ return(filp);
+ return (NULL);
+}
+
+EXPORT_SYMBOL(rt_allow_access);
+EXPORT_SYMBOL(aud_domain);
+EXPORT_SYMBOL(set_execution_environment);
+EXPORT_SYMBOL(rt_register_notify);
+EXPORT_SYMBOL(rt_unregister_notify);
+EXPORT_SYMBOL(rt_fcheck_files);
+EXPORT_SYMBOL(rt_request_irq);
+EXPORT_SYMBOL(execute_nonrt_handler);
+EXPORT_SYMBOL(rt_free_irq);
diff -N -a -u -r linux-2.6.15.4/drivers/aud/auddevice/io_event.c aud_linux/drivers/aud/auddevice/io_event.c
--- linux-2.6.15.4/drivers/aud/auddevice/io_event.c 1970-01-01 01:00:00.000000000 +0100
+++ aud_linux/drivers/aud/auddevice/io_event.c 2007-04-10 20:49:26.000000000 +0200
@@ -0,0 +1,661 @@
+/*
+ * rtime/auddevice/io_event.c
+ *
+ * 2007-19-01: Karl-Heinz.Krause@siemens.com
+ * Copyright (c) 2007 Siemens AG
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * This file provides all the functions needed for realtime capable io event
+ * noptification through a sigevent based API
+ */
+
+#include "../include/rt_timer.h"
+
+struct task_struct * rt_check_sigevent(sigevent_t *);
+struct task_struct * rt_find_task_by_pid(pid_t);
+int sched_setscheduler(struct task_struct*, int, struct sched_param *);
+
+extern struct rt_link_desc *rtlpr;
+extern struct rt_config_cntrl aud_config;
+extern struct dom_hdr aud_rt_hdr;
+
+spinlock_t ev_lock;
+int no_of_event_areas_max;
+int no_of_evar;
+
+struct rt_event {
+ int ev_id;
+ int ev_domain;
+ int ev_level; // rt_send_event may/will be issued from ISR or thread level
+ // this allows to build up the propagation infrastructure for the Linux domain
+ int ev_cnt; // occurrence count, only necessary for propagation to thread level
+ atomic_t state;
+ int (*ev_action) (void *);
+ struct notify rt_notify;
+};
+
+struct rt_event_hdr {
+ struct semaphore sem;
+ struct rt_event_area *evarp[1]; // placeholder/starter for rt_event_area pointer
+};
+
+struct rt_event_area {
+ int event_area_id;
+ int ev_no; // no of elements in the area
+ int sum_cnt; // sum of all ev_cnt (for optimization)
+ struct task_struct *ev_proxy; // proxy thread to be notified when signalling shoud be done from LINUX ISR
+ struct semaphore proxy_sem; // for synchronizing the installation of the proxy thread
+ struct rt_event ev[1]; // placeholder/starter for ev_no elements
+};
+
+
+struct rt_event_hdr * hdpl;
+
+unsigned get_exec_domain(void)
+{
+ if (!rtlpr)
+ return LX_EXEC;
+ return rtlpr->rt_get_exec_domain();
+}
+
+int fastcall noop(void *arg)
+{
+ return(0);
+}
+
+int fastcall error_catch(void)
+{
+ printkGen("Inconsistency in notification setup\n");
+ return(1);
+}
+
+int fastcall lx_notify_thread(void *arg)
+{
+ int flags;
+ struct notify *nfb = (struct notify*) arg;
+
+ spin_lock_irqsave(¤t->sighand->siglock, flags); // used by Linux only, therefore a Linux spinlock can be used
+ if (list_empty(&nfb->sigq.list))
+ {
+ nfb->sigq.info.si_overrun = 0;
+ spin_unlock_irqrestore(¤t->sighand->siglock, flags);
+ return(send_sigqueue(nfb->sigq.info.si_signo, &nfb->sigq, nfb->thread));
+ }
+ nfb->sigq.info.si_overrun++;
+ spin_unlock_irqrestore(¤t->sighand->siglock, flags);
+ return(1);
+}
+
+
+/* checks sigevent structure for valid specifications and returns process where to send the signal
+ * In case rt_check_sigevent is called in the realtime domain, the lock rt_task_list_sem is already taken
+ * If called from the Linux domain the task list lock must be taken here
+ */
+
+
+struct task_struct * rt_check_sigevent( sigevent_t * event)
+{
+
+ struct task_struct *rtn = current->group_leader;
+
+ if (event->sigev_notify & SIGEV_THREAD_ID) // assumes that SIGEV_SIGNAL_SV incorporates the SIGEV_THREAD_ID bit
+ {
+ if (THREAD_IS_REALTIME)
+ {
+ if (!(rtn = rtlpr->rt_find_task_by_pid(event->sigev_notify_thread_id))||(rtn->tgid != current->tgid))
+ return NULL;
+ }
+ else
+ {
+ read_lock_irq(&tasklist_lock);
+ rtn = find_task_by_pid(event->sigev_notify_thread_id);
+ read_unlock_irq(&tasklist_lock);
+ if (!rtn ||(rtn->tgid != current->tgid))
+ return NULL;
+ }
+ }
+ if ((event->sigev_notify & ~(SIGEV_SIGNAL_SV |SIGEV_NONE)) || ((event->sigev_signo < 0) || (event->sigev_signo > SIGRTMAX)) ||
+ ((event->sigev_notify == (SIGEV_SIGNAL_SV)) && (event->sigev_signo < SIGRTMIN)))
+ return NULL;
+ return rtn;
+}
+
+/*
+ * keeping the ev_area_id also inside event area and maintaining the right sequence for
+ * "allocation/deallocation" allows for a lockfree lookup. Which is important, since it is
+ * used by the realtime domain as well as by the Linux domain
+ */
+
+inline struct rt_event_area * get_evar(int ev_area_id)
+{
+ int evar_ind = ev_area_id & RT_EVAR_MASK;
+ struct rt_event_area *evar;
+
+ if (evar_ind > no_of_evar)
+ return NULL;
+ if ((evar = hdpl->evarp[evar_ind]) == NULL)
+ return NULL;
+ if (evar->event_area_id == ev_area_id)
+ return evar;
+ if (RT_EVENT_VERBOSE)
+ printkGen("get event area failed\n");
+ return NULL;
+}
+
+
+/* This routine gets called when the device driver gets initialized
+ */
+
+int rt_init_event_area (struct ev_entry *ev_list, int no_of_events)
+{
+ int size, i, ix, ev_area_id;
+ struct rt_event_area *evar;
+ struct rt_event *evpr;
+
+ if (no_of_events > RT_EV_SIZE)
+ return -EINVAL;
+ size = (sizeof(struct rt_event_area) + (no_of_events-1) * sizeof(struct rt_event));
+
+ if ((evar = (struct rt_event_area *)KMALLOC(size, GFP_KERNEL)) == NULL)
+ return -ENOMEM;
+
+ evar->ev_no = no_of_events;
+ evar->sum_cnt = 0;
+ evar->ev_proxy = NULL;
+ sema_init(&evar->proxy_sem, 0);
+ for (i = 0; i < no_of_events; i++)
+ {
+ evar->ev[i].ev_level = 0;
+ evar->ev[i].ev_domain = 0;
+ evar->ev[i].ev_cnt = 0;
+ atomic_set(&evar->ev[i].state, EV_EMPTY);
+ evar->ev[i].rt_notify.thread = NULL;
+ evar->ev[i].rt_notify.alt_thread = NULL;
+ evar->ev[i].rt_notify.sigq.info.si_code = SI_IOEVENT;
+ evar->ev[i].rt_notify.sigev_notify = SIGEV_NONE;
+ }
+ for (i = 0; i < no_of_events; i++, ev_list++)
+ {
+ ix = ev_list->event & RT_EV_MASK;
+ evpr = evar->ev + ix;
+ if (((ev_list->attr != EVSIG_ISR) && (ev_list->attr != EVSIG_THREAD)) || (ix >= no_of_events))
+ {
+ KFREE(evar);
+ return -EINVAL;
+ }
+ evpr->ev_id = ev_list->event;
+ evpr->ev_level = ev_list->attr;
+ }
+ down(&hdpl->sem);
+ ev_area_id = 0;
+ for (i = 0; i <= no_of_evar; i++)
+ if (hdpl->evarp[i] == NULL)
+ {
+ if (i == no_of_evar)
+ {
+ if (no_of_evar < RT_EVAR_MAX)
+ no_of_evar++;
+ else
+ break;
+ }
+ ev_area_id = (i + RT_EVAR_SIZE) & 0x7fffffff;
+ if (ev_area_id == 0)
+ {
+ if (RT_EVENT_VERBOSE)
+ printkGen("wrong event area specification\n");
+ break;
+ }
+ evar->event_area_id = ev_area_id;
+ hdpl->evarp[i] = evar; // must be the final action
+ break;
+ }
+ up(&hdpl->sem);
+ return(ev_area_id);
+}
+
+/*
+ * Sets up all what is needed for timer or io_event signalling
+ * For timers the routine is called under lock aud_rt_hdr.rt_tl_sem.
+ * For io_events protection is provided by the EV_BUSY state of the entry
+ */
+
+int rt_setup_notification(void **action_ptr, int id, struct sigevent *rt_sig, struct notify *npr)
+{
+ npr->sigev_notify = rt_sig->sigev_notify;
+ npr->notify_overrun = 0;
+ npr->alt_thread = NULL;
+ INIT_LIST_HEAD(&npr->sigq.list);
+ npr->sigq.flags = SIGQUEUE_PREALLOC;
+ npr->sigq.info.si_signo = rt_sig->sigev_signo;
+ npr->sigq.info.si_errno = 0;
+ npr->sigq.info.si_overrun = 0;
+ npr->sigq.info.si_tid = id;
+ if (rt_sig->sigev_notify == SIGEV_THREAD_ID)
+ npr->sigq.info.si_ptr = rt_sig->sigev_value.sival_ptr;
+ else
+ npr->sigq.info.si_int = rt_sig->sigev_value.sival_int; // SIGEV_SIGNAL_SV needs cycles/cycle-num
+ *action_ptr = noop;
+ if (rt_sig->sigev_notify == SIGEV_NONE)
+ return 0;
+ *action_ptr = error_catch;
+ if (THREAD_IS_REALTIME)
+ {
+ if (rt_sig->sigev_notify == SIGEV_THREAD_ID)
+ *action_ptr = rtlpr->rt_send_sigqueue;
+ else
+ if (rt_sig->sigev_notify == (SIGEV_SIGNAL_SV))
+ {
+ if (rt_sig->sigev_value.sival_int == 0)
+ *action_ptr = rtlpr->rt_send_sigqueue;
+ else
+ {
+ *action_ptr = rtlpr->rt_send_alt_sigqueue;
+ npr->alt_thread = current;
+ }
+ }
+ return 0;
+ }
+ *action_ptr = lx_notify_thread; // default for linux domain
+ return(0);
+}
+
+
+
+int proxy_send_event(void* arg)
+{
+ static int once = 1;
+ struct rt_event_area *evar = (struct rt_event_area *)arg;
+ struct rt_event *evpr;
+ struct sched_param sched_par;
+ int i;
+
+ sched_par.sched_priority = aud_config.ed_prio.val;
+ sched_setscheduler(current, SCHED_FIFO, &sched_par);
+ if (RT_EVENT_VERBOSE)
+ printkGen("event proxy thread is waiting for work ...\n");
+ daemonize("event proxy"); // its life is independent of the process which caused its birth
+ evar->ev_proxy = current;
+ up(&evar->proxy_sem); // continue thread which caused proxy installation
+ while (1)
+ {
+ __set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule();
+ if (current != evar->ev_proxy) // set to NULL if event area is going to be destroyed
+ break;
+ if (RT_EVENT_VERBOSE && once)
+ {
+ printkGen("proxy thread is working ...\n");
+ once = 0;
+ }
+ spin_lock_irq_hw(&ev_lock);
+ while (evar->sum_cnt)
+ {
+ evpr = &evar->ev[0];
+ for (i = 0; i < evar->ev_no; i++)
+ {
+ if (evpr->ev_cnt)
+ {
+ evpr->ev_cnt--;
+ evar->sum_cnt--;
+ spin_unlock_irq_hw(&ev_lock);
+ evpr->ev_action(&evpr->rt_notify);
+ spin_lock_irq_hw(&ev_lock);
+ if (!evar->sum_cnt)
+ break;
+ }
+ evpr++;
+ }
+
+ }
+ spin_unlock_irq_hw(&ev_lock);
+ }
+ up(&hdpl->sem); // to resume thread which is destroying the event area
+ current->exit_signal = -1;
+ return(0);
+}
+
+
+/*
+ * This function is not protected by a blocking lock. It protects itself by the busy state
+ */
+
+int rt_unregister_event(struct rt_event *evpr, int entry_state)
+{
+ struct notify *nfb;
+ int state;
+
+ if (entry_state != EV_BUSY)
+ {
+ if ((state = atomic_cmpxchg(&evpr->state, EV_REGISTERED, EV_BUSY)) != EV_REGISTERED)
+ { // EV_BUSY or EV_NONE
+ if ((state = atomic_cmpxchg(&evpr->state, EV_BUSY, EV_BUSY)) == EV_BUSY)
+ return -1;
+ return 0; // an empty entry doesn't need any further action
+ }
+ }
+ nfb = &evpr->rt_notify;
+ nfb->sigev_notify = SIGEV_NONE;
+ nfb->thread = NULL;
+ nfb->alt_thread = NULL;
+ // may be the sigqueue element is still queued
+ if (evpr->ev_domain == LX_DOMAIN)
+ {
+ spin_lock_irq(¤t->sighand->siglock);
+ list_del_init(&nfb->sigq.list); // POSIX allows to cut corners
+ spin_unlock_irq(¤t->sighand->siglock);
+ }
+ else
+ rtlpr->rt_dequeue_sigq(&nfb->sigq);
+ atomic_set(&evpr->state, EV_EMPTY);
+ return 0;
+}
+
+
+/*
+ * This routine is called from the device driver as result of a event_create(fd,..., ...)
+ * which gets converted inside the library * to an ioctl(fd,...,...)
+ * cmdptr is assumed to point to kernel space, meaning the calling device driver has to copy it from user space
+ */
+
+int do_rt_register_event(int evar_index, struct rt_ev_desc *arg)
+{
+ struct rt_event *evpr = NULL;
+ struct rt_event_area *evar;
+
+ struct notify *nfb;
+ int event;
+ sigevent_t *sigev_ptr;
+ int error = -EINVAL;
+ int ev_idx;
+ int state;
+ int pid;
+
+ if (arg == NULL)
+ return -EINVAL;
+ event = arg->event;
+ sigev_ptr = &arg->sigevent;
+
+ if ((evar = get_evar(evar_index)) == NULL)
+ return -EINVAL;
+ evpr = &evar->ev[0];
+ if ((ev_idx = (event & RT_EV_MASK)) >= evar->ev_no)
+ {
+ if (RT_EVENT_VERBOSE)
+ printkGen("ev_idx %d ev_no: %d\n", ev_idx, event);
+ return -EINVAL;
+ }
+ evpr += ev_idx;
+ if (evpr->ev_id != event)
+ {
+ if (RT_EVENT_VERBOSE)
+ printkGen("Register event mismatch %d ev_no: %d\n", ev_idx, evar->ev_no);
+ return -EINVAL;
+ }
+ nfb = &evpr->rt_notify;
+ if ((state = atomic_cmpxchg(&evpr->state, EV_EMPTY, EV_BUSY)) == EV_EMPTY)
+ { // other register_events and send events are locked out
+ if (sigev_ptr->sigev_notify == SIGEV_NONE)
+ goto err_out;
+ error = -EINVAL;
+ if ((nfb->thread = rt_check_sigevent(sigev_ptr)) == NULL) // good sigevent structure ?
+ {
+ if (RT_EVENT_VERBOSE)
+ printkGen("bad sigevent structure signo: %x, pid: %x\n", sigev_ptr->sigev_signo, (unsigned)sigev_ptr->sigev_notify_thread_id);
+ goto err_out;
+ }
+ if ((evpr->ev_level == EVSIG_ISR) && (LX_DOMAIN) && (evar->ev_proxy == NULL))
+ { // not possible in Linux to send signals from ISR
+ if (RT_EVENT_VERBOSE)
+ printkGen("ev_level: %x !exec_domain: %x\n", (unsigned)evpr->ev_level, get_exec_domain());
+ if ((pid = kernel_thread(proxy_send_event, evar, 0)) <= 0) // create proxy for sending signals
+ goto err_out;
+ down(&evar->proxy_sem); // wait for the proxy to be ready
+ }
+ if (rt_setup_notification((void**)&evpr->ev_action, event, sigev_ptr, nfb))
+ goto err_out;
+ evpr->ev_domain = get_exec_domain();
+ atomic_set(&evpr->state, EV_REGISTERED);
+ return 0;
+ }
+ else
+ if ((state = atomic_cmpxchg(&evpr->state, EV_REGISTERED, EV_BUSY)) == EV_REGISTERED)
+ { // an active entry can only get unregistered
+ if (sigev_ptr->sigev_notify != SIGEV_NONE)
+ {
+ error = -EBUSY;
+ goto err_out;
+ }
+ if (current->tgid != nfb->thread->tgid)
+ {
+ error = -EACCES;
+ goto err_out;
+ }
+ return (rt_unregister_event(evpr, EV_BUSY));
+ }
+err_out:
+ atomic_set(&evpr->state, state);
+ return error;
+}
+
+/*
+ * For the Linux domain no overall locking is needed
+ * For the realtime domain it must get synchronized with getting a thread in/out of the realtime thread list.
+ */
+
+int rt_register_event(int evar_index, struct rt_ev_desc *arg)
+{
+ int result;
+
+ if (THREAD_IS_REALTIME)
+ rtlpr->down_rt(&aud_rt_hdr.rt_tl_sem);
+ result = do_rt_register_event(evar_index, arg);
+ if (THREAD_IS_REALTIME)
+ rtlpr->up_rt(&aud_rt_hdr.rt_tl_sem);
+ return result;
+}
+
+
+/*
+ * This routine is called when the device driver detects the event "event" has occurred
+ * value for flags
+ */
+
+int rt_send_event(int evar_index, int event)
+{
+ struct rt_event *evpr = NULL;
+ struct rt_event_area * evar;
+ int ev_idx;
+ int flag, state;
+ int ret = -EINVAL;
+
+ if (unlikely((evar = get_evar(evar_index)) == NULL))
+ return ret;
+ evpr = evar->ev;
+ if (unlikely((ev_idx = (event & RT_EV_MASK)) >= evar->ev_no))
+ return ret;
+ evpr += ev_idx;
+ if ((state = atomic_cmpxchg(&evpr->state, EV_REGISTERED, EV_BUSY)) != EV_REGISTERED)
+ return -EBUSY;
+ if (unlikely(evpr->ev_id != event))
+ goto errout;
+ if (unlikely(get_exec_domain() != evpr->ev_domain))
+ goto errout;
+ if (likely(RT_DOMAIN || (evpr->ev_level == EVSIG_THREAD)))
+ {
+ evpr->ev_action(&evpr->rt_notify);
+ atomic_set(&evpr->state, EV_REGISTERED);
+ return 0;
+ }
+ // the following code gets only executed in the Linux domain
+ if (evar->ev_proxy == NULL)
+ goto errout;
+ ret = 0;
+ spin_lock_irqsave_hw(&ev_lock, flag);
+ evar->sum_cnt++;
+ evpr->ev_cnt++;
+ spin_unlock_irqrestore_hw(&ev_lock, flag);
+ if (evar->sum_cnt >= 1){
+ wake_up_process(evar->ev_proxy); // Let the proxy do the signalling
+ }
+errout:
+ atomic_set(&evpr->state, EV_REGISTERED);
+ return ret;
+}
+
+/*
+ * In case of a priority change, a migration to Linux can only take place if there are no notifications in the realtime domain
+ * for this thread. This routine is called while holding the rt_tl sem
+ */
+
+int rt_event_notification(struct task_struct *p)
+{
+ int i;
+ struct rt_event *evpr;
+ struct rt_event_area *evar;
+
+ for (i = 0; i < no_of_evar; i++)
+ {
+ if ((evar = hdpl->evarp[i]) == NULL)
+ continue;
+ for (i = 0, evpr = evar->ev; i < evar->ev_no; i++, evpr++)
+ if ((evpr->rt_notify.thread == p) || (evpr->rt_notify.alt_thread == p))
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * This routine is called when either a thread terminates a process or the realtime domain is shut down.
+ * It can be called from both domains. Data consistency is maintained without locking.
+ * If called from the realtime domain, the aud_rt_hdr.rt_tl_sem is hold in order to synchronize with deleting a thread.
+ * It unregisters events which have a notification channel to the current thread or a thread of that group
+ */
+
+void rt_delete_event_notification(int group_flag)
+{
+ int i, j;
+ struct rt_event *evpr;
+ struct rt_event_area *evar;
+
+ for (i = 0; i < no_of_evar; i++)
+ {
+ if ((evar = hdpl->evarp[i]) == NULL)
+ continue;
+ for (j = 0, evpr = &evar->ev[0]; j < evar->ev_no; j++, evpr++)
+ {
+ if (!evpr)
+ {
+ printkGen("invalid evpr\n");
+ return;
+ }
+ if (group_flag)
+ { // group_flag may only set when called from the Linux domain
+ if (((evpr->rt_notify.thread) && (evpr->rt_notify.thread->tgid == current->tgid)) ||
+ ((evpr->rt_notify.alt_thread) && (evpr->rt_notify.alt_thread->tgid == current->tgid)))
+ rt_unregister_event(evpr, EV_REGISTERED);
+ }
+ else
+ {
+ if (((evpr->rt_notify.thread) && (evpr->rt_notify.thread == current)) ||
+ ((evpr->rt_notify.alt_thread) && (evpr->rt_notify.alt_thread == current)))
+ rt_unregister_event(evpr, EV_REGISTERED);
+ }
+ }
+ }
+ return;
+}
+
+/*
+ * This routine is called when a close() leads to a release. It unregisters all events which
+ * have signalling channels to threads of the current process (tgid)
+ */
+
+int rt_delete_events(int evar_index)
+{
+ struct rt_event *evpr;
+ struct rt_event_area *evar;
+ struct task_struct *thread;
+ int i;
+
+ if ((evar = get_evar(evar_index)) == NULL)
+ return -EINVAL;
+
+ for (i = 0, evpr = evar->ev; i < evar->ev_no; i++, evpr++)
+ {
+ if ((thread = evpr->rt_notify.thread) != NULL)
+ if (thread->tgid == current->tgid) // tgid for alt_thread must be the same
+ rt_unregister_event(evpr, EV_REGISTERED);
+ }
+ return 0;
+}
+
+/*
+ * rt_destroy_event_area is to be called when a driver unloads
+ */
+
+void rt_destroy_event_area(int evar_id)
+{
+ struct rt_event_area *evar;
+ struct task_struct *thread;
+
+ if ((evar = get_evar(evar_id)) == NULL)
+ return;
+ down(&hdpl->sem);
+ hdpl->evarp[evar_id &RT_EVAR_MASK] = NULL; // now it cannot be reached anymore
+ if ((thread = evar->ev_proxy) != NULL)
+ {
+ evar->sum_cnt = 0; // in case proxy thread is working
+ evar->ev_proxy = NULL; // termination criteria
+ wake_up_process(thread); // wake up proxy for suicide
+ down(&hdpl->sem); // to be continued by proxy thread
+ }
+ up(&hdpl->sem);
+ KFREE(evar);
+ return;
+}
+
+void init_event_management(void)
+{
+ int size, i;
+
+ no_of_evar = 0;
+ size = (sizeof(struct rt_event_hdr) + RT_EVAR_MAX * sizeof(struct rt_event_area *));
+ if ((hdpl = (struct rt_event_hdr *)KMALLOC(size, GFP_KERNEL)) == NULL)
+ printkGen("no space for rt_event_hdr\n");
+ for (i = 0; i < RT_EVAR_MAX; i++)
+ hdpl->evarp[i] = NULL;
+ sema_init(&hdpl->sem, 1);
+ spin_lock_init(&ev_lock);
+}
+
+
+#if defined LINUX_RMOS_TARGET
+#elif defined LINUX_ECOS_TARGET
+#else
+
+EXPORT_SYMBOL(rt_send_event);
+EXPORT_SYMBOL(rt_register_event);
+EXPORT_SYMBOL(rt_init_event_area);
+EXPORT_SYMBOL(rt_delete_events);
+EXPORT_SYMBOL(rt_check_sigevent);
+EXPORT_SYMBOL(rt_setup_notification);
+EXPORT_SYMBOL(rt_delete_event_notification);
+EXPORT_SYMBOL(rt_event_notification);
+EXPORT_SYMBOL(rt_destroy_event_area);
+EXPORT_SYMBOL(get_exec_domain);
+#endif
+
diff -N -a -u -r linux-2.6.15.4/drivers/aud/auddevice/Makefile aud_linux/drivers/aud/auddevice/Makefile
--- linux-2.6.15.4/drivers/aud/auddevice/Makefile 1970-01-01 01:00:00.000000000 +0100
+++ aud_linux/drivers/aud/auddevice/Makefile 2007-04-10 20:49:26.000000000 +0200
@@ -0,0 +1,7 @@
+#
+# Makefile for the AuD realtime device driver
+#
+# 2007-02-15 hw3671 wolfgang.hartmann@siemens.com
+#
+obj-$(CONFIG_AuD_BASE_REALTIME) := auddriver.o
+auddriver-y := auddevice.o io_event.o io_base.o sync_timer.o
diff -N -a -u -r linux-2.6.15.4/drivers/aud/auddevice/.project aud_linux/drivers/aud/auddevice/.project
--- linux-2.6.15.4/drivers/aud/auddevice/.project 1970-01-01 01:00:00.000000000 +0100
+++ aud_linux/drivers/aud/auddevice/.project 2007-04-10 20:49:26.000000000 +0200
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>auddevice</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.cdt.make.core.makeBuilder</name>
+ <triggers>clean,full,incremental,</triggers>
+ <arguments>
+ <dictionary>
+ <key>org.eclipse.cdt.make.core.build.arguments</key>
+ <value></value>
+ </dictionary>
+ <dictionary>
+ <key>org.eclipse.cdt.core.errorOutputParser</key>
+ <value>org.eclipse.cdt.core.MakeErrorParser;org.eclipse.cdt.core.GCCErrorParser;org.eclipse.cdt.core.GASErrorParser;org.eclipse.cdt.core.GLDErrorParser;org.eclipse.cdt.core.VCErrorParser;</value>
+ </dictionary>
+ <dictionary>
+ <key>org.eclipse.cdt.make.core.enableAutoBuild</key>
+ <value>false</value>
+ </dictionary>
+ <dictionary>
+ <key>org.eclipse.cdt.make.core.environment</key>
+ <value></value>
+ </dictionary>
+ <dictionary>
+ <key>org.eclipse.cdt.make.core.enableFullBuild</key>
+ <value>true</value>
+ </dictionary>
+ <dictionary>
+ <key>org.eclipse.cdt.make.core.build.target.inc</key>
+ <value>all</value>
+ </dictionary>
+ <dictionary>
+ <key>org.eclipse.cdt.make.core.enabledIncrementalBuild</key>
+ <value>true</value>
+ </dictionary>
+ <dictionary>
+ <key>org.eclipse.cdt.make.core.build.target.clean</key>
+ <value>clean</value>
+ </dictionary>
+ <dictionary>
+ <key>org.eclipse.cdt.make.core.build.command</key>
+ <value>make</value>
+ </dictionary>
+ <dictionary>
+ <key>org.eclipse.cdt.make.core.enableCleanBuild</key>
+ <value>true</value>
+ </dictionary>
+ <dictionary>
+ <key>org.eclipse.cdt.make.core.append_environment</key>
+ <value>true</value>
+ </dictionary>
+ <dictionary>
+ <key>org.eclipse.cdt.make.core.build.target.full</key>
+ <value>clean all</value>
+ </dictionary>
+ <dictionary>
+ <key>org.eclipse.cdt.make.core.useDefaultBuildCmd</key>
+ <value>true</value>
+ </dictionary>
+ <dictionary>
+ <key>org.eclipse.cdt.make.core.build.target.auto</key>
+ <value>all</value>
+ </dictionary>
+ <dictionary>
+ <key>org.eclipse.cdt.make.core.stopOnError</key>
+ <value>false</value>
+ </dictionary>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.cdt.make.core.ScannerConfigBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.cdt.core.cnature</nature>
+ <nature>org.eclipse.cdt.make.core.makeNature</nature>
+ <nature>org.eclipse.cdt.make.core.ScannerConfigNature</nature>
+ </natures>
+</projectDescription>
diff -N -a -u -r linux-2.6.15.4/drivers/aud/auddevice/.settings/org.eclipse.cdt.core.prefs aud_linux/drivers/aud/auddevice/.settings/org.eclipse.cdt.core.prefs
--- linux-2.6.15.4/drivers/aud/auddevice/.settings/org.eclipse.cdt.core.prefs 1970-01-01 01:00:00.000000000 +0100
+++ aud_linux/drivers/aud/auddevice/.settings/org.eclipse.cdt.core.prefs 2007-04-10 21:07:38.000000000 +0200
@@ -0,0 +1,3 @@
+#Tue Apr 10 21:07:38 CEST 2007
+eclipse.preferences.version=1
+indexerId=org.eclipse.cdt.core.domsourceindexer
diff -N -a -u -r linux-2.6.15.4/drivers/aud/auddevice/sync_timer.c aud_linux/drivers/aud/auddevice/sync_timer.c
--- linux-2.6.15.4/drivers/aud/auddevice/sync_timer.c 1970-01-01 01:00:00.000000000 +0100
+++ aud_linux/drivers/aud/auddevice/sync_timer.c 2007-04-10 20:49:26.000000000 +0200
@@ -0,0 +1,581 @@
+/*
+ * rtime/auddevice/sync_timer.c
+ *
+ * 2007-19-01: Karl-Heinz.Krause@siemens.com
+ * Copyright (c) 2007 Siemens AG
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * This file contains the routines for the CLOCK_TIMER_SYNC Timers extension of the LINUX kernel
+ * and the RT-Kernel. It also contains the registration of the sync_clock in both domains.
+ */
+
+#include "../include/rt_timer.h"
+
+struct semaphore scl_sem;
+
+int register_new_posix_clock(clockid_t, struct k_clock *);
+int unregister_posix_clock(clockid_t);
+int send_sigqueue(int, struct sigqueue *, struct task_struct *);
+extern struct rtg_clock *rt_clock_arr[];
+extern struct k_clock posix_clocks[];
+
+static int sync_timer_settime(struct posix_timer *, int, struct itimerspec *, struct itimerspec *);
+static void sync_timer_gettime(struct posix_timer *, struct itimerspec *);
+static int sync_timer_delete(struct posix_timer *);
+static int check_sync_timer_restriction(struct posix_timer *, sigevent_t *);
+int sync_nsleep (clockid_t, int, struct timespec *);
+
+static int lx_sync_timer_settime(struct k_itimer *, int, struct itimerspec *, struct itimerspec *);
+static void lx_sync_timer_gettime(struct k_itimer *, struct itimerspec *);
+static int lx_sync_timer_delete(struct k_itimer *);
+static int lx_sync_timer_create(struct k_itimer * );
+static int clock_sync_settime(clockid_t, struct timespec *);
+static int clock_sync_gettime(clockid_t, struct timespec *);
+
+
+static void rt_clock_tick_0(void);
+static void rt_clock_tick_1(void);
+static void rt_clock_tick_2(void);
+
+static void lx_clock_tick_0(void);
+static void lx_clock_tick_1(void);
+static void lx_clock_tick_2(void);
+
+static int return_error(void);
+
+#define MAX_SYNC_CLOCKS 3 // maximum number of sync_clocks to get registered
+
+spinlock_t ptimer_lock;
+
+/*
+ * For the RT domain 3 rtg_clock structures are maintained.
+ * When registering the pointer to the structure is passed.
+ * For the Linux domain a template k_clock structure is maintained.
+ * When registering the template is copied This construct
+ * limited number of specific routines
+ */
+
+
+
+struct rtg_clock cl_arr[] = {
+ {.clock_set = clock_sync_settime, .clock_get = clock_sync_gettime,
+ .timer_set = sync_timer_settime, .timer_del = sync_timer_delete,.timer_get = sync_timer_gettime,
+ .timer_setup = check_sync_timer_restriction, },
+ {.clock_set = clock_sync_settime, .clock_get = clock_sync_gettime,
+ .timer_set = sync_timer_settime, .timer_del = sync_timer_delete,.timer_get = sync_timer_gettime,
+ .timer_setup = check_sync_timer_restriction, },
+ {.clock_set = clock_sync_settime, .clock_get = clock_sync_gettime,
+ .timer_set = sync_timer_settime, .timer_del = sync_timer_delete,.timer_get = sync_timer_gettime,
+ .timer_setup = check_sync_timer_restriction, },
+ };
+
+struct k_clock lx_clock_sync = {
+ .res = 0,
+ .clock_set = clock_sync_settime,
+ .clock_get = clock_sync_gettime,
+ .nsleep = sync_nsleep,
+ .timer_set = lx_sync_timer_settime,
+ .timer_del = lx_sync_timer_delete,
+ .timer_get = lx_sync_timer_gettime,
+ .timer_create = lx_sync_timer_create,
+ };
+
+struct k_clock lx_clock_sync_false = {
+ .res = 1000000,
+ .clock_set = (int (*)(clockid_t, struct timespec *))return_error,
+ .clock_get = (int (*)(clockid_t, struct timespec *))return_error,
+ .nsleep = (int (*)(clockid_t, int, struct timespec *))return_error,
+ .timer_create = (int (*)(struct k_itimer *))return_error,
+ .timer_set = (int (*)(struct k_itimer *, int, struct itimerspec *, struct itimerspec *))return_error,
+ .timer_del = (int (*)(struct k_itimer *))return_error,
+ .timer_get = (void (*)(struct k_itimer *, struct itimerspec *))return_error,
+ };
+
+
+struct sync_clock_hdr sync_clock_arr[]={
+ {.fp = NULL, .rt_clock_isr = rt_clock_tick_0, .lx_clock_isr = lx_clock_tick_0},
+ {.fp = NULL, .rt_clock_isr = rt_clock_tick_1, .lx_clock_isr = lx_clock_tick_1},
+ {.fp = NULL, .rt_clock_isr = rt_clock_tick_2, .lx_clock_isr = lx_clock_tick_2},
+};
+
+struct sync_clock_hdr *cl_map[MAX_CLOCKS];
+
+extern struct dom_hdr aud_rt_hdr;
+extern unsigned long aud_lx_tgid;
+
+static void noop(void *arg)
+{
+
+}
+
+static int return_error(void)
+{
+ return -EINVAL;
+}
+
+
+/* for sync timer tick handling there is an optimized routine at the ISR level only
+ * consequently only the signalling SIGEV_SIGNAL_SV can be allowed.
+ */
+static int check_sync_timer_restriction(struct posix_timer *tmr, sigevent_t *sigevent)
+{
+ if (sigevent->sigev_notify != (SIGEV_SIGNAL_SV))
+ return -EINVAL;
+ return 0;
+}
+
+/*
+ * only the process which registered with HARD_REALTIME can use CLOCK_SYNC timers
+ * If a realtime domain is installed, it can only be used from the realtime domain
+ */
+
+int not_authorized(void)
+{
+ if (aud_rt_hdr.timer_daemon)
+ {
+ if (THREAD_IS_REALTIME)
+ return 0;
+ return 1;
+ }
+ if (current->tgid != aud_lx_tgid)
+ return 1;
+ return 0;
+}
+
+/*
+ * These are the specific routines for CLOCK_SYNC timers called from the RT domain
+ */
+
+static void sync_timer_gettime(struct posix_timer *tmr, struct itimerspec * value)
+{
+ _INT64 it_period, it_delay;
+
+ it_period = tmr->itmr.it_incr;
+ it_delay = tmr->itmr.fire.it_delay;
+ convert_to_external(cl_map[tmr->it_clock]->res, &it_period, &value->it_interval);
+ convert_to_external(cl_map[tmr->it_clock]->res, &it_delay, &value->it_value);
+ return;
+}
+
+
+static int sync_timer_settime(struct posix_timer *tmr, int flags, struct itimerspec *value, struct itimerspec *ovalue)
+{
+ _INT64 it_period, it_delay;
+ long error;
+
+ if (RT_TIMER_VERBOSE)
+ printkGen("sync_timer_settime (%d)\n", (int)tmr->it_id);
+ if (ovalue != NULL)
+ sync_timer_gettime(tmr, ovalue); // read back old value
+ if (flags & TIMER_ABSTIME)
+ return (-EINVAL);
+ if ((error = convert_to_internal(cl_map[tmr->it_clock]->res, &it_period, &value->it_interval)))
+ return(error);
+ if ((error = convert_to_internal(cl_map[tmr->it_clock]->res, &it_delay, &value->it_value))) // invalid
+ return(error);
+ spin_lock_irq_hw(&ptimer_lock);
+ list_del_init(&tmr->itmr.it_link); // remove if in list
+ tmr->itmr.fire.it_delay = (int)it_delay;
+ tmr->itmr.it_incr = (int)it_period;
+ if (it_delay)
+ list_add_tail(&tmr->itmr.it_link, &cl_map[tmr->it_clock]->pending_list); // only if timer is not disarmed
+ spin_unlock_irq_hw(&ptimer_lock);
+ return(0);
+}
+
+static int sync_timer_delete(struct posix_timer *tmr) // gets only called inside RT domain
+{
+
+ spin_lock_irq_hw(&ptimer_lock);
+ list_del_init(&tmr->itmr.it_link);
+ spin_unlock_irq_hw(&ptimer_lock);
+ return(0);
+}
+
+
+/* this routine is for both domains and called through clock specific routines*/
+
+static int clock_sync_settime (clockid_t clockid, struct timespec * tp)
+{
+ _INT64 timeval;
+ int error;
+
+ if (not_authorized())
+ return -EINVAL;
+ if ((error = convert_to_internal(cl_map[clockid]->res, &timeval, tp)) < 0)
+ return(error);
+ cl_map[clockid]->clock_val = timeval;
+ spin_lock_irq_hw(&ptimer_lock);
+ list_splice_init(&cl_map[clockid]->pending_list,&cl_map[clockid]->active_list);
+ spin_unlock_irq_hw(&ptimer_lock);
+ return(0);
+}
+
+static int clock_sync_gettime(clockid_t clockid, struct timespec *value)
+{
+ return(convert_to_external(cl_map[clockid]->res , &cl_map[clockid]->clock_val, value));
+};
+
+int sync_nsleep (clockid_t clockid, int flags, struct timespec * new_setting)
+{
+ return(0);
+}
+
+/* SYNC-clock interrupt routine. This routine is for the RT-domain only.
+ * It executes at ISR level
+*/
+
+void rt_sync_clock_isr(struct sync_clock_hdr * cl)
+{
+ struct list_head *head, *tp;
+ struct itimer *itmr;
+
+ cl->clock_val += 1;
+ head = &cl->active_list;
+ for (tp = head; head != tp->next; tp = tp->next)
+ {
+ itmr = (struct itimer *)tp->next;
+ if (--itmr->fire.it_delay <= 0)
+ {
+ (itmr->timer_action(itmr->action_par));
+ if (itmr->it_incr == 0)
+ list_del_init(&itmr->it_link);
+ else
+ itmr->fire.it_delay = itmr->it_incr; // cyclic timer
+ }
+ }
+}
+
+
+void rt_clock_tick_0(void)
+{
+ rt_sync_clock_isr(&sync_clock_arr[0]);
+}
+
+
+void rt_clock_tick_1(void)
+{
+ rt_sync_clock_isr(&sync_clock_arr[1]);
+}
+
+
+void rt_clock_tick_2(void)
+{
+ rt_sync_clock_isr(&sync_clock_arr[2]);
+}
+
+static void lx_notify_task(void *arg)
+{
+ int ret;
+ struct k_itimer *timr = (struct k_itimer *)arg;
+
+ timr->sigq->info.si_signo = timr->it_sigev_signo;
+ timr->sigq->info.si_errno = 0;
+ timr->sigq->info.si_code = SI_TIMER;
+ timr->sigq->info.si_tid = timr->it_id;
+ timr->sigq->info.si_value = timr->it_sigev_value;
+ spin_lock_irq_hw(¤t->sighand->siglock);
+ if (list_empty(&timr->sigq->list))
+ timr->sigq->info.si_overrun = 0; // in overrun case gets detected in send...sigqueue
+ spin_unlock_irq_hw(¤t->sighand->siglock);
+ // in Linux send always to the specified thread only
+ // the complete scheme would require a specific create routine
+ // which in turn requires an extended k_clock structure
+ ret = send_sigqueue(timr->it_sigev_signo, timr->sigq, timr->it_process);
+}
+
+
+static int lx_sync_timer_settime(struct k_itimer *ktmr, int flags, struct itimerspec *value, struct itimerspec *ovalue)
+{
+ struct lp_itimer *tmr = (struct lp_itimer*) ktmr;
+ _INT64 it_period, it_delay;
+ long error;
+
+ if (RT_TIMER_VERBOSE)
+ printkGen("sync_timer_settime (%d)\n", (int)tmr->it_id);
+
+ if (not_authorized()) // only the rt-process is allowed to use sync_clock timers
+ return -EINVAL; // but we cannot check at creation
+ if (ovalue != NULL)
+ lx_sync_timer_gettime((struct k_itimer*)tmr, ovalue); // read back old value
+ if (flags & TIMER_ABSTIME)
+ return (-EINVAL);
+ if ((error = convert_to_internal(cl_map[tmr->it_clock]->res, &it_period, &value->it_interval)))
+ return(error);
+ if ((error = convert_to_internal(cl_map[tmr->it_clock]->res, &it_delay, &value->it_value))) // invalid
+ return(error);
+ if (tmr->itmr.lhdr == NULL) // indicator for first use
+ { // can't do it in special timer_create routine
+ if (tmr->it_sigev_notify == SIGEV_NONE)
+ tmr->itmr.action = noop;
+ if (tmr->it_sigev_notify != (SIGEV_SIGNAL_SV))
+ return (-EINVAL);
+ tmr->itmr.action = lx_notify_task; // overwrite what was done at sys_timer_create
+ INIT_LIST_HEAD(&tmr->itmr.it_link);
+ INIT_LIST_HEAD(&tmr->sigq->list);
+ tmr->itmr.lhdr = (struct rt_list_hdr*)cl_map[tmr->it_clock]; // only != NULL used as indicator only
+ tmr->itmr.action_par = tmr;
+ }
+ spin_lock_irq_hw(&ptimer_lock);
+ list_del_init(&tmr->itmr.it_link); // remove if in list
+ tmr->itmr.fire.it_delay = (int)it_delay;
+ tmr->it_incr = (int)it_period;
+ if (it_delay)
+ list_add_tail(&tmr->itmr.it_link, &cl_map[tmr->it_clock]->pending_list); // only if timer is not disarmed
+ spin_unlock_irq_hw(&ptimer_lock);
+ return(0);
+}
+
+static int lx_sync_timer_create (struct k_itimer *ktmr)
+{
+ struct lp_itimer *tmr = (struct lp_itimer*) ktmr;
+
+ tmr->itmr.lhdr = NULL; // indicator that set up work has to be done at timer_settime
+ return 0;
+}
+
+
+static int lx_sync_timer_delete(struct k_itimer *ktmr) // gets only called inside Linux domain
+{
+ struct lp_itimer *tmr = (struct lp_itimer*) ktmr;
+
+ if (tmr->itmr.it_link.prev != NULL)
+ list_del_init(&tmr->itmr.it_link);
+ return(0);
+}
+
+static void lx_sync_timer_gettime(struct k_itimer *ktmr, struct itimerspec * value)
+{
+ _INT64 it_period, it_delay;
+ struct lp_itimer *tmr = (struct lp_itimer*) ktmr;
+
+ it_period = tmr->it_incr;
+ it_delay = tmr->itmr.fire.it_delay;
+ convert_to_external(cl_map[tmr->it_clock]->res, &it_period, &value->it_interval);
+ convert_to_external(cl_map[tmr->it_clock]->res, &it_delay, &value->it_value);
+ return;
+}
+
+/*
+ * This tick routine executes as softirq/daemon inside the linux kernel
+ */
+
+ int lx_clock_proxy(void* arg)
+{
+ struct list_head *al_head, *tp;
+ struct lx_itimer *itmr;
+ struct lp_itimer *tmr;
+ struct sync_clock_hdr * cl;
+
+ cl = (struct sync_clock_hdr *)arg;
+ cl->proc = current;
+
+ daemonize("clock_sync_proxy");
+ while (!(aud_rt_hdr.state & RT_SHUTDOWN))
+ {
+ __set_current_state(TASK_UNINTERRUPTIBLE);
+ if (!cl->act_cnt)
+ schedule();
+ al_head = &cl->active_list;
+ spin_lock_irq (&ptimer_lock);
+ cl->clock_val += 1;
+ cl->act_cnt--;
+ for (tp = al_head->next; al_head != tp;)
+ {
+ itmr = (struct lx_itimer *)tp;
+ tp = tp->next;
+ if (--itmr->fire.it_delay <= 0)
+ {
+ tmr = itmr->action_par;
+ (itmr->action(tmr));
+ if (tmr->it_incr == 0)
+ {
+ list_del_init(&itmr->it_link);
+ continue;
+ }
+ else
+ itmr->fire.it_delay = tmr->it_incr;
+ }
+ }
+ spin_unlock_irq(&ptimer_lock);
+ }
+ return 0;
+}
+
+void lx_clock_tick_0(void)
+{
+ if (sync_clock_arr[0].proc)
+ {
+ sync_clock_arr[0].act_cnt++;
+ if (sync_clock_arr[0].act_cnt > 1)
+ return;
+ wake_up_process(sync_clock_arr[0].proc);
+ }
+ else
+ printkGen("No lx_clock_proxy\n");
+}
+
+void lx_clock_tick_1(void)
+{
+ if (sync_clock_arr[1].proc)
+ {
+ sync_clock_arr[1].act_cnt++;
+ if (sync_clock_arr[1].act_cnt > 1)
+ return;
+ wake_up_process(sync_clock_arr[1].proc);
+ }
+ else
+ printkGen("No lx_clock_proxy\n");
+}
+
+void lx_clock_tick_2(void)
+{
+ if (sync_clock_arr[2].proc)
+ {
+ sync_clock_arr[2].act_cnt++;
+ if (sync_clock_arr[2].act_cnt > 1)
+ return;
+ wake_up_process(sync_clock_arr[2].proc);
+ }
+ else
+ printkGen("No lx_clock_proxy\n");
+}
+
+void init_sync_clock_management(void)
+{
+ int i;
+
+ sema_init(&scl_sem, 1);
+ spin_lock_init(&ptimer_lock);
+
+ for (i = 0; i < MAX_SYNC_CLOCKS; i++)
+ {
+ sync_clock_arr[i].fp = NULL;
+ sync_clock_arr[i].clockid = 0;
+ sync_clock_arr[i].clock_val = 0;
+ INIT_LIST_HEAD(&sync_clock_arr[i].active_list);
+ INIT_LIST_HEAD(&sync_clock_arr[i].pending_list);
+ }
+
+}
+
+
+/* This routine is called from a device driver as result of a register_clock(fd, flags) which gets converted inside the library
+ * to a ioctl(fd,...,...)
+ * sync timers only make sense for a real time environment. Therefore we allow registration of a clock only for a process registered
+ * as hard realtime process, no matter whether the realtime module is loaded or not
+ */
+
+int rt_register_sync_clock(struct file* fp, int res, void(**fn)(void))
+{
+ int i;
+ clockid_t sync_clockid = -EBUSY;
+
+ if (THREAD_IS_REALTIME)
+ return -EINVAL; // registering must take place in the Linux domain
+ if (aud_lx_tgid != current->tgid) // only the process registered as hard realtime process can do it
+ return -EINVAL;
+ if ((res <= 0) || (res > NS_IN_SEC))
+ return -EINVAL;
+ if (NS_IN_SEC%res) // one second must be a multiple of res
+ return -EINVAL;
+
+ down(&scl_sem);
+ for (i = 0; i < MAX_SYNC_CLOCKS; i++)
+ if (sync_clock_arr[i].fp == fp) // only once per device
+ goto errout;
+ for (i = 0; i < MAX_SYNC_CLOCKS; i++)
+ if (sync_clock_arr[i].fp == NULL)
+ break;
+ if (i >= MAX_SYNC_CLOCKS)
+ {
+ sync_clockid = -ESRCH;
+ goto errout;
+ }
+ lx_clock_sync.res = res; // is used in Linux as an indicator for a used clock
+ if (aud_rt_hdr.state == RT_INSTALLED)
+ { // if installed only the realtime domain can use this clockid
+ cl_arr[i].res = res;
+ sync_clockid = register_new_posix_clock((clockid_t)-1, &lx_clock_sync_false); // make sure clockid can't be used in Linux
+ sync_clockid = rtlpr->rt_register_clock(sync_clockid, &cl_arr[i]);
+ *fn = sync_clock_arr[i].rt_clock_isr;
+ }
+ else
+ {
+ sync_clockid = register_new_posix_clock((clockid_t)-1, &lx_clock_sync);
+ kernel_thread(lx_clock_proxy, (void*)&sync_clock_arr[i], 0);
+ *fn = sync_clock_arr[i].lx_clock_isr;
+ }
+ cl_map[sync_clockid] = &sync_clock_arr[i];
+ sync_clock_arr[i].clockid = sync_clockid;
+ sync_clock_arr[i].fp = fp;
+ sync_clock_arr[i].res = res;
+errout:
+ up(&scl_sem);
+ return sync_clockid;
+}
+
+/*
+ * This routine gets called from a device driver
+ * -- when it receives a close from a process which has successfully registered
+ * a sync_clock, meaning the release() routine of the driver has to call it
+ * This also covers the shutdown of the realtime domain
+ */
+
+int rt_unregister_sync_clock(struct file* fp)
+{
+ int i, clockid;
+
+ down(&scl_sem);
+ for (i = MAX_SYNC_CLOCKS - 1; i >= 0; i--) {
+ if (!sync_clock_arr[i].fp) {
+ continue;
+ }
+ if ((sync_clock_arr[i].fp == fp) || ((fp == NULL) && sync_clock_arr[i].fp))
+ {
+ clockid = sync_clock_arr[i].clockid;
+ unregister_posix_clock(clockid);
+ rtlpr->rt_unregister_clock(clockid);
+ INIT_LIST_HEAD(&sync_clock_arr[i].active_list);
+ INIT_LIST_HEAD(&sync_clock_arr[i].pending_list);
+ sync_clock_arr[i].clockid = 0;
+ sync_clock_arr[i].fp = NULL;
+ up(&scl_sem);
+ if (fp)
+ return (0);
+ }
+ }
+ up(&scl_sem);
+ if (fp)
+ return -EINVAL;
+ return 0;
+}
+
+
+
+#if defined LINUX_RMOS_TARGET
+#elif defined LINUX_ECOS_TARGET
+#else
+EXPORT_SYMBOL(rt_register_sync_clock);
+EXPORT_SYMBOL(rt_unregister_sync_clock);
+EXPORT_SYMBOL(ptimer_lock);
+#endif
+
+
+
+
+
diff -N -a -u -r linux-2.6.15.4/drivers/aud/audrealtime/aud_ipipe.c aud_linux/drivers/aud/audrealtime/aud_ipipe.c
--- linux-2.6.15.4/drivers/aud/audrealtime/aud_ipipe.c 1970-01-01 01:00:00.000000000 +0100
+++ aud_linux/drivers/aud/audrealtime/aud_ipipe.c 2007-04-14 06:47:29.000000000 +0200
@@ -0,0 +1,307 @@
+/*
+ * rtime/audrealtime/aud_ipipe.c
+ *
+ * 2007-19-01: Karl-Heinz.Krause@siemens.com
+ * Copyright (c) 2007 Siemens AG
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * This file contains the interface functions between the realtime module and ipipe
+ */
+
+#include "../include/rt_timer.h"
+
+#define AuD_DOMAIN_ID 0x16061986
+
+
+void to_lx_isr(unsigned, void*);
+void to_rt_isr(unsigned, void*);
+void wake_up_lx_isr(unsigned, void *);
+asmlinkage void math_state_restore(void);
+#ifdef CONFIG_SMP
+fastcall void rtx_preemption_isr(struct pt_regs *regs);
+#endif
+
+int rt_reschedule(struct task_struct *);
+int rt_clock_settime(void);
+extern task_t *rt_curr_task;
+extern long rt_syscall_table_size_ref;
+extern long rt_sys_call_table;
+extern long (*sys_rt_syscall_table)(int op, int par);
+extern struct dom_hdr aud_rt_hdr;
+extern struct ipipe_domain *ipipe_root_domain;
+extern struct ipipe_domain *ipipe_percpu_domain[];
+extern struct ipipe_domain aud_domain;
+struct ipipe_domain_attr aud_rt_domain_attr = {
+ .name = "aud_rt_domain",
+ .domid = AuD_DOMAIN_ID,
+ .priority = IPIPE_HEAD_PRIORITY,
+};
+
+extern unsigned long aud_lx_tgid;
+extern struct timespec new_lx_time;
+
+unsigned ex_lx_irq; // irq for notifying the linux daemon for futex and execution in Linux
+unsigned wr_lx_irq; // irq for notifying the linux thread for write buffer handling
+unsigned to_rt_irq; // irq for waking up the realtime domain;
+unsigned wake_up_lx_irq; // irq for functions which require only a wake_up_process and can therefore
+ // executed directly from ISR level
+
+#ifdef CONFIG_SMP
+/*
+ * Check whether a sched_setscheduler() in the Linux domain has affected a running realtime thread
+ * Before calling this routine via the hook Linux has already changed the scheduling parameters.
+ * Since p->array == NULL no further action was taken in Linux code, but now there may be a thread in the
+ * realtime threadlist which is no longer eligible for executing in the realtime domain.
+ */
+static int aud_lx_sched_change(unsigned event, struct ipipe_domain *ipd, void *data)
+{
+ struct task_struct *p = (struct task_struct *)data;
+
+ if (p->state & RT_TASK_RUNNING)
+ rt_reschedule(p); // it is a running thread of the realtime domain
+ return 0;
+}
+#endif
+ // rt domain hook for syscall prologue of entry.S
+static int aud_rt_syscall_entry(unsigned event, struct ipipe_domain *ipd, void *data)
+{
+ struct pt_regs *regs = (struct pt_regs *)data;
+ unsigned syscall_no = regs->eax;
+ int (*rt_sys_call)(unsigned a, unsigned b, unsigned c, unsigned d, unsigned e);
+
+ if (syscall_no > rt_syscall_table_size_ref / sizeof(void *))
+ {
+ printkGen("rt: syscall opcode too big (%d)\n", syscall_no);
+ regs->eax = -ENOSYS; //(1)
+ return 1;
+ }
+
+/* There are two types of rt_sys_call handling:
+ * - (1)complete, autonomous execution, thread stays in the realtime domain, no tailwork should be performed
+ * - (2)thread migration to Linux, execution of entry.s code continues in Linux domain
+ */
+ rt_sys_call = (int (*)(unsigned a, unsigned b, unsigned c, unsigned d, unsigned e))*(&rt_sys_call_table + syscall_no);
+ if (RT_SYSCALL_VERBOSE)
+ printkGen("enter rt syscall id=%d p=%p pri=%d\n", syscall_no, current, current->prio);
+ regs->eax = rt_sys_call(regs->ebx, regs->ecx, regs->edx, regs->esi, regs->edi);
+ if (THREAD_IS_REALTIME) // (1)
+ return 1;
+ if (RT_SYSCALL_VERBOSE)
+ printkGen("rt syscall executes in Linux id=%d p=%p pri=%d\n", syscall_no, current, current->prio);
+ return 0; // (2)
+}
+
+
+/*
+ * aud_lx_syscall_exit checks at system call exit whether the thread needs to migrate to the realtime domain
+ */
+
+static int aud_lx_syscall_exit(unsigned event, struct ipipe_domain *ipd, void *data)
+{
+ if (IS_HARD_REALTIME_PROCESS(current))
+ {
+ if (!AuD_REALTIME_PRIO(current)) {
+ return 0; // m.n. don't migrate when prio too low
+ }
+// if (current->pid == current->tgid)
+ if (current == aud_rt_hdr.rt_proc)
+ {
+ if (RT_FAULT_VERBOSE)
+ printkGen ("tgid anchor thread not allowed to migrate %x\n", (unsigned)aud_rt_hdr.rt_proc);
+ return 0; // either main thread read thread is not allowed to migrate
+ }
+ if ((current->thread_info->flags) & _TIF_ALLWORK_MASK)
+ {
+ if (RT_MIGRATE_VERBOSE)
+ printkGen("TIF flags set %x\n", (unsigned)current->thread_info->flags);
+ current->thread_info->flags &= ~_TIF_ALLWORK_MASK;
+ }
+ clear_tsk_thread_flag(current, TIF_NOTIFY_RESUME);
+ clear_tsk_thread_flag(current, TIF_NEED_RESCHED);
+ __ipipe_unstall_root(); // in case it is locked
+ if (migrate_to_rt(USER_THREAD) == -1)
+ return 0;
+ // now thread executes in the realtime domain
+ if (new_lx_time.tv_nsec >= 0) // clock_settime calls has marked an update pending
+ rt_clock_settime();
+ return 1;
+ }
+ return 0;
+}
+
+
+unsigned rt_get_exec_domain(void)
+{
+ if (ipipe_current_domain == ipipe_root_domain)
+ return LX_EXEC;
+ return RT_EXEC;
+
+}
+
+
+static const int trap2sig[] = {
+ SIGFPE, // 0 - Divide error
+ SIGTRAP, // 1 - Debug
+ SIGSEGV, // 2 - NMI (but we ignore these)
+ SIGTRAP, // 3 - Software breakpoint
+ SIGSEGV, // 4 - Overflow
+ SIGSEGV, // 5 - Bounds
+ SIGILL, // 6 - Invalid opcode
+ SIGSEGV, // 7 - Device not available
+ SIGSEGV, // 8 - Double fault
+ SIGFPE, // 9 - Coprocessor segment overrun
+ SIGSEGV, // 10 - Invalid TSS
+ SIGBUS, // 11 - Segment not present
+ SIGBUS, // 12 - Stack segment
+ SIGSEGV, // 13 - General protection fault
+ SIGSEGV, // 14 - Page fault
+ 0, // 15 - Spurious interrupt
+ SIGFPE, // 16 - Coprocessor error
+ SIGBUS, // 17 - Alignment check
+ SIGSEGV, // 18 - Reserved
+ SIGFPE, // 19 - XMM fault
+ 0,0,0,0,0,0,0,0,0,0,0,0
+};
+
+#define TRAP_SINGLE_STEP 1
+#define TRAP_SW_DEBUG 3
+#define TRAP_DEV_NOT_AVAILABLE 7
+
+
+/*
+ * With the exception of fp error for saving/restoring the fpu context all faults are handled in the Linux domain
+ * e.g. an installed handler gets executed in the Linux domain. The base assumption is, that within time critical
+ * paths a thread has to avoid running into an exception. So execution in the Linux domain should not pose a problem.
+ * On the other hand it is the most elegant solution saving a lot of implementation efforts.
+ */
+static int aud_rt_trap_handling(unsigned event, struct ipipe_domain *ipd, void *data)
+{
+ struct pt_regs *regs = (struct pt_regs *)data;
+
+ if (THREAD_IS_REALTIME) {
+ if(RT_EXCEPTION_VERBOSE)
+ printkGen("fault: p=%p pid: %d eip=%#x in aud_rt_domain except=%d\n", current, current->pid, regs->eip, event);
+ switch(event) {
+ case TRAP_SINGLE_STEP:
+ break;
+ case TRAP_SW_DEBUG:
+ break;
+ case TRAP_DEV_NOT_AVAILABLE:
+ if (RT_EXCEPTION_VERBOSE)
+ printkGen("Floating point exception in RT domain\n");
+ math_state_restore();
+ current->fpu_counter = 6; // force math_restore for all subsequent context switches
+ return 1;
+ default:
+ execute_in_lx();
+ return 0; // execute exception in the Linux domain
+ }
+ }
+ do_rt_leave();
+ do_exit(event);
+ return 0; // return value not relevant
+}
+
+
+/*********************** init *********************************************************/
+
+int setup_aud_rt_domain(void)
+{
+ unsigned trapnr;
+ int ret = 0;
+
+ if (ipipe_register_domain(&aud_domain, &aud_rt_domain_attr))
+ {
+ printkGen("registering aud_rt_domain failed\n");
+ return -EBUSY;
+ }
+
+#ifdef CONFIG_SMP
+ if ((ret = ipipe_virtualize_irq(&aud_domain,
+ RESCHEDULE_VECTOR - FIRST_EXTERNAL_VECTOR,
+ (ipipe_irq_handler_t)&rtx_preemption_isr,
+ NULL,
+ NULL,
+ IPIPE_DEFAULT_MASK)))
+ return ret;
+
+ if (RT_INIT_VERBOSE)
+ printkGen("IPI reschedule: irq=%d for rtx_preemption_isr\n", RESCHEDULE_VECTOR - FIRST_EXTERNAL_VECTOR);
+#endif
+
+ // setup the communication soft IRQs
+ ex_lx_irq = ipipe_alloc_virq();
+ if ((ret = ipipe_virtualize_irq(ipipe_root_domain, ex_lx_irq, to_lx_isr,(void *)&aud_rt_hdr.to_lx_sm, NULL, IPIPE_HANDLE_MASK)))
+ return ret;
+ if (RT_INIT_VERBOSE)
+ printkGen("Virq %d for ex_lx_irq \n", ex_lx_irq);
+ wr_lx_irq = ipipe_alloc_virq();
+ if ((ret = ipipe_virtualize_irq(ipipe_root_domain, wr_lx_irq, to_lx_isr, (void *)&aud_rt_hdr.write_sm, NULL, IPIPE_HANDLE_MASK)))
+ return ret;
+
+// try for fast wake up
+ wake_up_lx_irq = ipipe_alloc_virq();
+ if ((ret = ipipe_virtualize_irq(ipipe_root_domain, wake_up_lx_irq, wake_up_lx_isr, NULL, NULL, IPIPE_HANDLE_MASK)))
+ return ret;
+
+ if (RT_INIT_VERBOSE)
+ printkGen("Virq %d for wr_lx_irq \n", wr_lx_irq);
+ if ((to_rt_irq = ipipe_alloc_virq()) < 0) // checking the last only should be okay
+ return ret;
+ if ((ret = ipipe_virtualize_irq(&aud_domain, to_rt_irq, to_rt_isr, NULL, NULL, IPIPE_HANDLE_MASK )))
+ return ret;
+ if (RT_INIT_VERBOSE)
+ printkGen("Virq %d for to_rt_irq \n", to_rt_irq);
+
+#ifdef CONFIG_SMP
+ ipipe_catch_event(ipipe_root_domain, IPIPE_EVENT_SELF|IPIPE_EVENT_SETSCHED, aud_lx_sched_change);
+#endif
+ ipipe_catch_event(&aud_domain, IPIPE_EVENT_SELF|IPIPE_EVENT_SYSCALL, aud_rt_syscall_entry);
+ ipipe_catch_event(ipipe_root_domain, IPIPE_EVENT_SELF|IPIPE_EVENT_SYSCALL_EX, aud_lx_syscall_exit);
+
+ // subscribe for trap handling
+ for (trapnr = 0; trapnr < IPIPE_NR_FAULTS; trapnr++)
+ {
+ if (trapnr == 2)
+ continue; // NMI not handled
+ ipipe_catch_event(&aud_domain, IPIPE_EVENT_SELF | trapnr, aud_rt_trap_handling);
+ }
+ if (RT_INIT_VERBOSE)
+ printkGen("aud rt domain initialized\n");
+ return(0);
+}
+
+void destroy_aud_rt_domain(void)
+{
+#ifdef CONFIG_SMP
+ ipipe_virtualize_irq(&aud_domain,
+ RESCHEDULE_VECTOR - FIRST_EXTERNAL_VECTOR,
+ NULL,
+ NULL,
+ NULL,
+ IPIPE_DEFAULT_MASK);
+#endif
+
+ ipipe_free_virq(ex_lx_irq);
+ ipipe_free_virq(wr_lx_irq);
+ ipipe_free_virq(to_rt_irq);
+ ipipe_free_virq(wake_up_lx_irq);
+ ipipe_unregister_domain(&aud_domain);
+ // Deleting event handler
+ ipipe_catch_event(ipipe_root_domain, IPIPE_EVENT_SETSCHED, NULL);
+ ipipe_catch_event(ipipe_root_domain, IPIPE_EVENT_SYSCALL_EX, NULL);
+}
+
diff -N -a -u -r linux-2.6.15.4/drivers/aud/audrealtime/fs_op.c aud_linux/drivers/aud/audrealtime/fs_op.c
--- linux-2.6.15.4/drivers/aud/audrealtime/fs_op.c 1970-01-01 01:00:00.000000000 +0100
+++ aud_linux/drivers/aud/audrealtime/fs_op.c 2007-04-10 20:49:26.000000000 +0200
@@ -0,0 +1,231 @@
+/*
+ * rtime/audrealtime/fs_op.c
+ *
+ * 2007-19-01: Karl-Heinz.Krause@siemens.com
+ * Copyright (c) 2007 Siemens AG
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * This file contains the routines for handling the file system operations allowed in the realtime domain.
+ * This include the basic entry routines for read(), write() and ioctl() and the write buffer management for fd 1 and 2
+ * (stdout, stderr). The write() calls in the realtime domain fill the buffer, the corresponding routines for emptying the
+ * buffer are executed in the Linux domain
+ */
+
+#include "../include/rt_timer.h"
+#include "../include/rt_buffer.h"
+
+struct file *rt_fcheck_files(struct file *, int);
+
+unsigned msg_count;
+
+static struct com_buf {
+ spinlock_t lock;
+ struct buf_head buf_begin;
+ char buffer[BUFLEN];
+ struct buf_head buf_end;
+} buffer;
+
+static struct buf_head *rpr, *old_wpr, *wpr;
+
+
+struct file* rt_fcheck_file_fd(int fd, int flags)
+{
+ struct file *filp;
+ struct files_struct *fls = current->files;
+ struct fdtable *fdt;
+
+ do{
+ fdt = files_fdtable(fls);
+ filp = fdt->fd[fd];
+ }while(fdt != files_fdtable(fls)); // to circumvent the RCU stuff
+ if (flags)
+ return rt_fcheck_files(filp, flags);
+ return filp;
+}
+
+
+void init_write_buffer(void)
+{
+ msg_count = 0;
+ memset(&buffer, 0, sizeof(buffer));
+ spin_lock_init(&buffer.lock);
+ buffer.buf_begin.link = &buffer.buf_begin;
+ buffer.buf_end.link = &buffer.buf_begin;
+ buffer.buf_begin.state = BUF_EMPTY ;
+ buffer.buf_begin.overrun = 0;
+ wpr = &buffer.buf_begin;
+ old_wpr = wpr;
+ rpr = wpr;
+ return;
+}
+
+
+struct buf_head* get_write_buffer(int wrlen)
+{
+ struct buf_head *req_wpr;
+ int len;
+ unsigned irqFlag;
+
+ len = (wrlen + sizeof(struct buf_head) + 3) & ~0x3; // size rounded to the next 32-Bit boundary
+ req_wpr = NULL;
+ if (len >= BUFLEN/2)// a pragmatic check to allow for a simple buffer managment
+ return(NULL);
+ spin_lock_irqsave_hw(&buffer.lock, irqFlag);
+ if (rpr <= wpr)
+ { // wrap around of free area
+ if (((int)&buffer.buf_end - (int) wpr) >= (len + (int)sizeof(struct buf_head)))
+ goto out_ok;
+ if (((int)rpr - (int)&buffer.buf_begin) >= (len + (int)sizeof(struct buf_head)))
+ {
+ wpr->link = &buffer.buf_begin;
+ wpr = &buffer.buf_begin;
+ wpr->overrun = 0;
+ goto out_ok;
+ }
+ old_wpr->overrun += 1;
+ goto out_not_ok;
+ }
+ else
+ if (((int)rpr - (int)wpr) < (len + (int)sizeof(struct buf_head)))
+ {
+ old_wpr->overrun += 1;
+ goto out_not_ok;
+ }
+out_ok:
+ old_wpr = wpr;
+ req_wpr = wpr;
+ req_wpr->state = BUF_REQUESTED;
+ wpr = (struct buf_head *)((int)wpr + len);
+ req_wpr->link = wpr;
+ wpr->link = rpr; // remaining free area element
+ wpr->state = BUF_EMPTY;
+ wpr->overrun = 0;
+ msg_count++;
+out_not_ok:
+ spin_unlock_irqrestore_hw(&buffer.lock, irqFlag);
+ return(req_wpr);
+};
+
+/*
+ * routine for reading an element of the comm buffer and copying into the user buffer of the read call
+ * the read point rpr needs no locking, since there is only one instance which modifies it
+ */
+
+int rt_read_buffer(char *addr, int len)
+{
+ int retval = -EINVAL;
+
+ while (rpr->state != BUF_FILLED) {
+ if ((rpr->link == &buffer.buf_begin) && (rpr != &buffer.buf_begin)){
+ rpr = &buffer.buf_begin;
+ continue;
+ }
+ return(-EAGAIN);
+ }
+ retval = (int)rpr->link - (int)rpr;
+ if (len < retval) // message doesn't fit into the user buffer
+ retval = len;
+ else if (len > retval) // return correct length
+ len = retval;
+ retval = copy_to_user(addr, (char *) rpr, retval);
+ spin_lock_irq_hw(&buffer.lock);
+ rpr = rpr->link;
+ wpr->link = rpr;
+ msg_count--;
+ spin_unlock_irq_hw(&buffer.lock);
+ if (retval)
+ return -EFAULT;
+ return (len);
+}
+
+int rt_write_buffered(unsigned mode, void *buff, unsigned len)
+{
+ struct buf_head *wpr;
+ struct buf_std_info *myStringInfo;
+
+ wpr = get_write_buffer(len + sizeof(int));
+ if (wpr == NULL) {
+ return(-1);
+ }
+ myStringInfo = (struct buf_std_info *) wpr;
+
+ wpr->type = mode;
+ myStringInfo->len = len;
+ memcpy(myStringInfo->info, buff, len);
+ wpr->state = BUF_FILLED; // mark buffer
+ ipipe_trigger_irq(wr_lx_irq);
+ return(len);
+}
+
+
+asmlinkage long sys_rt_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+ struct file * filp;
+
+ filp = rt_fcheck_file_fd(fd, RT_IO_IOCTL);
+ if (filp && filp->f_op)
+ {
+ if (filp->f_op->unlocked_ioctl)
+ return filp->f_op->unlocked_ioctl(filp, cmd, arg);
+ else
+ return -EINVAL; // plain/old ioctl() not allowed for RT-access
+ }
+ execute_in_lx();
+ return(0);
+}
+
+
+asmlinkage ssize_t sys_rt_read(unsigned int fd, char __user * buf, size_t count)
+{
+ struct file *filp;
+
+ filp = rt_fcheck_file_fd(fd, RT_IO_READ);
+ if (filp && filp->f_op && filp->f_op->read)
+ return filp->f_op->read(filp, buf, count, NULL);
+ execute_in_lx();
+ return(0);
+}
+
+/*
+ * For surviving dup we might want to tie the decision whether to use the buffer mechanism for stdout and stderr
+ * on the filp rather on the fd. In this case we have to compare against both filps (which have been saved at init time)
+ * The current solution seems also sufficient we get the messages out
+ */
+
+
+asmlinkage ssize_t sys_rt_write(unsigned int fd, const char __user * buf, size_t count)
+{
+ struct file *filp;
+
+ if (RT_WRITE_VERBOSE)
+ printkGen("sys_rt_write: fd=%d buf=%p count=%d)\n", fd, buf, count);
+ switch (fd){
+ case 0:
+ return -EBADF;
+ case 1:
+ return rt_write_buffered(PROP_STD_OUT, (char *) buf, count);
+ case 2:
+ return rt_write_buffered(PROP_STD_ERR, (char *) buf, count);
+ default:
+ filp = rt_fcheck_file_fd(fd, RT_IO_READ);
+ if (filp && filp->f_op && filp->f_op->write)
+ return filp->f_op->write(filp, buf, count, NULL);
+ }
+ execute_in_lx();
+ return(0);
+}
+
diff -N -a -u -r linux-2.6.15.4/drivers/aud/audrealtime/futex.c aud_linux/drivers/aud/audrealtime/futex.c
--- linux-2.6.15.4/drivers/aud/audrealtime/futex.c 1970-01-01 01:00:00.000000000 +0100
+++ aud_linux/drivers/aud/audrealtime/futex.c 2007-04-10 20:49:26.000000000 +0200
@@ -0,0 +1,253 @@
+/*
+ * rtime/audrealtime/futex.c
+ *
+ * 2007-19-01: Karl-Heinz.Krause@siemens.com
+ * Copyright (c) 2007 Siemens AG
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *
+ * In order to maintain the realtime capability we cannot use the linux
+ * mm-semaphore. Therefore the virtual address inside the realtime process
+ * is solely used as key. This is possible since
+ * -- the complete RT process is locked into memory
+ * -- only one RT-process is supported
+ * -- (so far) no futexes on shared memory are supported.
+ * In case futexes on shared memory need to get supported
+ * we would have to map to physical and then do a reverse map to virtual to the
+ * address space of the realtime process before calling realtime . Since this is
+ * all done at the Linux side, there is no problem with the mm-lock
+ * A scan through a hash queue is protected by a spinlock which disables interrupts.
+ * Because of the size of the local RT-hashqueue this is viewed to be acceptable also
+ * for the worst case szenario
+ */
+
+#include "../include/rt_timer.h"
+
+#include <linux/jhash.h>
+
+#define FUTEX_HASHBITS 8
+
+void add_lx_request(struct lx_cmd*);
+struct lx_cmd* get_lx_request(void);
+long copy_conv_to_internal(long long *itr, struct timespec *uvalue);
+
+
+/*
+ * Futexes take the virtual address as key.
+ */
+struct futex_q {
+ struct list_head list;
+ unsigned long key;
+ struct task_struct *proc;
+};
+
+/*
+ * Split the global futex_lock into every hash list lock.
+ */
+struct futex_hash_bucket {
+ spinlock_t lock;
+ struct list_head chain;
+};
+
+static struct futex_hash_bucket futex_queues[1<<FUTEX_HASHBITS];
+
+/*
+ * Get the hash bucket
+ */
+static inline struct futex_hash_bucket *hash_futex(unsigned long key)
+{
+ u32 hash = jhash_1word(key, key);
+ return &futex_queues[hash & ((1 << FUTEX_HASHBITS)-1)];
+}
+
+
+int rt_futex_wake(unsigned long uaddr)
+{
+
+ struct futex_hash_bucket *bh;
+ struct list_head *lp;
+ struct futex_q *fu;
+
+ bh = hash_futex(uaddr);
+ spin_lock_irq_hw(&bh->lock);
+ for (lp = bh->chain.next; lp != &bh->chain; lp = lp->next)
+ {
+ fu = (struct futex_q *)lp;
+ if (fu->key == uaddr)
+ {
+ list_del_init(lp);
+ spin_unlock_irq_hw(&bh->lock);
+ rt_wake_up_thread(fu->proc);
+ return 1;
+ }
+ }
+ spin_unlock_irq_hw(&bh->lock);
+ return 0;
+}
+
+/*
+ * This routine gets executed in the Linux domain. So far futexes work only inside the realtime process
+ * In case it has to work also between the realtime process and other processes, an address mapping has
+ * to be done, virtual -> physical, physical -> virtual of realtime process
+ */
+
+asmlinkage int rt_futex_wake_from_lx(unsigned long uaddr, int val)
+{
+ int nr = 0;
+
+ if ((current->tgid != aud_lx_tgid) || (current == aud_rt_hdr.to_lx_daemon))
+ return 0;
+ do {
+ if (!rt_futex_wake(uaddr))
+ break;
+ nr++;
+ continue;
+ }while (nr < val);
+ if (nr)
+ ipipe_trigger_irq(to_rt_irq);
+ return nr;
+}
+
+int rt_futex_wait(unsigned long uaddr, int val, int timeoutFlag, long long time)
+{
+ struct futex_hash_bucket *bh;
+ int curval;
+ struct futex_q q;
+ int retVal;
+
+ if ((retVal = copy_from_user(&curval, (long unsigned*) uaddr, sizeof(unsigned long))) < 0)
+ return -EFAULT; // only to make sure that afterwards it can get accessed
+
+ bh = hash_futex(uaddr);
+ INIT_LIST_HEAD(&q.list);
+ q.key = uaddr;
+ q.proc = current;
+
+ __set_current_state(RT_TASK_UNINTERRUPTIBLE);
+ spin_lock_irq_hw(&bh->lock);
+ list_add_tail(&q.list, &bh->chain);
+ spin_unlock_irq_hw(&bh->lock);
+ curval = *(int*)uaddr; // it is accessible without fault
+ if (curval != val) {
+ spin_lock_irq_hw(&bh->lock);
+ list_del_init(&q.list);
+ spin_unlock_irq_hw(&bh->lock);
+ __set_current_state(RT_TASK_RUNNING);
+ return -EWOULDBLOCK;
+ }
+ time = rt_schedule_timeout(timeoutFlag, time);
+ if (!timeoutFlag)
+ return 0;
+ if (time == 0)
+ {
+ spin_lock_irq_hw(&bh->lock);
+ list_del_init(&q.list);
+ spin_unlock_irq_hw(&bh->lock);
+ return -ETIMEDOUT;
+ }
+ return 0;
+}
+
+void rt_init_futex(int no_of_fu_req)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(futex_queues); i++) {
+ INIT_LIST_HEAD(&futex_queues[i].chain);
+ spin_lock_init(&futex_queues[i].lock);
+ }
+}
+
+int do_in_linux(unsigned long uaddr, int op, int val, unsigned long uaddr2, int val2, int val3)
+{
+ struct lx_cmd *cptr;
+
+ if ((cptr = get_lx_request()) == NULL)
+ return -EFAULT; // should we try to pause some time?
+ cptr->_req._fuop.uaddr = uaddr;
+ cptr->_req._fuop.op = op;
+ cptr->_req._fuop.val = val;
+ cptr->_req._fuop.uaddr2 = uaddr2;
+ cptr->_req._fuop.val2 = val2;
+ cptr->_req._fuop.val3 = val3;
+ cptr->type = EXEC_FUTEX_LX;
+ add_lx_request(cptr);
+ return val; // we cannot wait for the actual number
+}
+
+
+asmlinkage long sys_rt_futex(u32 __user *uaddr, int op, int val, struct timespec __user *utime, u32 __user *uaddr2, int val3)
+{
+ long long timeout = 0;
+ long unsigned offset;
+ int val2 = 0;
+ int timeoutFlag = 0; // wait indefinitely
+ int nr = 0;
+ long ret;
+
+ if (RT_FUTEX_VERBOSE) {
+ unsigned myKernelVal = *uaddr;
+ printkGen("running through my futexRt (%p(%#x):%d:%d:%p)\n", uaddr, myKernelVal, op, val, utime);
+ }
+ offset = (long unsigned)uaddr % PAGE_SIZE; //check for a naturally aligned futex
+ if (unlikely((offset % sizeof(u32)) != 0))
+ return -EINVAL;
+ switch (op)
+ {
+ case FUTEX_WAKE:
+ {
+ do {
+ if (!rt_futex_wake((unsigned long) uaddr))
+ break;
+ nr++;
+ }while (nr < val);
+ if (nr)
+ rt_check_preemption();
+ if (nr < val)
+ // number of requested wakeups not fulfilled
+ do_in_linux((unsigned long)uaddr, op, val-nr, (unsigned long)uaddr2, val2, val3);
+ return nr;
+ }
+ case FUTEX_WAIT:
+ {
+ if (utime) {
+ if ((ret = copy_conv_to_internal(&timeout, utime)) < 0)
+ return(ret);
+ if (RT_FUTEX_VERBOSE) {
+ printkGen("FutexRt timeout:%ld\n", timeout);
+ }
+ if (timeout == 0)
+ return(0);
+ timeoutFlag = 1;
+ }
+ return rt_futex_wait((unsigned long)uaddr, val, timeoutFlag, timeout);
+ }
+ case FUTEX_CMP_REQUEUE:
+ {
+ val2 = (int) (long) utime;
+ return do_in_linux((unsigned long)uaddr, op, val, (unsigned long)uaddr2, val2, val3);
+ }
+ default:
+ return -ENOSYS;
+ }
+ return 0;
+}
+
+
+
+
+
diff -N -a -u -r linux-2.6.15.4/drivers/aud/audrealtime/Makefile aud_linux/drivers/aud/audrealtime/Makefile
--- linux-2.6.15.4/drivers/aud/audrealtime/Makefile 1970-01-01 01:00:00.000000000 +0100
+++ aud_linux/drivers/aud/audrealtime/Makefile 2007-04-10 20:49:26.000000000 +0200
@@ -0,0 +1,9 @@
+#
+# Makefile for the AuD Linux HARD realtime device driver
+#
+# 2007-02-15 hw3671 wolfgang.hartmann@siemens.com
+#
+obj-$(CONFIG_AuD_HARD_REALTIME) := audrealtime.o
+audrealtime-y := fs_op.o realtime_base.o rt_timer.o semaphore.o \
+ sched.o signal.o thread.o syscall_table.o futex.o aud_ipipe.o\
+ rt_mqueue.o
diff -N -a -u -r linux-2.6.15.4/drivers/aud/audrealtime/realtime_base.c aud_linux/drivers/aud/audrealtime/realtime_base.c
--- linux-2.6.15.4/drivers/aud/audrealtime/realtime_base.c 1970-01-01 01:00:00.000000000 +0100
+++ aud_linux/drivers/aud/audrealtime/realtime_base.c 2007-04-10 20:49:27.000000000 +0200
@@ -0,0 +1,665 @@
+/*
+ * rtime/audrealtime/realtime_base.c
+ *
+ * 2007-19-01: Karl-Heinz.Krause@siemens.com
+ * Copyright (c) 2007 Siemens AG
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * This file links the realtime module to the AuD-Driver and to the kernel
+ * In particular it contains all the base functions for setting up and
+ * shutting down the realtime domain and for thread migration between
+ * the two domains.
+ */
+
+
+#include "../include/rt_timer.h"
+#include <asm/i387.h>
+
+
+#define AuD_REALTIME_NAME "audrealtime"
+
+static int init_AuD_realtime(void);
+static void cleanup_AuD_realtime(void);
+
+MODULE_AUTHOR("Karl-Heinz Krause");
+MODULE_DESCRIPTION (AuD_REALTIME_NAME);
+MODULE_LICENSE("GPL");
+
+unsigned rt_version = 0x01012007;
+
+void rt_init_sched(void);
+void rt_init_futex(void);
+void init_lx_request_list(void);
+void init_write_buffer(void);
+
+#ifdef CONFIG_SMP
+void rt_pin_irqs(void);
+void rt_unpin_irqs(void);
+#endif
+
+
+int setup_aud_rt_domain(void);
+void destroy_aud_rt_domain(void);
+int sched_setscheduler(struct task_struct*, int, struct sched_param *);
+int set_execution_environment(int);
+int rt_unregister_sync_clock(struct file*);
+int rt_init_realtime(void);
+void rt_shutdown_realtime(void);
+int rt_read_buffer(char*, int);
+int rt_write_buffered(unsigned, void *, unsigned);
+int rt_futex_wake_from_lx(unsigned long, int);
+void rt_check_for_work(void);
+void rt_settime_from_lx(struct timespec *);
+int do_check_rt(void*);
+long do_futex(unsigned long, int, int, unsigned long, unsigned long, int, int);
+int rt_install_isr_rt (int, void (*)(unsigned, void*), int);
+unsigned rt_get_exec_domain(void);
+void rt_set_diagnosis(unsigned);
+void rt_noop_work(void);
+
+extern int (*rtx_futex_wake_handling)(unsigned long, int);
+extern void (*rtx_preemption_handling)(void);
+extern void (*rtx_wake_lx_handling)(struct proc_wait_queue *);
+extern void (*rtx_settime_handling)(struct timespec *);
+
+#ifdef CONFIG_SMP
+static cpumask_t rt_cpu_mask = {{ [0 ... BITS_TO_LONGS(NR_CPUS)-1] = 1UL }};
+#endif
+
+struct rt_link_desc rt_link = {
+ .rt_register_clock = rt_register_clock,
+ .rt_unregister_clock = rt_unregister_clock,
+ .rt_send_sigqueue = rt_send_sigqueue,
+ .rt_send_alt_sigqueue = rt_send_alt_sigqueue,
+ .rt_dequeue_sigq = rt_dequeue_sigq,
+ .rt_find_task_by_pid = rt_find_task_by_pid,
+ .rt_shutdown_realtime = rt_shutdown_realtime,
+ .do_timer_rt = do_timer_rt,
+ .do_check_rt = do_check_rt,
+ .up_rt = up_rt,
+ .down_rt = down_rt,
+ .do_migrate_to_rt = do_migrate_to_rt,
+ .do_execute_in_lx = do_execute_in_lx,
+ .rt_read_buffer = rt_read_buffer,
+ .rt_write_buffered = rt_write_buffered,
+ .rt_get_exec_domain = rt_get_exec_domain,
+ .rt_init_realtime = rt_init_realtime,
+};
+
+extern struct rt_link_desc *rtlpr;
+extern struct rt_config_cntrl aud_config;
+
+extern struct semaphore AuDDevSem;
+extern struct ipipe_domain aud_ipd;
+extern struct ipipe_domain *ipipe_root_domain;
+
+extern struct dom_hdr aud_rt_hdr;
+extern unsigned long aud_lx_tgid;
+extern unsigned wake_up_lx_irq;
+
+long sys_rt_ni_syscall(void)
+{
+ if (RT_FAULT_VERBOSE)
+ printkGen("RT syscall not implemented\n");
+ return -ENOSYS;
+}
+
+
+/*
+ * The optional realtime module gets loaded after the AuDDriver, but some its functions do get called by/through
+ * the AuDDriver. Therefore all what the init-routine of the realtime module does is to make available the
+ * function pointer table by intializing rtlpr with the address of the function pointer table rt_link
+ */
+
+int init_AuD_realtime()
+{
+ rtlpr = &rt_link;
+ rtlpr->rt_version = rt_version;
+ aud_rt_hdr.state = 0;
+ aud_lx_tgid = 0;
+ return 0;
+}
+
+
+
+void cleanup_AuD_realtime(void)
+{
+
+ if (aud_rt_hdr.state == RT_INSTALLED)
+ rt_shutdown_realtime();
+ rtlpr = NULL;
+ if (RT_INIT_VERBOSE)
+ printkGen("%s shut down and cleaned up\n", AuD_REALTIME_NAME);
+}
+
+/*
+ * A free list of request elements is only needed for futex requests
+ * to make sure a request element for shutdown is always available a separate element
+ * check_notify_cmd is maintained separately
+ * For thread delegation the request element is built on the stack of the requesting thread
+ */
+
+struct lx_cmd *cptr;
+struct lx_cmd cmd_arr[NO_OF_FU_REQUESTS];
+
+struct lx_cmd check_notify_cmd = {
+ .type = CHECK_NOTIFY,
+};
+
+void init_lx_request_list()
+{
+ int i;
+
+ INIT_LIST_HEAD(&check_notify_cmd.req_link);
+ cptr = &cmd_arr[0];
+ INIT_LIST_HEAD(&aud_rt_hdr.free_list); // free list of futex delegation requests
+ for (i = 0; i < NO_OF_FU_REQUESTS ; i++, cptr++)
+ {
+ INIT_LIST_HEAD(&cptr->req_link);
+ list_add(&cptr->req_link, &aud_rt_hdr.free_list);
+ }
+}
+
+struct lx_cmd* get_lx_request(void)
+{
+ struct list_head *lp;
+
+ if (aud_rt_hdr.free_list.next == &aud_rt_hdr.free_list)
+ return NULL;
+ spin_lock_irq_hw(&aud_rt_hdr.to_lx_lock);
+ lp = aud_rt_hdr.free_list.next;
+ if (lp == &aud_rt_hdr.free_list)
+ lp = NULL;
+ else
+ list_del(lp);
+ spin_unlock_irq_hw(&aud_rt_hdr.to_lx_lock);
+ return (struct lx_cmd*)lp;
+}
+
+void free_lx_request(struct lx_cmd * req)
+{
+ spin_lock_irq_hw(&aud_rt_hdr.to_lx_lock);
+ list_add(&req->req_link, &aud_rt_hdr.free_list);
+ spin_unlock_irq_hw(&aud_rt_hdr.to_lx_lock);
+}
+
+void add_lx_request(struct lx_cmd* req)
+{
+ spin_lock_irq_hw(&aud_rt_hdr.to_lx_lock);
+ list_add_tail(&req->req_link, &aud_rt_hdr.to_lx_list);
+ spin_unlock_irq_hw(&aud_rt_hdr.to_lx_lock);
+ if (THREAD_IS_REALTIME)
+ ipipe_trigger_irq(ex_lx_irq);
+ else
+ up(&aud_rt_hdr.to_lx_sm); // activate migration daemon directly
+}
+
+
+void add_wake_up_request(struct proc_wait_queue *req)
+{
+ spin_lock_irq_hw(&aud_rt_hdr.to_lx_lock);
+ list_add_tail(&req->list, &aud_rt_hdr.wake_lx_list);
+ spin_unlock_irq_hw(&aud_rt_hdr.to_lx_lock);
+ ipipe_trigger_irq(wake_up_lx_irq);
+}
+
+/*
+ * For call execution in Linux or having a thread checking for an available message
+ * the wake_up_process can be done directly from ISR level
+ */
+
+void wake_up_lx_isr(unsigned irq, void * cookie)
+{
+ struct proc_wait_queue *req;
+ struct list_head *p;
+
+ if (list_empty(&aud_rt_hdr.wake_lx_list))
+ return;
+ spin_lock_irq_hw(&aud_rt_hdr.to_lx_lock);
+ p = aud_rt_hdr.wake_lx_list.next;
+ list_del(p);
+ spin_unlock_irq_hw(&aud_rt_hdr.to_lx_lock);
+ req = (struct proc_wait_queue *)p;
+ wake_up_process(req->task);
+}
+
+
+
+/*
+ * This Linux ISR is used to propagate actions to the linux domain. This ISR is for two IRQs
+ * -- waking up the write daemon for looking up the buffer
+ * -- waking up the do_execute_in_lx daemon
+ * both daemons get woken up via semaphores, so no request can get lost
+ */
+
+void to_lx_isr(unsigned irq, void * cookie)
+{
+ up((struct semaphore *)cookie);
+}
+
+/*
+ * This realtime ISR notfifies the realtime domain. It gets called whenever the Linux domain brings a
+ * thread into the runqueue of the realtime domain. Since the check for preemption is done in the ipipe
+ * layer, the isr can be a noop
+ */
+
+void to_rt_isr(unsigned irq, void * cookie)
+{
+}
+
+#ifdef CONFIG_SMP
+/*
+ * Reschedule call back. Nothing to do,
+ * all the work is done automatically when
+ * we return from the interrupt.
+ */
+fastcall void rtx_preemption_isr(struct pt_regs *regs)
+{
+ ack_APIC_irq();
+}
+#endif
+
+int rt_init_realtime(void)
+{
+#ifdef CONFIG_SMP
+ int new_cpu, old_cpu = smp_processor_id();
+
+ if (num_online_cpus() > 1)
+ {
+ rt_pin_irqs(); // Reserving CPU0 for RT IRQs
+
+ /* Pin the RT-process to CPU0. */
+ if (set_cpus_allowed(current, rt_cpu_mask) != 0)
+ printkGen("pinning the RT-process failed\n");
+
+ if (RT_INIT_VERBOSE)
+ if ((new_cpu = smp_processor_id()) != old_cpu)
+ printkGen("RT-process migrated from cpu=%d to cpu=%d\n", old_cpu, new_cpu);
+ }
+#endif
+
+ sema_init_rt(&aud_rt_hdr.rt_tl_sem, 1); // access to the realtime thread list
+ sema_init(&aud_rt_hdr.setup_sm, 0); // having the main thread waiting for completion of setup
+ sema_init(&aud_rt_hdr.to_rt_sm, 0); // for notification of the migration daemon
+ sema_init(&aud_rt_hdr.to_rt_op, 1); // for locking the migration action
+ sema_init(&aud_rt_hdr.to_lx_sm, 0);
+ sema_init(&aud_rt_hdr.write_sm, 1);
+ spin_lock_init(&aud_rt_hdr.to_lx_lock);
+ aud_rt_hdr.tgid_rt = 0;
+ aud_rt_hdr.to_rt_proc = NULL;
+ aud_rt_hdr.timer_daemon = NULL;
+ aud_rt_hdr.to_rt_daemon = NULL;
+ aud_rt_hdr.to_lx_daemon = NULL;
+ INIT_LIST_HEAD(&aud_rt_hdr.reg_list);
+ INIT_LIST_HEAD(&aud_rt_hdr.rt_tl);
+ INIT_LIST_HEAD(&aud_rt_hdr.to_lx_list); // queue may hold either migration or futex delegation requests
+ INIT_LIST_HEAD(&aud_rt_hdr.wake_lx_list);
+ rt_init_sched();
+ rt_init_futex();
+ init_lx_request_list(); // list of request elements is needed for futex execution
+ init_write_buffer(); // the buffer for writes to stdout and stderr
+ if (RT_INIT_VERBOSE)
+ printkGen("realtime system initialized\n");
+ rtx_preemption_handling = rt_noop_work; // IPI handling needs a function pointer before the RT domain is set up
+ return setup_aud_rt_domain();
+}
+
+
+
+
+/*
+ * Shutdown of the realtime system starts always from the Linux domain. A exit()call in the realtime domain
+ * is propagated to Linux. A exit() call in the Linux domain is intercepted to call this rt_shutdown_realtime
+ * function first. First it is made sure that
+ * - no new migration takes place by setting the state to RT_SHUTDOWN
+ * - no RT ISR for a hw interrupt will get called by calling set_execution_environment(0)
+ * From here the timeout task of the realtime domain is woken up, which in turn sends SIGKILL
+ * to all user realtime threads, which causes these threads to migrate to Linux. After all realtime threads are
+ * migrated, the timer daemon migrates to Linux and terminates. Afterwards Linux do_group_exit() processing continues
+ */
+
+void rt_shutdown_realtime(void)
+{
+ unsigned old_msg_count;
+
+#ifdef CONFIG_SMP
+ rt_unpin_irqs();
+#endif
+ down(&aud_rt_hdr.dev_sem);
+ if (aud_rt_hdr.state == RT_INSTALLED)
+ {
+ down(&aud_rt_hdr.to_rt_op); // tell the migrate_to_rt daemon to do a transition
+ aud_rt_hdr.to_rt_proc = NULL; // to the state RT_SHUTDOWN synchronized with
+ up(&aud_rt_hdr.to_rt_sm); // possible migrations and to terminate
+ old_msg_count = msg_count;
+ schedule_timeout(50); // to give the write thread a chance to flush it out
+ while (msg_count)
+ {
+ schedule_timeout(100);
+ if (msg_count == old_msg_count)
+ break; // no message in buffer anymore
+ old_msg_count = msg_count;
+ }
+
+ up(&aud_rt_hdr.write_sm); // write buffer read thread gets woken up it returns with -ENXIO
+ down(&aud_rt_hdr.setup_sm); // continues when timer daemon kills itself
+ destroy_aud_rt_domain();
+ }
+ rt_unregister_sync_clock(NULL); // sync clocks can only exist for the realtime process
+ aud_rt_hdr.state = 0; // now a new register_process and
+ aud_lx_tgid = 0; // probe_realtime may get issued again
+ aud_rt_hdr.timer_daemon = NULL;
+ up(&aud_rt_hdr.dev_sem);
+}
+
+
+/*
+ * When migrating back to Linux a user thread must join the thread group again
+ * The tgid link in the task structure is hashed. To avoid computing the queue head again
+ * we link it just to the list entry of the main thread, which is know not to migrate
+ * There are three different migration reasons
+ * Call execution in the Linux domain:
+ * The thread stays in the rt_pid_list. Therefore it stays a target for notification.
+ * Sending a signal or creating a new notification for that thread does no harm.
+ * Priority change:
+ * It can only take place if there are no notifications for that thread.
+ * The thread is taken out of the rt_pid_list upfront.
+ * Thread termination (either a rt_shutdown or exiting a thread):
+ * All notification channels for that thread are deleted upfront
+ * The thread is taken out of the rt_pid_list upfront.
+ */
+
+
+asmlinkage void execute_in_lx(void)
+{
+ struct proc_wait_queue req;
+
+ INIT_LIST_HEAD(&req.list);
+ req.task = current;
+ if (RT_MIGRATE_VERBOSE)
+ printkGen("wait to go to lx p=%p\n", current);
+ add_wake_up_request(&req);
+ __set_current_state(RT_TASK_UNINTERRUPTIBLE);
+ rt_schedule();
+ // now the thread executes in the Linux domain
+ ipipe_reenter_root (current, current->policy, current->rt_priority); // execute leaving half of the Linux schedule
+ if (current->tgid == aud_rt_hdr.tgid_rt) // check for user thread
+ { // put it back into Linux's tgid list
+ write_lock_irq(&tasklist_lock);
+ list_add_tail(¤t->pids[PIDTYPE_TGID].pid_list, &aud_rt_hdr.rt_proc->pids[PIDTYPE_TGID].pid_list);
+ current->tgid = aud_lx_tgid; // restore old tgid
+ write_unlock_irq(&tasklist_lock);
+ }
+}
+
+
+long do_rt_leave(void)
+{
+ down_rt(&aud_rt_hdr.rt_tl_sem);
+ list_del_init(¤t->rt_pid_list); // get it out of the realtime thread list.
+ up_rt(&aud_rt_hdr.rt_tl_sem); // no new notification for that thread can get created
+ rt_delete_event_notification(0); // in case there are notifications for that thread
+ rt_delete_timer_notification(); // remove them
+ execute_in_lx();
+ return 0;
+}
+
+
+/*
+ * This daemon either
+ * -- executes FUTEX_WAKE (and FUTEX_CMP_REQUEUE) actions or
+ * -- notifies during setup/shutdown
+ */
+
+int do_execute_in_lx(void *arg)
+{
+ struct lx_cmd *req;
+ struct list_head *p;
+ struct fu *fp;
+ struct sched_param sched_par;
+
+ sched_par.sched_priority = aud_rt_hdr.to_lx_prio;
+ sched_setscheduler(current, SCHED_FIFO, &sched_par);
+ if (RT_INIT_VERBOSE)
+ printkGen("to_lx_daemon_started pid: %d\n", current->pid);
+ do
+ {
+ down(&aud_rt_hdr.to_lx_sm);
+ if (list_empty(&aud_rt_hdr.to_lx_list))
+ continue;
+ spin_lock_irq_hw(&aud_rt_hdr.to_lx_lock);
+ p = aud_rt_hdr.to_lx_list.next;
+ list_del(p);
+ spin_unlock_irq_hw(&aud_rt_hdr.to_lx_lock);
+
+ req = (struct lx_cmd *)p;
+// if (RT_MIGRATE_VERBOSE)
+// printkGen("lx_daemon type=%#x p=%p\n", req->type, current);
+ switch (req->type) {
+ case CHECK_NOTIFY:
+ up(&aud_rt_hdr.setup_sm); // setup: main thread waits, exit: calling thread waits
+ if (aud_rt_hdr.state == RT_INSTALLED)
+ continue; // regular operation continues
+ if (RT_SHUTDOWN_VERBOSE)
+ printkGen("execute_in_lx daemon pid %d shuts down\n", current->pid);
+ current->exit_signal = -1;
+ return 0; // daemon shuts down itself
+ case EXEC_FUTEX_LX:
+ fp = &req->_req._fuop;
+ do_futex(fp->uaddr, fp->op, fp-> val, 0, fp->uaddr2, fp->val2, fp->val3);
+ free_lx_request(req); // recycle request element
+ continue;
+ default:
+ printkGen("wrong execute_in_lx type\n");
+ }
+
+ }
+ while(1);
+// atomic_dec(¤t->usage);
+ return 0;
+}
+
+
+/*
+ * Places the request, triggers the thread migration daemon, puts itself out of the runqueue by doing a schedule
+ * The migration daemon checks whether the thread is out of the runqueue. If ok, it calls the function
+ * rt_wake_up_thread()to get it into the runqueue of the realtime scheduler and triggers an iüipe interrupt for the realtime domain.
+ * For migrating kernel threads this function is called explicitly. For user threads this function is always called when leaving
+ * a system call in the Linux domain and the thread has TIF_NOTIFY_RESUME set.
+ * A realtime user thread must not stay a target for Linux signalling.
+ * -- to remove it from the tgid list, gets it out of Linux's thread list scanning
+ * -- to assign another tgid disables it being a target when creating a sigevent based notification
+ * Any change to the tgid link needs a rw lock of the the task list
+ */
+
+int fastcall migrate_to_rt(int mode)
+{
+ // if (RT_MIGRATE_VERBOSE) // m.n.
+// printkGen("wait for migrate (%p)...\n", current);
+ if (!AuD_REALTIME_PRIO(current))
+ {
+ printkGen("tried to migrate with priority %d\n", current->prio);
+ return -1; // can't migrate when prio too low
+ }
+#ifdef CONFIG_SMP
+ if (smp_processor_id())
+ { // force thread to run on cpu 0
+ if (set_cpus_allowed(current, rt_cpu_mask)!= 0)
+ printkGen("forcing thread pid: %d to run on cpu0 failed\n", current->pid);
+ }
+#endif /* CONFIG_SMP */
+ down(&aud_rt_hdr.to_rt_op); // serialize competing migrations
+ if ((aud_rt_hdr.state != RT_INSTALLED) && (mode != INITIAL_THREAD))
+ {
+ up(&aud_rt_hdr.to_rt_op);
+ return -1;
+ }
+ aud_rt_hdr.to_rt_proc = current; // put in requesting process
+ if (mode == USER_THREAD)
+ { // remove it from the Linux thread group
+ write_lock_irq(&tasklist_lock);
+ list_del_init(¤t->pids[PIDTYPE_TGID].pid_list); // out of Linux's thread list scanning
+ if (aud_rt_hdr.tgid_rt == 0) // first user thread to migrate
+ aud_rt_hdr.tgid_rt = current->pid; // opens a new thread group
+ current->tgid = aud_rt_hdr.tgid_rt; // joins the realtime thread group
+ write_unlock_irq(&tasklist_lock);
+ sigemptyset(¤t->real_blocked); // is used as ->blocked in the realtime domain
+ }
+ preempt_disable();
+ up(&aud_rt_hdr.to_rt_sm); // activate migration daemon
+ __set_current_state(TASK_UNINTERRUPTIBLE);
+ preempt_enable_no_resched();
+ schedule();
+ // from here it runs under control of the realtime scheduler
+ rt_enter_schedule(); // for unlocking the realtime runqueue
+ down_rt(&aud_rt_hdr.rt_tl_sem);
+ if ((mode != INITIAL_THREAD) && (rt_find_task_by_pid(current->pid) == NULL))
+ { // initial migration of a thread except the rt timer thread.
+ INIT_LIST_HEAD(¤t->rt_sigqueue_head);
+ INIT_LIST_HEAD(¤t->rt_pid_list);
+ list_add_tail(¤t->rt_pid_list, &aud_rt_hdr.rt_tl);
+ current->rt_timer_list_hdr = NULL; // a carrier thread refers to its timer list header
+ unlazy_fpu(current);
+ if (RT_INIT_VERBOSE)
+ printkGen("task %p pid %d prio %d added to rt_pid_list\n", current, current->pid, current->prio);
+ }
+ up_rt(&aud_rt_hdr.rt_tl_sem);
+ return 0; // up(&aud_rt_hdr.to_rt_op) is performed by the migration daemon
+}
+
+/*
+ * Execution loop of the migration daemon. The thread to migrate is specified in aud_rt_hdr.to_rt_proc
+ * It has to make sure, that the requesting client is really out of the runqueue of Linux.
+ * aud_rt_hdr.to_rt_proc == NULL indicates that the daemon has to be shut down
+ */
+
+int do_migrate_to_rt(void *arg)
+{
+ struct task_struct *tp;
+ struct sched_param sched_par;
+
+ sched_par.sched_priority = aud_rt_hdr.to_rt_prio;
+ sched_setscheduler(current, SCHED_FIFO, &sched_par);
+ if (RT_INIT_VERBOSE)
+ printkGen("migrate_to_rt daemon started pid: %d\n", current->pid);
+ do {
+ down(&aud_rt_hdr.to_rt_sm); // wait to get triggered by a client
+ if (!(tp = aud_rt_hdr.to_rt_proc)) // to_rt_proc == NULL indicates shutdown request
+ break;
+ while (tp->array)
+ { // process isn't out of the runqueue yet. Migration
+ __set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(POLL_TIME); // takes always place at one processor, so it is safe
+ } // to assume that execution proceeded til context switch
+ aud_rt_hdr.to_rt_proc = NULL;
+ if (RT_MIGRATE_VERBOSE)
+ printkGen("migrate thread: %p pid: %d\n", tp, tp->pid);
+ INIT_LIST_HEAD(&tp->run_list);
+ rt_wake_up_thread(tp); // it gets queued into the rt run queue
+ ipipe_trigger_irq(to_rt_irq);
+ up(&aud_rt_hdr.to_rt_op); // allow for next migration
+ }while(1);
+ aud_rt_hdr.state = RT_SHUTDOWN;
+ set_execution_environment(0); // all rt ISRs will get uninstalled and linux ISRs will be installed instead
+ rt_wake_up_thread(aud_rt_hdr.timer_daemon); // timer daemon migrates all realtime threads one by one to Linux
+ ipipe_trigger_irq(to_rt_irq); //
+ up(&aud_rt_hdr.to_rt_op); // make sure pending migration requests don't lead to blocking
+ if (RT_SHUTDOWN_VERBOSE)
+ printkGen("migrate_to_rt daemon pid %d shuts down\n", current->pid);
+ current->exit_signal = -1;
+ return 0;
+}
+
+
+/* This daemon migrates to realtime, it handles all internal timers of the realtime kernel.
+ * They are basically timeout timers for the futex(..., FUTEX_WAIT, ...) call.
+ * For further details look in rtimer.c
+ * Because that is the place where also the shutdown is completed, intialization and reset of the
+ * function pointer entries which link to the dynamically loaded realtime module
+ */
+
+int do_timer_rt(void *arg)
+{
+ struct sched_param sched_par;
+
+ sched_par.sched_priority = aud_rt_hdr.td_prio;
+ sched_setscheduler(current, SCHED_FIFO, &sched_par);
+ if (RT_INIT_VERBOSE)
+ printkGen("timer_daemon pid %d started in Linux domain\n", current->pid);
+ rtx_futex_wake_handling = rt_futex_wake_from_lx;
+ rtx_preemption_handling = rt_check_for_work;
+ rtx_settime_handling = rt_settime_from_lx;
+ rtx_wake_lx_handling = add_wake_up_request;
+ time_handling_rt(aud_config.no_of_timers.val, aud_config.no_of_headers.val, aud_config.no_of_sigq.val);
+ // it returns when either the realtime domain is shutdown
+ // or the realtime setup was not successfully finished
+ rtx_futex_wake_handling = NULL;
+ rtx_preemption_handling = rt_noop_work;
+ rtx_wake_lx_handling = NULL;
+ rtx_settime_handling = NULL;
+ aud_rt_hdr.tgid_rt = 0;
+ aud_rt_hdr.pid_wr = 0;
+ aud_rt_hdr.state = RT_HARD; // in case of a failed setup it is original register state
+ // in case of a shutdown it gets zeroed afterwards in rt_shutdown_realtime
+ add_lx_request(&check_notify_cmd); // activate migrate_to_lx daemon for suicide
+ if (RT_SHUTDOWN_VERBOSE)
+ printkGen("rt_timer daemon pid %d shuts down\n", current->pid);
+ current->exit_signal = -1;
+ return 0; // timer daemon thread shuts down
+}
+
+
+/*
+ * just for initial test, serves no other purpose
+ */
+
+int do_check_rt(void *arg)
+{
+ unsigned myCount = 0;
+ _INT64 timeout = 5000;
+ struct sched_param sched_par;
+
+ sched_par.sched_priority = aud_config.td_prio.val + 1;
+ sched_setscheduler(current, SCHED_FIFO, &sched_par);
+ if (RT_CHECK_VERBOSE)
+ printkGen("enter do_check_rt\n");
+ __set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(1);
+ if (RT_CHECK_VERBOSE)
+ printkGen("do_check_rt: timeout in Linux completed\n");
+ if (!migrate_to_rt(KERNEL_THREAD))
+ {
+ while (aud_rt_hdr.state != RT_SHUTDOWN) {
+ myCount++;
+ if (RT_CHECK_VERBOSE)
+ printkGen("loop do_check_rt in realtime cnt: %d)\n", myCount);
+ __set_current_state(RT_TASK_UNINTERRUPTIBLE);
+ rt_schedule_timeout(1, timeout);
+ if (timeout < 200000)
+ timeout += 5000;
+ }
+ execute_in_lx();
+ }
+ if (RT_SHUTDOWN_VERBOSE)
+ printkGen("do_check_rt shutdown\n");
+ current->exit_signal = -1;
+ return 0;
+}
+
+module_init (init_AuD_realtime);
+module_exit (cleanup_AuD_realtime);
+
diff -N -a -u -r linux-2.6.15.4/drivers/aud/audrealtime/rt_mqueue.c aud_linux/drivers/aud/audrealtime/rt_mqueue.c
--- linux-2.6.15.4/drivers/aud/audrealtime/rt_mqueue.c 1970-01-01 01:00:00.000000000 +0100
+++ aud_linux/drivers/aud/audrealtime/rt_mqueue.c 2007-04-10 20:49:27.000000000 +0200
@@ -0,0 +1,107 @@
+/*
+ * rtime/audrealtime/rt_mqueue.c
+ * Author: Stefan Assmann (S.Assmann AT gmx DOT de)
+ * Copyright (c) 2007 Siemens AG
+ * last change: 2007-01-29
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * This file contains the basic send/receive frontend functions of
+ * the POSIX message queues needed for the realtime domain
+ */
+
+
+#include "../include/rt_timer.h"
+#include <linux/mqueue.h>
+
+extern struct file* rt_fcheck_file_fd(int fd, int flags);
+extern void add_wake_up_request(struct proc_wait_queue *req);
+
+void rt_do_wakeup(struct proc_wait_queue *wait)
+{
+ rt_wake_up_thread(wait->task);
+ if (THREAD_IS_REALTIME) {
+ rt_check_preemption();
+ }
+ else {
+ ipipe_trigger_irq(to_rt_irq);
+ }
+}
+// rt_mq_sleep is called under lock and left under lock
+int rt_mq_sleep(struct mqueue_inode_info *info,
+ struct list_head *wait_list, long timeout)
+{
+ int flag;
+ signed long time;
+ struct proc_wait_queue wait;
+
+ flag = 0;
+ time = 0;
+
+ wait.do_wakeup = rt_do_wakeup;
+ wait.task = current;
+ list_add_tail(&wait.list, wait_list);
+ spin_unlock_irq_hw(&info->lock);
+
+ if (timeout != MAX_SCHEDULE_TIMEOUT)
+ flag = 1;
+ set_current_state(RT_TASK_UNINTERRUPTIBLE);
+ time = rt_schedule_timeout(flag, timeout);
+
+ spin_lock_irq_hw(&info->lock);
+ if (time == 0) {
+ if (!list_empty(&wait.list))
+ // in case it got woken up by time or by sig
+ list_del(&wait.list);
+ return -ETIMEDOUT;
+ }
+ return time;
+}
+
+asmlinkage long sys_rt_mq_timedsend(mqd_t mqdes, const char __user *u_msg_ptr,
+ size_t msg_len, unsigned int msg_prio,
+ const struct timespec __user *u_abs_timeout)
+{
+ int ret;
+ struct file *filp;
+
+ filp = rt_fcheck_file_fd(mqdes, 0);
+ if (unlikely(!filp)) {
+ ret = -EBADF;
+ goto out;
+ }
+
+ ret = timedsend_common(filp, u_msg_ptr, msg_len, msg_prio,
+ u_abs_timeout, rt_mq_sleep);
+out:
+ return ret;
+}
+
+asmlinkage ssize_t sys_rt_mq_timedreceive(mqd_t mqdes, char __user *u_msg_ptr,
+ size_t msg_len, unsigned int __user *u_msg_prio,
+ const struct timespec __user *u_abs_timeout)
+{
+ ssize_t ret;
+ struct file *filp;
+
+ filp = rt_fcheck_file_fd(mqdes, 0);
+ if (unlikely(!filp)) {
+ ret = -EBADF;
+ goto out;
+ }
+ ret = timedreceive_common(filp, u_msg_ptr, msg_len, u_msg_prio,
+ u_abs_timeout, rt_mq_sleep);
+out:
+ return ret;
+}
diff -N -a -u -r linux-2.6.15.4/drivers/aud/audrealtime/rt_timer.c aud_linux/drivers/aud/audrealtime/rt_timer.c
--- linux-2.6.15.4/drivers/aud/audrealtime/rt_timer.c 1970-01-01 01:00:00.000000000 +0100
+++ aud_linux/drivers/aud/audrealtime/rt_timer.c 2007-04-10 20:49:27.000000000 +0200
@@ -0,0 +1,1093 @@
+/*
+ * rtime/audrealtime/rt_timer.c
+ *
+ * 2007-19-01: Karl-Heinz.Krause@siemens.com
+ * Copyright (c) 2007 Siemens AG
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * This file contains all the common functions POSIX timers and the specific
+ * routines for CLOCK_REALTIME timers.The specific routines
+ * for the CLOCK_SYNC timers for the RT domain as well as the Linux domain are
+ * in file sync_timer.c
+ */
+#include "../include/rt_timer.h"
+
+struct task_struct * rt_check_sigevent(sigevent_t *);
+int rt_setup_notification(void **, int, struct sigevent *, struct notify *);
+struct task_struct * rt_find_task_by_pid(int);
+int rt_event_notification(struct task_struct *);
+void rt_mark_exit_pending(struct task_struct *);
+struct itimer * rt_thread_list_hdr_handling(struct rt_list_hdr *);
+int rt_timer_settime(struct posix_timer *, int, struct itimerspec *, struct itimerspec *);
+void rt_timer_gettime(struct posix_timer *, struct itimerspec *);
+int rt_timer_delete(struct posix_timer *);
+int rt_nsleep(int, struct timespec *, struct itimerspec *);
+int rt_clock_settime_in_lx(clockid_t, struct timespec *);
+int rt_clock_gettime(clockid_t, struct timespec *);
+int assoc_timer_with_rt_list(struct posix_timer *, sigevent_t *);
+void add_lx_request(struct lx_cmd*);
+int rt_init_sigqueue_pool(int);
+void rt_free_sigqueue_pool(void);
+extern int (*rt_subscribe_tick_ptr)(void);
+
+int rt_register_clock(clockid_t, struct rtg_clock *);
+int rt_dequeue_sigq(struct sigqueue *);
+void rt_sched_rr(void);
+
+long unsigned clock_getres_int(int);
+extern struct ipipe_domain aud_ipd;
+extern struct lx_cmd check_notify_cmd;
+
+u64 get_jiffies_64(void);
+
+struct timespec new_lx_time;
+
+extern struct timezone sys_tz;
+extern struct dom_hdr aud_rt_hdr;
+
+extern struct k_clock posix_clocks[];
+extern unsigned lockaddr;
+
+struct posix_timer_pool rcl = {
+ .available_timer = {&rcl.available_timer, &rcl.available_timer},
+ .created_timer = {&rcl.created_timer, &rcl.created_timer},
+ .available_list_hdr = {&rcl.available_list_hdr, &rcl.available_list_hdr},
+ .used_timer = 0,
+ .bitmap = NULL,
+ .tmr_map = NULL
+ };
+
+
+/* The CLOCK_REALTIME interrupt operates on list headers of type struct rt_list_hdr.
+ * The interrupt sequence always first handles the isr_list_hdr completely at the ISR-level.
+ * Afterwards it (pre)checks the queued thread_list_headers. This is a very fast check.
+ * If a timer or the thread_list_hdr needs handling, the corresponding thread will get activated.
+ * The complete handling of the thread_list_header itself will then take place at the thread level.
+ * This allows to maintain the best balance between realtime and performance
+ */
+struct rt_list_hdr isr_list_hdr;
+struct rt_list_hdr tint_list_hdr; // thread_list header for internal (timeout) functions
+
+extern spinlock_t ptimer_lock;
+
+struct rtg_clock rt_clock = {
+ .res = 1000000,
+ .clock_val = 0,
+ .offset = 0,
+ .clock_set = rt_clock_settime_in_lx,
+ .clock_get = rt_clock_gettime,
+ .nsleep = NULL,
+ .timer_set = rt_timer_settime,
+ .timer_del = NULL,
+ .timer_get = rt_timer_gettime,
+ .timer_setup = assoc_timer_with_rt_list
+ };
+
+struct rtg_clock *rt_clock_arr[MAX_CLOCKS];
+/*
+ * This operation is called under the blocking lock rcl.lock
+ */
+
+struct posix_timer* get_new_timer(void)
+{
+ struct posix_timer *tmr = NULL;
+
+ if (!list_empty(&rcl.available_timer))
+ {
+ tmr = (struct posix_timer *)rcl.available_timer.next;
+ list_del_init(&tmr->it_link);
+ tmr->rt_notify.thread = NULL;
+ tmr->rt_notify.alt_thread = NULL;
+ tmr->it_state = 0;
+ rcl.used_timer++;
+ }
+ return(tmr);
+}
+
+/*
+ * It may be called either from sys_rt_timer_delete(), rt_delete_notification() or sys_rt_timer_create()
+ */
+
+int rt_timer_delete(struct posix_timer *tmr)
+{
+ timer_t timerid;
+ int no_of_bitword, bit_mask;
+
+ down_rt(&rcl.sem);
+ timerid = tmr->it_id;
+ *(rcl.tmr_map + (timerid & 0xffff)) = NULL;
+ no_of_bitword = (timerid & 0xffff) >> 5;
+ bit_mask = ~(0x1 <<timerid & 0x1f);
+ *(rcl.bitmap + no_of_bitword) &= bit_mask;
+ spin_lock_irq_hw(&ptimer_lock);
+ list_del_init(&tmr->itmr.it_link); // remove it if in active list
+ tmr->it_state = RT_TIMER_DELETED;
+ tmr->itmr.flags = 0;
+ spin_unlock_irq_hw(&ptimer_lock);
+ list_del_init(&tmr->it_link); // remove from created list
+ list_add(&tmr->it_link, &rcl.available_timer); // recycle it in available list
+ rt_dequeue_sigq (&tmr->rt_notify.sigq); // in case it is still queued
+ rcl.used_timer--;
+ up_rt(&rcl.sem);
+ return(0);
+}
+
+/*
+ * checks whether the clock with the given clockid exists and returns the pointer to the clock structure
+ */
+
+static INLINE struct rtg_clock * rt_get_clock(clockid_t clockid)
+{
+ if ((clockid >= MAX_CLOCKS) || (clockid < 0))
+ return NULL;
+ return(rt_clock_arr[clockid]);
+}
+
+/*
+ * checks whether the timer with the given timerid exists for that process and returns the pointer to it
+ */
+
+INLINE struct posix_timer* rt_get_timer(timer_t timerid)
+{
+ struct posix_timer *tmr;
+
+ if ((timerid & 0xffff) > rcl.max_timer)
+ return(NULL);
+ if ((tmr = (struct posix_timer*)*(rcl.tmr_map +(timerid & 0xffff))) != NULL)
+ if ((tmr->it_id == timerid) && (current->tgid == tmr->rt_notify.thread->tgid))
+ return(tmr);
+ return(NULL);
+}
+
+/* insert a CLOCK_REALTIME timer into a list_hdr structure. This routine must be called under lock
+ */
+
+INLINE int make_timer_active(struct itimer *itmr)
+{
+ struct rt_list_hdr *hdr;
+ int ix;
+
+ hdr = itmr->lhdr;
+ ix = (int) itmr->fire.activation_time;
+ if((itmr->fire.activation_time - hdr->clock_val) <= RT_L1_MASK)
+ list_add_tail(&itmr->it_link, &hdr->l1_list[ix & RT_L1_MASK]);
+ else
+ {
+ if((itmr->fire.activation_time - hdr->clock_val) <= RT_L1L2_MASK)
+ list_add_tail(&itmr->it_link, &hdr->l2_list[(ix >> RT_L1_BITS) & RT_L2_MASK]);
+ else
+ list_add_tail(&itmr->it_link, &hdr->overflow_list);
+ }
+ return(0);
+};
+
+
+/* checks the L2 or overflow list for entries which may migrate to a list closer to activation
+ * this operation must not be called under lock
+ */
+
+void reorder_timer_list(struct rt_list_hdr *hdr)
+{
+ struct list_head *lp;
+ struct list_head tmp;
+ int mod_clock_val;
+ int flag;
+
+ INIT_LIST_HEAD(&tmp);
+ mod_clock_val = (int)hdr->clock_val & RT_L1L2_MASK;
+ spin_lock_irqsave_hw(&ptimer_lock, flag);
+ if (mod_clock_val == 0)
+ list_splice_init(&hdr->overflow_list, &tmp);
+ list_splice_init(&hdr->l2_list[mod_clock_val >> RT_L1_BITS], &tmp);
+ for (lp = tmp.next; lp != &tmp; lp = tmp.next)
+ {
+ list_del_init(lp);
+ make_timer_active((struct itimer*)lp);
+ spin_unlock_irqrestore_hw(&ptimer_lock, flag);
+ spin_lock_irqsave_hw(&ptimer_lock, flag);
+ }
+ spin_unlock_irqrestore_hw(&ptimer_lock, flag);
+}
+
+/*
+ * copy a user time to the internal 64 value based on realtime clock
+ * (used for timeouts a.s.o.)
+ * returns either a negative error value or zero
+ */
+long copy_conv_to_internal(_INT64 *itr, struct timespec *uvalue)
+{
+ struct timespec value;
+ int error;
+
+ if ((error = copy_from_user(&value, uvalue, sizeof(struct timespec))))
+ return (error);
+ return(convert_to_internal(rt_clock.res, itr, &value));
+}
+
+
+/*
+ * copy the internal 64 value based on realtime clock to a user time
+ * (used for timeouts a.s.o.)
+ * return value negative: error
+ * 0 or positve: correct convertion
+ */
+long copy_conv_to_external(_INT64 *itr, struct timespec *uvalue)
+{
+ struct timespec value;
+
+ convert_to_external(rt_clock.res, itr, &value);
+ return(copy_to_user(uvalue, &value, sizeof(struct timespec)));
+}
+
+
+/* for internal nanosleep or timeout timers in the real time domain.
+ * the field id kann be used for an arbitrary id. It can be retrieved again as tmr->it_id
+ */
+
+void setup_internal_timer(struct itimer *itmr, _INT64 value, int fastcall (*timer_action) (void *))
+{
+
+ itmr->it_incr = 0;
+ itmr->timer_action = timer_action;
+ itmr->action_par = (void*)current;
+ itmr->lhdr = &tint_list_hdr; // insert timer into the list hdr for timeouts
+ spin_lock_irq_hw(&ptimer_lock);
+ itmr->fire.activation_time = value + rt_clock.clock_val; // only relative times may get specified
+ make_timer_active(itmr);
+ spin_unlock_irq_hw(&ptimer_lock);
+ return;
+}
+
+_INT64 delete_internal_timer(struct itimer *itmr)
+{
+ _INT64 remaining_time = 0;
+
+ spin_lock_irq_hw(&ptimer_lock);
+ list_del_init(&itmr->it_link); // remove if still in active list
+ spin_unlock_irq_hw(&ptimer_lock);
+ remaining_time = itmr->fire.activation_time - rt_clock.clock_val;
+ if (remaining_time < 0)
+ remaining_time = 0;
+ return (remaining_time);
+}
+
+
+void init_rt_list(struct rt_list_hdr *lhdr)
+{
+ int i;
+
+ INIT_LIST_HEAD(&lhdr->hdr_link);
+ INIT_LIST_HEAD(&lhdr->overflow_list);
+ for (i = 0; i < RT_L1_SIZE; i ++)
+ INIT_LIST_HEAD(&lhdr->l1_list[i]);
+ for (i = 0; i < RT_L2_SIZE; i ++)
+ INIT_LIST_HEAD(&lhdr->l2_list[i]);
+ lhdr->run_cnt = 0;
+ lhdr->notification = (void*)rt_send_sigqueue;
+ lhdr->notification_par = &lhdr->rt_notify;
+ lhdr->rt_notify.sigq.info.si_code = SI_LHDR;
+ lhdr->rt_notify.sigq.info.si_signo = SIGTIMER;
+ lhdr->rt_notify.sigq.info.si_overrun = 0;
+ lhdr->rt_notify.sigq.flags = SIGQUEUE_PREALLOC;
+}
+
+
+/*
+ * Timer handling is based on list_hdr.
+ * -- for signalling type SIGEV_THREAD_SV the isr_list_hdr is statically assigned
+ * -- for internal timers the tint_list_hdr is also statically assigned
+ * -- for signalling type SIGEV_SIGNAL_SV (handler) a list_hdr is dynamically assigned
+ * The isr_list_hdr is directly managed at the isr level
+ * Both other types are managed at thread level, the timer daemon and the corresponding carrier threads
+ * This scheme of list headers allows for best possible realtime behavior of time critical user threads
+ * The entire operation is called under aud_rt_hdr.rt_tl_sem lock
+ */
+
+int assoc_timer_with_rt_list (struct posix_timer *tmr, sigevent_t *rt_sig)
+{
+ struct list_head* lh;
+ struct rt_list_hdr *hdp;
+ struct task_struct *process;
+
+ tmr->itmr.lhdr = &isr_list_hdr; // only SIGEV_SIGNAL_SV timers are handled at ISR level
+ if (rt_sig->sigev_notify != SIGEV_THREAD_ID)
+ return (0);
+ if ((process = rt_find_task_by_pid(rt_sig->sigev_notify_thread_id)) == NULL)
+ return -EINVAL;
+ for (lh = &tint_list_hdr.hdr_link; lh->next != &tint_list_hdr.hdr_link; lh = lh->next)
+ {
+ hdp = (struct rt_list_hdr *)lh->next;
+ if (hdp->rt_notify.thread == process){
+ tmr->itmr.lhdr = hdp; // found matching rt_list header
+ return(0);
+ }
+ }
+ if (list_empty(&rcl.available_list_hdr)) // check for available list headers
+ return -EAGAIN;
+ hdp = (struct rt_list_hdr *)rcl.available_list_hdr.next;
+ list_del_init(rcl.available_list_hdr.next);
+ hdp->rt_notify.thread = process;
+ process->rt_timer_list_hdr = hdp; // indicator for a thread being a carrier thread (different handling of sigwait)
+ tmr->itmr.lhdr = hdp;
+ spin_lock_irq_hw(&ptimer_lock);
+ hdp->clock_val = rt_clock.clock_val;
+ list_add_tail(&hdp->hdr_link, &tint_list_hdr.hdr_link);
+ spin_unlock_irq_hw(&ptimer_lock);
+ return(0);
+}
+
+
+
+/* For fast allocation of a timer id a bit list is maintained. The bit number serves as the index in an array of pointers
+ to timers. The final timerid is composed of the bit number(lob) and a counter value (hob)
+ Because the bitlist is handled in entities of 32 bits, lock time stays short enough also for a larger number of timers
+*/
+
+asmlinkage long sys_rt_timer_create(clockid_t clockid, sigevent_t *sigevent_ptr, timer_t *created_timer_id)
+{
+ struct posix_timer *tmr = NULL;
+ struct itimer *itmr;
+ struct notify *npr;
+ sigevent_t rt_sig;
+ int error = -EINVAL;
+ int i;
+ unsigned bw, *bwp;
+ timer_t timerid;
+ struct rtg_clock *clock;
+ unsigned mask = 0x1;
+
+ if (RT_TIMER_VERBOSE)
+ printkGen("sys_rt_timer_create (%#x)\n", (unsigned int)clockid);
+
+ if ((clock = rt_get_clock(clockid)) == NULL)
+ return -EINVAL;
+ if (!sigevent_ptr)
+ return -EINVAL;
+ if (copy_from_user(&rt_sig, sigevent_ptr, sizeof(sigevent_t)))
+ return -EFAULT;
+ bwp = rcl.bitmap;
+ down_rt(&rcl.sem);
+ for (i = 0; i < rcl.max_timer; i += 32) // find a free slot in the table
+ { // scan of the bitlist
+ if ((bw = *bwp) == -1) // all bits set
+ {
+ bwp++; // next word
+ continue;
+ }
+ for(; (bw & mask) != 0; i++) // may be optimized by assembly programming
+ mask <<= 1; // find first bit set instruction
+ *bwp |= mask;
+ break;
+ }
+ timerid = (((rcl.id_count++ & 0xffff) << 16) | i);
+ if ((i < rcl.max_timer)&& (*(rcl.tmr_map + i) == NULL))
+ tmr = get_new_timer();
+ up_rt(&rcl.sem);
+ if (!tmr)
+ return -EAGAIN;
+ if((error = copy_to_user(created_timer_id, &timerid, sizeof(timer_t))))
+ return error;
+ tmr->it_clock = clockid;
+ itmr = &tmr->itmr;
+ itmr->lhdr = NULL;
+ error = -EINVAL;
+ npr = &tmr->rt_notify;
+
+ // creating a new notification path must be atomic with respect to
+ // adding/deleting threads from the realtime thread list
+ down_rt(&aud_rt_hdr.rt_tl_sem);
+ if ((npr->thread = rt_check_sigevent(&rt_sig))) // good sigevent structure ?
+ {
+ if (rt_setup_notification((void**)&itmr->timer_action, timerid, &rt_sig, npr)== 0)
+ if (clock->timer_setup((struct posix_timer *)tmr, &rt_sig) == 0)
+ {
+ list_add((struct list_head *)tmr, &rcl.created_timer); // now the notification path can be found
+ tmr->it_id = timerid;
+ *(rcl.tmr_map + i) = tmr; // now the timer can be reached
+ up_rt(&aud_rt_hdr.rt_tl_sem);
+ return (0);
+ }
+ }
+ up_rt(&aud_rt_hdr.rt_tl_sem);
+ rt_timer_delete(tmr);
+ return error;
+
+//
+}
+
+
+void rt_timer_gettime(struct posix_timer *tmr, struct itimerspec *value)
+{
+ _INT64 remaining_time, period;
+
+ struct itimer *itmr = &tmr->itmr;
+
+ if (RT_TIMER_VERBOSE)
+ printkGen("sys_rt_timer_gettime (%#x)\n", (unsigned int)tmr->it_id);
+ period = itmr->it_incr;
+ convert_to_external(rt_clock.res, &period, &value->it_interval);
+ spin_lock_irq_hw(&ptimer_lock);
+ if (list_empty(&itmr->it_link))
+ remaining_time = 0; // timer has already expired
+ else
+ remaining_time = itmr->fire.activation_time - rt_clock.clock_val;
+ spin_unlock_irq_hw(&ptimer_lock);
+ convert_to_external(rt_clock.res, &remaining_time, &value->it_value);
+ return;
+}
+
+asmlinkage long sys_rt_timer_gettime(timer_t timerid, struct itimerspec *uvalue)
+{
+ struct posix_timer *tmr;
+ struct itimerspec rtn;
+
+ if ((tmr = rt_get_timer(timerid)) == NULL)
+ return -EINVAL;
+ rt_clock_arr[tmr->it_clock]->timer_get(tmr, &rtn);
+ if (uvalue)
+ return(copy_to_user(uvalue, &rtn, sizeof(struct itimerspec)));
+ return(0);
+}
+
+
+int rt_timer_settime(struct posix_timer *tmr, int flags, struct itimerspec *value, struct itimerspec *ovalue)
+{
+
+ _INT64 it_period, it_delay, clock_val;
+ struct itimer *itmr = &tmr->itmr;
+ long error;
+
+ if (RT_TIMER_VERBOSE)
+ printkGen("rt_timer_settime (%d)\n", (unsigned int)tmr->it_id);
+
+ if (ovalue != NULL)
+ rt_timer_gettime(tmr, ovalue); // read back old value
+ if ((error = convert_to_internal(rt_clock.res, &it_period, &value->it_interval)) < 0)
+ return(error);
+ if ((error = convert_to_internal(rt_clock.res, &it_delay, &value->it_value)) < 0)
+ return(error);
+ spin_lock_irq_hw(&ptimer_lock);
+ // Between getting the pointer and locking a delete may have taken place, therefore we check again inside the lock
+ if (!(tmr->it_state & RT_TIMER_DELETED))
+ {
+ list_del_init(&itmr->it_link); // remove if in some active listlist
+ if (!(list_empty(&tmr->rt_notify.sigq.list))) // if sig is queued, remove it
+ rt_dequeue_sigq(&tmr->rt_notify.sigq); // POSIX allows for cutting corners
+ list_del_init(&tmr->rt_notify.sigq.list);
+ clock_val = rt_clock.clock_val;
+ itmr->it_incr = (long unsigned)it_period;
+ if (!(flags & TIMER_ABSTIME))
+ itmr->fire.activation_time = it_delay + clock_val;
+ else
+ {
+ it_delay -= rt_clock.offset;
+ if (clock_val >= it_delay)
+ it_delay = clock_val + 1;
+ itmr->fire.activation_time = it_delay;
+ tmr->insert_offset = rt_clock.offset;
+ }
+ itmr->flags = flags;
+ if ((it_delay) && (tmr->rt_notify.sigev_notify != SIGEV_NONE))
+ make_timer_active(itmr); // only if timer is not disarmed
+ }
+ else
+ error = -EINVAL;
+ spin_unlock_irq_hw(&ptimer_lock);
+ return(error);
+}
+
+
+
+asmlinkage long sys_rt_timer_settime(timer_t timerid, int flags, struct itimerspec *uvalue, struct itimerspec *ovalue)
+{
+ struct posix_timer *tmr;
+
+ struct itimerspec new_spec, old_spec;
+ int error = 0;
+ struct itimerspec *rtn = ovalue ? &old_spec : NULL;
+
+ if (!uvalue)
+ return -EINVAL;
+ if (copy_from_user(&new_spec, uvalue, sizeof (struct itimerspec))) return -EFAULT;
+ if (!(tmr = rt_get_timer(timerid)))
+ return -EINVAL;
+ tmr->it_state = 0; // reset for A&D timeliness supervision
+ if ((error = rt_clock_arr[tmr->it_clock]->timer_set(tmr, flags, &new_spec, rtn)))
+ return (error);
+ if (rtn)
+ return(copy_to_user(ovalue, &old_spec, sizeof(struct itimerspec)));
+ return (0);
+}
+
+
+asmlinkage long sys_rt_timer_delete(timer_t timerid)
+{
+ struct posix_timer *tmr;
+
+ if (RT_TIMER_VERBOSE)
+ printkGen("sys_rt_timer_delete (%d)\n", (unsigned int)timerid);
+
+ if ((tmr = rt_get_timer(timerid)) == NULL)
+ return -EINVAL;
+ down_rt(&aud_rt_hdr.rt_tl_sem); // needs to be synchronized via thread_list_sem because checking/removing
+ list_del_init((struct list_head *)tmr); // of existing notifications needs this list and this must be synchronized
+ up_rt(&aud_rt_hdr.rt_tl_sem); // with inserting/removing threads from the realtime thread list
+ rt_timer_delete(tmr);
+ return 0;
+}
+
+
+asmlinkage long sys_rt_clock_settime(clockid_t clockid, struct timespec *value)
+{
+ struct rtg_clock *clock;
+ struct timespec new_spec;
+
+ if (!(clock = rt_get_clock(clockid)))
+ return -EINVAL;
+ if (copy_from_user(&new_spec, value, sizeof (struct timespec))) return -EFAULT;
+ if (clock->clock_set)
+ return (clock->clock_set(clockid, value));
+ return -EPERM;
+}
+
+int rt_clock_settime_in_lx(clockid_t clockid, struct timespec *tp)
+{
+ execute_in_lx();
+ return 0;
+}
+
+int rt_clock_settime(void)
+{
+ _INT64 timeval;
+ int error;
+ struct posix_timer *tmr;
+ struct list_head *lp;
+ struct timespec tp;
+
+ if (RT_TIMER_VERBOSE)
+ printkGen("rt_clock_settime \n");
+
+ spin_lock_irq_hw(&ptimer_lock);
+ tp = new_lx_time;
+ new_lx_time.tv_nsec = -1;
+ spin_unlock_irq_hw(&ptimer_lock);
+ if ((error = convert_to_internal(rt_clock.res, &timeval, &tp)) < 0)
+ return(error);
+ rt_clock.offset = timeval - rt_clock.clock_val;
+/*
+ * All abs_timers need to get adjusted. There may be also entries in the queue which are not
+ * active TIMER_ABSTIMER timers anymore. They get just removed from the queue.
+ * The handling of the it_link queue with an unkown number of entries is only protected by the
+ * rcl.sem semaphore, since all realtime critical functions never deal with the it_link queue.
+ * There is no window, since a new element which is added during the scan is already based
+ * on the new offset time
+ */
+ down_rt(&rcl.sem);
+ for (lp = rcl.created_timer.next; lp != &rcl.created_timer; lp = lp->next)
+ {
+ tmr = list_entry(lp, struct posix_timer, it_link);
+ if ((tmr->itmr.flags & TIMER_ABSTIME) && (rt_clock.offset - tmr->insert_offset))
+ {
+ spin_lock_irq_hw(&ptimer_lock);
+ list_del_init(&tmr->itmr.it_link);
+ tmr->itmr.fire.activation_time -= (rt_clock.offset - tmr->insert_offset);
+ tmr->insert_offset = rt_clock.offset;
+ if (tmr->itmr.fire.activation_time <= rt_clock.clock_val)
+ tmr->itmr.fire.activation_time = rt_clock.clock_val + 1;
+ make_timer_active(&tmr->itmr);
+ spin_unlock_irq_hw(&ptimer_lock);
+ }
+ }
+ up_rt(&rcl.sem);
+ return (0);
+};
+
+
+/*
+ * This routine is executed in the Linux domain. It gets called from the hook in posix-timers.c
+ */
+
+void rt_settime_from_lx(struct timespec *new_spec)
+{
+ new_lx_time = *new_spec;
+}
+
+
+asmlinkage long sys_rt_clock_gettime(clockid_t clockid, struct timespec *value)
+{
+ struct rtg_clock *clock;
+ struct timespec clock_val;
+
+ if (!(clock = rt_get_clock(clockid)))
+ return -EINVAL;
+ clock->clock_get(clockid, &clock_val);
+ return(copy_to_user(value, &clock_val, sizeof(struct timespec)));
+}
+
+
+
+// get value in kernelspace
+long rt_clock_gettime_internal(struct timespec *value)
+{
+ _INT64 real_time;
+
+ real_time = rt_clock.clock_val + rt_clock.offset;
+ return(convert_to_external(rt_clock.res, &real_time, value));
+}
+
+
+int rt_clock_gettime(clockid_t clockid, struct timespec *value)
+{
+
+ struct timespec time_val;
+
+ rt_clock_gettime_internal(&time_val);
+ *value = time_val;
+ if (RT_TIMER_VERBOSE)
+ printkGen("rt_clock_gettime \n");
+ return 0;
+};
+
+asmlinkage long sys_rt_clock_getres(clockid_t clockid, struct timespec *uvalue)
+{
+ struct rtg_clock *clock;
+ struct timespec value;
+
+ if (RT_TIMER_VERBOSE)
+ printkGen("sys_rt_clock_getres (%#x)\n", (unsigned int)clockid);
+
+ if (!(clock = rt_get_clock(clockid)))
+ return -EINVAL;
+ value.tv_nsec = clock->res;
+ return(copy_to_user(uvalue, &value, sizeof(struct timespec)));
+}
+
+asmlinkage long sys_rt_nanosleep(struct timespec *rqtp, struct timespec *rmtp)
+{
+ long long expire;
+ long ret;
+
+ if ((ret = copy_conv_to_internal(&expire, rqtp)) < 0)
+ return(ret);
+ if (expire == 0) // no wait time
+ return(0);
+ current->state = RT_TASK_UNINTERRUPTIBLE;
+ expire = rt_schedule_timeout(1, expire);
+ if (expire) {
+ if (rmtp) {
+ if (copy_conv_to_external(&expire, rmtp))
+ return -EFAULT;
+ }
+ }
+ return 0;
+}
+
+asmlinkage long sys_rt_gettimeofday(struct timeval __user *tv, struct timezone __user *tz)
+{
+ struct timespec tval;
+
+ if (likely(tv != NULL)) {
+ rt_clock_gettime_internal(&tval);
+ tval.tv_nsec /= 1000;
+ if (copy_to_user(tv, &tval, sizeof(struct timeval)))
+ return -EFAULT;
+ }
+ if (unlikely(tz != NULL)) {
+ if (copy_to_user(tz, &sys_tz, sizeof(struct timezone)))
+ return -EFAULT;
+ }
+ return 0;
+}
+
+
+
+/*
+ * This routine gets called when "change priority" call would cause a migration to Linux
+ * since only a thread which is not a notification target is allowed to migrate
+ * This routine is called under rt_tl_sem lock
+ */
+
+int rt_notification(struct task_struct *p)
+{
+ struct list_head *tp;
+ struct posix_timer *tmr;
+ int ret;
+
+ for (tp = rcl.created_timer.next; tp != &rcl.created_timer; tp = tp->next)
+ {
+ tmr = (struct posix_timer*)tp;
+ if ((tmr->rt_notify.thread == p) || (tmr->rt_notify.alt_thread == p))
+ return 1;
+ }
+ ret = rt_event_notification(p);
+ return (ret);
+}
+
+
+
+/*
+ * deletes all timer based notifications to the current thread .
+ * In addition if the current thread is a carrier thread, the associated list_hdr gets deleted.
+ * This operation must be called with the aud_rt_hdr.rt_tl_sem hold. Thread gets out of the rt_thread_list
+ * before releasing aud_rt_hdr.rt_tl_sem, thus no notification for that thread can get created
+ */
+
+void rt_delete_timer_notification(void)
+{
+ struct list_head *tp;
+ struct posix_timer *tmr;
+
+ for (tp = rcl.created_timer.next; tp != &rcl.created_timer;)
+ {
+ tmr = (struct posix_timer*)tp;
+ tp = tp->next;
+ if ((tmr->rt_notify.thread == current) || (tmr->rt_notify.alt_thread == current))
+ rt_timer_delete(tmr);
+ }
+ if (current->rt_timer_list_hdr) // does a carrier thread get deleted ?
+ { // then return the associated list hdr
+ tp = (struct list_head*) current->rt_timer_list_hdr;
+ list_del_init(tp);
+ list_add_tail(tp, &rcl.available_list_hdr);
+ }
+ return;
+}
+
+
+/* This routine executes at ISR level. It checks all rt_list_headers for timers ready to fire. Timers in the isr_list_hdr
+ * get handled immediately. If a timer in a thread_list_hdr is ready to fire, then the corresponding thread is woken up and
+ * scanning of the rt_list_headers continues at the ISR-level.
+ * A thread_list_hdr is then handled by the thread woken up.
+ */
+//#define SYNC_CLOCK_INTR_DIAG
+void rt_clock_isr(unsigned irq, void * cookie)
+{
+ struct list_head *head, *list, *hp;
+ struct itimer *itmr;
+ struct rt_list_hdr *hdr;
+ int mod_clock_val;
+
+ if (rt_subscribe_tick_ptr)
+ rt_subscribe_tick_ptr();
+ if ((THREAD_IS_REALTIME) && (current->policy == SCHED_RR) && !--current->time_slice) {
+ current->time_slice = RT_TIME_SLICE;
+ rt_sched_rr();
+ }
+ rt_clock.clock_val += 1;
+ isr_list_hdr.clock_val += 1;
+ mod_clock_val = (int)rt_clock.clock_val & RT_L1_MASK;
+ head = &tint_list_hdr.hdr_link;
+ if (!mod_clock_val)
+ { // reordering of the timer lists needs to be done
+ reorder_timer_list(&isr_list_hdr); // for the isr_list_hdr at the isr level
+ hp = head;
+ do // for all other list_hdr the handling thread has
+ { // to be woken up
+ hdr = (struct rt_list_hdr *)hp;
+ hdr->run_cnt += 1; // in a smp system this must be done atomically
+ if (hdr->run_cnt == 1)
+ {
+ hdr->clock_val = rt_clock.clock_val;
+ hdr->notification(hdr->notification_par);
+ }
+ hp = hp->next;
+ } while(head != hp);
+ }
+ else
+ { // check whether a timer expired and a handling thread needs woken up
+ hp = head;
+ do
+ {
+ hdr = (struct rt_list_hdr *)hp;
+ if (!(list_empty(&hdr->l1_list[mod_clock_val])))
+ { // a timer has expired
+ hdr->run_cnt += 1; // in a smp system this must be done atomically
+ if (hdr->run_cnt == 1)
+ {
+ hdr->clock_val= rt_clock.clock_val;
+ hdr->notification(hdr->notification_par); //
+ }
+ }
+ else
+ {
+ if (hdr->run_cnt == 0)
+ hdr->clock_val= rt_clock.clock_val; // keep the clock synchronous
+ }
+ hp = hp->next;
+ }while(head != hp);
+ }
+ list = &isr_list_hdr.l1_list[mod_clock_val]; // now handle the isr_list_hdr directly
+ while (list != list->next)
+ {
+ itmr = (struct itimer *)list->next;
+ list_del_init(&itmr->it_link);
+ (itmr->timer_action(itmr->action_par));
+ itmr->flags = 0; // can't be absolute time anymore
+ if (itmr->it_incr == 0)
+ continue;
+ itmr->fire.activation_time += itmr->it_incr;
+ make_timer_active(itmr); // in a smp system this must be done under lock
+ }
+}
+
+
+/*
+ * This routine handles a rt_list_hdr at the thread level. It has to be called under lock
+ */
+
+struct itimer * rt_thread_list_hdr_handling(struct rt_list_hdr *hdr)
+{
+ struct list_head *list;
+ struct itimer *itmr;
+ int mod_clock_val;
+
+next_run:
+ if ((hdr->run_cnt) == 0)
+ return (NULL);
+ mod_clock_val = (int)(hdr->clock_val) & RT_L1_MASK;
+ if (!mod_clock_val)
+ {
+ spin_unlock_irq_hw(&ptimer_lock);
+ reorder_timer_list(hdr); // must not be called under lock
+ spin_lock_irq_hw(&ptimer_lock);
+ }
+ list = &hdr->l1_list[mod_clock_val];
+ if (list == list->next)
+ { // no timer has expired
+ if ((hdr->run_cnt) == 1)
+ return (NULL);
+ hdr->run_cnt--;
+ hdr->clock_val += 1; // another clock interrupt is still to be handled
+ goto next_run;
+ }
+ itmr = (struct itimer *)list->next;
+ list_del_init(&itmr->it_link);
+ itmr->flags = 0; // can't be absolute time anymore
+ if (itmr->it_incr != 0)
+ {
+ itmr->fire.activation_time += itmr->it_incr;
+ make_timer_active(itmr); // never absolute
+ }
+ return(itmr);
+}
+
+
+/*
+ * This routine installs all the necessary infrastructure for posix timers, clock_sync drivers in the RT-Domain.
+ * This routine is executed in the Linux domain, by the thread for handling timeouts of the realtime
+ * domain while this thread still executes in the Linux domain.
+ */
+
+int rt_init_timer(int no_posix_timer, int no_of_list_hdr)
+{
+ int i, size;
+ struct posix_timer *tmr;
+ struct rt_list_hdr *hdr;
+
+ INIT_LIST_HEAD(&rcl.available_timer);
+ INIT_LIST_HEAD(&rcl.available_list_hdr);
+ INIT_LIST_HEAD(&rcl.created_timer);
+ sema_init_rt(&rcl.sem, 1);
+ if (RT_INIT_VERBOSE)
+ printkGen("init_posix_timers ...\n");
+
+ /* allocate space for the maximum number of timers (CLOCK_REALTIME and CLOCK_SYNC) and timer list headers
+ * allowed for the RT-Domain.
+ * Initialize the bitmap and the pointer list and queue the timers in the list of available timers
+ */
+ size = (((no_posix_timer + 31) >> 3) + no_posix_timer * 4 + no_posix_timer * sizeof(struct posix_timer)
+ + no_of_list_hdr * sizeof(struct rt_list_hdr));
+ if ((rcl.bitmap = (unsigned *) KMALLOC(size, GFP_KERNEL)) == NULL)
+ return(-1);
+ rcl.tmr_map = (struct posix_timer**) (rcl.bitmap + ((no_posix_timer + 31) >> 5));
+ tmr = (struct posix_timer *)(rcl.tmr_map + no_posix_timer);
+ for (i = 0; i < no_posix_timer ; i++)
+ {
+ tmr->it_id = 0; // 0:invalid timer entry
+ tmr->itmr.action_par = (void*)&tmr->rt_notify;
+ tmr->rt_notify.sigq.info.si_code = SI_TIMER;
+ tmr->itmr.flags = 0;
+ INIT_LIST_HEAD(&tmr->it_link);
+ INIT_LIST_HEAD(&tmr->itmr.it_link);
+ INIT_LIST_HEAD(&tmr->rt_notify.sigq.list);
+ list_add (&tmr->it_link, &rcl.available_timer);
+ tmr++;
+ *(rcl.bitmap + (i >> 5)) = 0;
+ *(rcl.tmr_map + i) = 0;
+ }
+ rcl.used_timer = 0;
+ rcl.max_timer = i;
+ rcl.id_count = 1;
+
+ /* initialize the list headers used for handler notification via carrier threads
+ * and queue them in the list of available list headers
+ * The two list headers for timers handled at the ISR level (isr_list_hdr) and for timers handled by the timeout thread
+ * tint_list_hdr) are allocated statically
+ */
+
+ hdr = (struct rt_list_hdr *)tmr;
+ for (i = 0; i < no_of_list_hdr ; i++)
+ {
+ init_rt_list(hdr);
+ list_add (&hdr->hdr_link, &rcl.available_list_hdr);
+ hdr++;
+ }
+ init_rt_list(&isr_list_hdr); // init ISR rt_list
+ init_rt_list(&tint_list_hdr); // init def. list hdr for timeouts
+ for (i = 0; i < MAX_CLOCKS; i ++) // init clock_arr
+ rt_clock_arr[i] = NULL;
+ return(0);
+}
+
+int destroy_rt(int flags)
+{
+ aud_rt_hdr.state = flags;
+ execute_in_lx();
+ KFREE((char*)rcl.bitmap);
+ rt_free_sigqueue_pool();
+ return -1;
+} // now the realtime domain can get deleted
+
+
+
+/*
+ * The task for handling timeouts is created in the Linux domain. First it creates the entire infrastucture for all timer handling
+ * (POSIX timers for CLOCK_REALTIME, CLOCK_MONOTONIC and CLOCK_SYNC). Then it gets migrated to the realtime domain.
+ * Here it attaches itself to the list header for timeout timers and installs the ISR handler for the CLOCK_REALTIME
+ */
+
+int time_handling_rt(int no_of_timers, int no_of_headers, int no_of_sigq)
+{
+ struct itimer *itmr;
+ task_t *p = NULL;
+ struct list_head *lp;
+ struct timeval tval;
+ struct timespec tspec;
+ int tod_init = 0;
+ int res;
+
+ if ((res = clock_getres_int(CLOCK_REALTIME)) < 0) // exported from patched posix-timers.c
+ return -1;
+ if (rt_init_timer(no_of_timers, no_of_headers)< 0)
+ return -1;
+ if (rt_init_sigqueue_pool(no_of_sigq) < 0)
+ return -1;
+ init_rt_list(&tint_list_hdr); // init list hdr for timeouts
+ rt_clock_arr[CLOCK_REALTIME] = &rt_clock;
+ rt_clock.res = (int)res;
+ tint_list_hdr.notification = rt_wake_up_thread;
+ tint_list_hdr.notification_par = current;
+ tod_init = 0; // initialization of timeofday at first tick
+ if (migrate_to_rt(INITIAL_THREAD) == -1)
+ {
+ if (RT_INIT_VERBOSE)
+ printkGen("timer daemon could not migrate to rt \n");
+ return -1;
+ }
+ // From here executing in the realtime domain
+ // everthing is setup and the tick can get enabled
+ // subscribe for timer interrupt
+ if (rt_request_irq(__ipipe_tick_irq, (void*)rt_clock_isr, 0, NULL, NULL, NULL) < 0)
+ return (destroy_rt(RT_FAILED));
+ if (RT_INIT_VERBOSE)
+ printkGen("timer daemon installed in RT domain \n");
+ aud_rt_hdr.state = RT_INSTALLED;
+ aud_rt_hdr.timer_daemon = current; // needed for shutdown to detect the very last thread
+ while (!(aud_rt_hdr.state & RT_SHUTDOWN)) {
+ __set_current_state(RT_TASK_UNINTERRUPTIBLE);
+ if (!tint_list_hdr.run_cnt)
+ rt_schedule();
+ if (tod_init == 0)
+ { // no further tick needs to get assumed while init
+ do_gettimeofday(&tval);
+ tspec.tv_sec = tval.tv_sec;
+ tspec.tv_nsec = tval.tv_usec * 1000;
+ tspec.tv_nsec = tspec.tv_nsec - res/2; // to precompensate for round to nearest in convert to internal
+ convert_to_internal(rt_clock.res, &rt_clock.clock_val, &tspec);
+ rt_clock.offset = 0;
+ rt_clock.clock_val += 1; // one tick is already pending for Linux
+ tint_list_hdr.clock_val = rt_clock.clock_val;
+ isr_list_hdr.clock_val = rt_clock.clock_val;
+ tod_init = 1;
+ new_lx_time.tv_nsec = -1; // clock is up to date
+ add_lx_request(&check_notify_cmd); // notify main thread to complete start up
+ }
+ if (new_lx_time.tv_nsec >= 0) // clock_settime calls has marked an update pending
+ rt_clock_settime();
+ if (aud_rt_hdr.state & RT_SHUTDOWN)
+ break;
+ spin_lock_irq_hw(&ptimer_lock);
+ while ((itmr = rt_thread_list_hdr_handling(&tint_list_hdr))) {
+ spin_unlock_irq_hw(&ptimer_lock);
+ itmr->timer_action(itmr->action_par); // waking up a thread
+ spin_lock_irq_hw(&ptimer_lock);
+ }
+ tint_list_hdr.run_cnt = 0;
+ spin_unlock_irq_hw(&ptimer_lock);
+ }
+ down_rt(&aud_rt_hdr.rt_tl_sem);
+ if (RT_SHUTDOWN_VERBOSE)
+ printkGen("timer daemon preparing for shutdown\n");
+ rt_free_irq(__ipipe_tick_irq); // disable timer interrupt for RT domain
+ while(!list_empty(&aud_rt_hdr.rt_tl)) // shutting down all threads
+ {
+ lp = aud_rt_hdr.rt_tl.next;
+ p = (task_t*)list_entry(lp, task_t, rt_pid_list);
+ if (THREAD_IS_LINUX)
+ { // already under Linux control
+ list_del_init(lp);
+ continue;
+ }
+ rt_mark_exit_pending(p);
+ up_rt(&aud_rt_hdr.rt_tl_sem);
+ __set_current_state(RT_TASK_UNINTERRUPTIBLE);
+ rt_schedule(); // gets woken up from the Linux domain as long as there are user threads
+ down_rt(&aud_rt_hdr.rt_tl_sem);
+ }
+ up_rt(&aud_rt_hdr.rt_tl_sem);
+ return (destroy_rt(RT_SHUTDOWN));
+}
+
+
+int rt_register_clock(clockid_t clockid, struct rtg_clock *clptr)
+{
+ int i;
+
+ if (clockid == -1)
+ {
+ for (i = MAX_CLOCKS -1; i > 0; i--)
+ if (rt_clock_arr[clockid] == NULL)
+ break;
+ clockid = i;
+ }
+ if ((clockid >= MAX_CLOCKS) ||(clockid < 2))
+ return -EINVAL;
+ rt_clock_arr[clockid] = clptr;
+ rt_clock_arr[clockid]->offset = 0;
+ return(clockid);
+}
+
+int rt_unregister_clock(clockid_t clockid)
+{
+ if (clockid >= MAX_CLOCKS)
+ return -EINVAL;
+ rt_clock_arr[clockid] = NULL;
+ return 0;
+
+}
+
+
diff -N -a -u -r linux-2.6.15.4/drivers/aud/audrealtime/sched.c aud_linux/drivers/aud/audrealtime/sched.c
--- linux-2.6.15.4/drivers/aud/audrealtime/sched.c 1970-01-01 01:00:00.000000000 +0100
+++ aud_linux/drivers/aud/audrealtime/sched.c 2007-04-16 12:50:14.000000000 +0200
@@ -0,0 +1,338 @@
+/*
+ * rtime/audrealtime/sched.c
+ *
+ * 2007-19-01: Karl-Heinz.Krause@siemens.com
+ * Copyright (c) 2007 Siemens AG
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * This file contains all the routines needed for UP preemptive scheduling
+ *
+ */
+
+#include "../include/rt_timer.h"
+
+#ifdef CONFIG_SMP
+void smp_send_reschedule(int cpu);
+#endif
+
+_INT64 delete_internal_timer(struct itimer *);
+
+struct runqueue runqueues[1];
+
+extern struct ipipe_domain *ipipe_root_domain;
+extern struct ipipe_domain *ipipe_percpu_domain[];
+
+task_t *rt_req_task; // task requested for execution
+task_t *lx_curr_task;
+
+
+
+void rt_init_sched(void)
+{
+ int ii;
+
+ spin_lock_init(&runqueues[0].lock);
+ for (ii = 0; ii < MAX_NO_OF_RT_PRIO; ii++) {
+ INIT_LIST_HEAD(&runqueues[0].queue[ii].qhead);
+ runqueues[0].queue[ii].idx = ii;
+ }
+ runqueues[0].nr_running = 0;
+ runqueues[0].bitmapPrio = 0;
+ rt_req_task = NULL; // task requested for execution
+}
+
+/*
+ * Interrupt handling for IPIs needs a function pointer before the RT domain is set up
+ */
+
+void rt_noop_work(void)
+{
+}
+
+
+/*
+ * called from the rtx patch of ipipe for the realtime domain after executing an ISR
+ * It is called with HW interrupts off
+ */
+
+void rt_check_for_work(void)
+{
+ runqueue_t *rq = &runqueues[0];
+ task_t * rt_curr_task;
+
+ if (!rt_req_task || (rt_req_task == current))
+ return;
+
+#ifdef CONFIG_SMP
+ // Delegate the check for context switch to CPU0 since the tick isr can get handled on other CPUs as well
+ if (smp_processor_id()) {
+ smp_send_reschedule(0);
+ return;
+ }
+#endif
+
+ spin_lock_irq_hw(&rq->lock);
+ if (THREAD_IS_LINUX)
+ { // current stack is Linux stack
+ lx_curr_task = current; // save it for leaving rt domain
+ if (current->tgid != aud_lx_tgid) // another address space?
+ rt_switch_mm(rt_req_task->active_mm->pgd); // switch address space
+ }
+ rt_curr_task = current;
+ rt_switch_to(rt_curr_task, rt_req_task, rt_curr_task);
+ if (THREAD_IS_LINUX)
+ { // returning to Linux stack
+ if (current->tgid != aud_lx_tgid) // resume when leaving rt_domain
+ rt_switch_mm(current->active_mm->pgd); // switch address space
+ rt_req_task = NULL;
+ }
+ spin_unlock_irq_hw(&rq->lock); // now the HW interrupts are enabled
+ local_irq_disable_hw(); // ipipe resumes with local interrupts off
+}
+
+
+inline task_t * rt_get_next_thread(runqueue_t *rq)
+{
+ int ii;
+ struct list_head *queue;
+
+
+ ii = __ffs(rq->bitmapPrio); // search for the first bit, starting at top
+ queue = rq->queue[ii].qhead.next;
+ return((task_t*)list_entry(queue, task_t, run_list));//
+}
+
+
+inline void rt_enqueue_thread(runqueue_t *rq, struct task_struct *p)
+{
+ int idx;
+
+ if (unlikely((idx = p->prio) >= MAX_NO_OF_RT_PRIO))
+ { // must be a thread which is due to migration
+ idx = MAX_NO_OF_RT_PRIO - 1; // For executing migration we queue the thread
+ p->state |= RT_MIGRATION_PENDING; // at the lowest priority
+ }
+ list_add_tail(&p->run_list, &rq->queue[idx].qhead);
+ __set_bit(idx, &rq->bitmapPrio);
+ rt_req_task = rt_get_next_thread(rq);
+}
+
+inline void rt_dequeue_thread(runqueue_t *rq, struct task_struct *p)
+{
+ struct list_head *lp;
+ struct rq_head *qp;
+
+ lp = p->run_list.prev;
+ list_del_init(&p->run_list);
+ if (list_empty(lp))
+ {
+ qp = (struct rq_head *)list_entry(lp, struct rq_head, qhead);
+ __clear_bit(qp->idx, &rq->bitmapPrio);
+ }
+}
+
+
+/* This routine may be called
+ * - from a rt thread
+ * - from an ISR
+ * - from a Linux thread, a subsequent ipipe-softinterrupt for the RT-domain leads to a switch
+ */
+
+
+int fastcall rt_wake_up_thread(void * arg)
+{
+ runqueue_t *rq = &runqueues[0];
+ task_t *p = (task_t*) arg;
+ int flags;
+
+ spin_lock_irqsave_hw(&rq->lock, flags); // we may be called from ISR with interrupts already disabled
+ p->state |= RT_TASK_RUNNING;
+ if (likely(list_empty(&p->run_list))) // may be already queued in
+ rt_enqueue_thread(rq,p);
+ spin_unlock_irqrestore_hw(&rq->lock, flags); //we may be called from ISR with interrupts disabled
+ return 0;
+}
+
+/*
+ * is called as part of a system call which does a wake up e.g. FUTEX_WAKE
+ * There is no nesting and no call from isr, therefore spin_lock_irq_hw/spin_unlock_irq_hw can be used
+ */
+
+void fastcall rt_check_preemption(void)
+{
+ runqueue_t *rq = &runqueues[0];
+ task_t * rt_curr_task;
+
+ spin_lock_irq_hw(&rq->lock); //
+
+ if (current != rt_req_task)
+ {
+ rt_curr_task = current;
+ rt_switch_to(rt_curr_task, rt_req_task, rt_curr_task);
+ }
+ spin_unlock_irq_hw(&rq->lock);
+}
+
+
+/*
+ * rt_schedule gets only called from a RT thread which suspends itself
+ * Attention: it uses the pair spin_lock_irq_hw/spin_unlock_irq_hw().
+ * First, for the RT domain it is guaranteed, that there is no nesting and
+ * second when continueing a thread after a domain switch the interrupts
+ * must be enabled unconditionally
+ */
+
+void fastcall rt_schedule(void)
+{
+ runqueue_t *rq = &runqueues[0];
+ int state;
+ task_t *rt_curr_task;
+
+ spin_lock_irq_hw(&rq->lock);
+ if (likely(!(current->state & RT_TASK_RUNNING))) // in case it got RUNNING again
+ {
+ __set_current_state(TASK_UNINTERRUPTIBLE);
+ rt_dequeue_thread(rq, current);
+ if (!rq->bitmapPrio)
+ rt_req_task = lx_curr_task; // we have to switch to the Linux domain
+ else
+ rt_req_task = rt_get_next_thread(rq);
+ if (likely(rt_req_task != current))
+ {
+ rt_curr_task = current;
+ rt_switch_to( rt_curr_task, rt_req_task, rt_curr_task);
+ }
+ }
+ if (THREAD_IS_REALTIME) //
+ {
+ spin_unlock_irq_hw(&rq->lock);
+ if (current->state & (RT_MIGRATION_PENDING | RT_EXIT_PENDING))
+ {
+ state = current->state;
+ do_rt_leave(); // in both cases the thread has to leave the rt thread list
+ if (aud_rt_hdr.state == RT_SHUTDOWN)
+ {
+ rt_wake_up_thread(aud_rt_hdr.timer_daemon); // wake up timer daemon
+ ipipe_trigger_irq(to_rt_irq); // to take down next thread
+ current->exit_signal = -1;
+ do_exit(-1);
+ }
+ else
+ if (state & RT_EXIT_PENDING)
+ do_exit(0);
+
+ }
+ }
+ // otherwise thread has left realtime scheduling and unlocking was done when leaving domain
+}
+
+/*
+ * This routine is needed for dynamic priority changes. Within a SMP system it may also get called
+ * from Linux if p != current
+ */
+
+int rt_reschedule(struct task_struct *p)
+{
+ runqueue_t *rq = &runqueues[0];
+
+ spin_lock_irq_hw(&rq->lock);
+ if ((p->prio >= MAX_NO_OF_RT_PRIO) && (p == current))
+ { // need to migrate to Linux
+ spin_unlock_irq_hw(&rq->lock);
+ execute_in_lx(); // migrate immediately
+ return 0;
+ }
+ if (list_empty(&p->run_list))
+ { // thread is not active
+ spin_unlock_irq_hw(&rq->lock);
+ return 0;
+ }
+ rt_dequeue_thread(rq, p);
+ rt_enqueue_thread(rq, p);
+ spin_unlock_irq_hw(&rq->lock);
+ if (THREAD_IS_REALTIME)
+ rt_check_preemption();
+ else
+ ipipe_trigger_irq(to_rt_irq); // can only occur within a MP-system
+ return 0;
+}
+
+
+/*
+ * When migrating from Linux to realtime, the migrating thread must execute the leaving half of
+ * the scheduling function in particular it must unlock the runqueue
+ */
+
+void rt_enter_schedule()
+{
+ runqueue_t *rq = &runqueues[0];
+
+ spin_unlock_irq_hw(&rq->lock);
+}
+
+
+_INT64 rt_schedule_timeout(int flag, _INT64 timeout)
+{
+ struct itimer itmr;
+ _INT64 remaining_time;
+
+ if (!flag)
+ {
+ rt_schedule();
+ return(0);
+ }
+ setup_internal_timer(&itmr, timeout, rt_wake_up_thread);
+ rt_schedule();
+ remaining_time = delete_internal_timer(&itmr);
+ return(remaining_time);
+}
+
+/*
+ * gets called from either sys_rt_sched_yield or
+ * from the tick routine when the time slice has expired
+ */
+
+void rt_sched_rr(void)
+{
+ int flags;
+ runqueue_t *rq;
+ rq = &runqueues[0];
+
+ spin_lock_irqsave_hw(&rq->lock, flags);
+ rt_dequeue_thread(rq, current);
+ rt_enqueue_thread(rq, current);
+ rt_req_task = rt_get_next_thread(rq);
+ spin_unlock_irqrestore_hw(&rq->lock, flags);
+}
+
+asmlinkage long sys_rt_sched_yield(void)
+{
+ rt_sched_rr();
+ rt_check_preemption();
+ return (0);
+}
+
+void rt_mark_exit_pending(struct task_struct *p)
+{
+ runqueue_t *rq;
+ rq = &runqueues[0];
+
+ spin_lock_irq_hw(&rq->lock);
+ p->state |= RT_EXIT_PENDING;
+ spin_unlock_irq_hw(&rq->lock);
+ rt_wake_up_thread(p);
+}
diff -N -a -u -r linux-2.6.15.4/drivers/aud/audrealtime/semaphore.c aud_linux/drivers/aud/audrealtime/semaphore.c
--- linux-2.6.15.4/drivers/aud/audrealtime/semaphore.c 1970-01-01 01:00:00.000000000 +0100
+++ aud_linux/drivers/aud/audrealtime/semaphore.c 2007-04-10 20:49:27.000000000 +0200
@@ -0,0 +1,74 @@
+/*
+ * rtime/audrealtime/fs_op.c
+ *
+ * 2007-19-01: Karl-Heinz.Krause@siemens.com
+ * Copyright (c) 2007 Siemens AG
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * This file contains the functions for rt kernel internal semaphores
+ *
+ */
+
+#include "../include/rt_timer.h"
+
+
+
+void sema_init_rt(struct rt_semaphore *sem, int val)
+{
+ sem->count = val;
+ spin_lock_init(&sem->wait.lock);
+ INIT_LIST_HEAD(&sem->wait.list);
+}
+
+
+void up_rt(struct rt_semaphore *sem)
+{
+ struct rt_wait *wq;
+ int flag;
+
+ spin_lock_irqsave_hw(&sem->wait.lock, flag); // may also be issued from ISR mode
+ if (list_empty(&sem->wait.list))
+ {
+ sem->count++;
+ spin_unlock_irqrestore_hw(&sem->wait.lock, flag);
+ return;
+ }
+ wq = (struct rt_wait *)&sem->wait.list.next;
+ list_del_init(&wq->list);
+ rt_wake_up_thread(wq->proc);
+ spin_unlock_irqrestore_hw(&sem->wait.lock, flag);
+ rt_check_preemption();
+}
+
+void down_rt(struct rt_semaphore *sem)
+{
+ struct rt_wait wq;
+
+ spin_lock_irq_hw(&sem->wait.lock);
+ if (sem->count > 0)
+ {
+ sem->count--;
+ spin_unlock_irq_hw(&sem->wait.lock);
+ return;
+ }
+ wq.proc = current;
+ INIT_LIST_HEAD(&wq.list);
+ list_add_tail(&wq.list, &sem->wait.list);
+ __set_current_state(RT_TASK_UNINTERRUPTIBLE);
+ spin_unlock_irq_hw(&sem->wait.lock);
+ rt_schedule();
+}
diff -N -a -u -r linux-2.6.15.4/drivers/aud/audrealtime/signal.c aud_linux/drivers/aud/audrealtime/signal.c
--- linux-2.6.15.4/drivers/aud/audrealtime/signal.c 1970-01-01 01:00:00.000000000 +0100
+++ aud_linux/drivers/aud/audrealtime/signal.c 2007-04-10 20:49:27.000000000 +0200
@@ -0,0 +1,533 @@
+/*
+ * rtime/audrealtime/signal.c
+ *
+ * 2007-19-01: Karl-Heinz.Krause@siemens.com
+ * Copyright (c) 2007 Siemens AG
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * This file contains all the signal functions of the rt kernel
+ *
+ */
+
+
+#include "../include/rt_timer.h"
+
+struct itimer * rt_thread_list_hdr_handling(struct rt_list_hdr *);
+extern struct rtg_clock rt_clock;
+int copy_siginfo_to_user(siginfo_t *info, siginfo_t *src);
+
+struct task_struct * rt_get_task_locked(pid_t);
+void rt_mark_exit_pending(struct task_struct *);
+long do_rt_leave(void);
+
+struct sighand_struct rt_p_handler; // ->p_handler of Linux domain stays untouched
+ // only used to protect sigqueue list handling of realtime domain
+extern spinlock_t ptimer_lock;
+
+spinlock_t siglock;
+struct sig_pool_head {
+ struct list_head free_list; // free list of struct notify elements
+ char * mem; // address for freeing area when shutting down
+};
+struct sig_pool_head nfb_pool;
+
+#ifdef SIGEMT
+#define M_SIGEMT M(SIGEMT)
+#else
+#define M_SIGEMT 0
+#endif
+
+#if SIGRTMIN > BITS_PER_LONG
+#define M(sig) (1ULL << ((sig)-1))
+#else
+#define M(sig) (1UL << ((sig)-1))
+#endif
+#define T(sig, mask) (M(sig) & (mask))
+
+#define SIG_KERNEL_ONLY_MASK (\
+ M(SIGKILL) | M(SIGSTOP) )
+
+#define SIG_KERNEL_STOP_MASK (\
+ M(SIGSTOP) | M(SIGTSTP) | M(SIGTTIN) | M(SIGTTOU) )
+
+#define SIG_KERNEL_COREDUMP_MASK (\
+ M(SIGQUIT) | M(SIGILL) | M(SIGTRAP) | M(SIGABRT) | \
+ M(SIGFPE) | M(SIGSEGV) | M(SIGBUS) | M(SIGSYS) | \
+ M(SIGXCPU) | M(SIGXFSZ) | M_SIGEMT )
+
+#define SIG_KERNEL_IGNORE_MASK (\
+ M(SIGCONT) | M(SIGCHLD) | M(SIGWINCH) | M(SIGURG) )
+
+#define sig_kernel_only(sig) \
+ (((sig) < SIGRTMIN) && T(sig, SIG_KERNEL_ONLY_MASK))
+#define sig_kernel_coredump(sig) \
+ (((sig) < SIGRTMIN) && T(sig, SIG_KERNEL_COREDUMP_MASK))
+#define sig_kernel_ignore(sig) \
+ (((sig) < SIGRTMIN) && T(sig, SIG_KERNEL_IGNORE_MASK))
+#define sig_kernel_stop(sig) \
+ (((sig) < SIGRTMIN) && T(sig, SIG_KERNEL_STOP_MASK))
+
+#define sig_user_defined(t, signr) \
+ (((t)->sighand->action[(signr)-1].sa.sa_handler != SIG_DFL) && \
+ ((t)->sighand->action[(signr)-1].sa.sa_handler != SIG_IGN))
+
+#define sig_fatal(t, signr) \
+ (!T(signr, SIG_KERNEL_IGNORE_MASK|SIG_KERNEL_STOP_MASK) && \
+ (t)->sighand->action[(signr)-1].sa.sa_handler == SIG_DFL)
+
+static int sig_ignored(struct task_struct *t, int sig)
+{
+ void * handler;
+
+ /* Is it explicitly or implicitly ignored? */
+
+ handler = t->sighand->action[sig-1].sa.sa_handler;
+ return handler == SIG_IGN ||
+ (handler == SIG_DFL && sig_kernel_ignore(sig));
+ return 0;
+}
+
+#define PSEUDO_SIG 0x0f0f0f0f
+#define TRY 0 // to distinguish when dequeueing a signal
+#define NEED -EINTR // in case no matching signal is found
+
+
+/*
+ * At least for realtime signals, elements with lower signal number should be served first
+ * Since multiple sigq elements are a rare case. We take the hit here for sorting them in correctly
+ * This routine is called under lock
+ */
+
+void sigq_add_ordered(struct list_head *new, struct list_head *head)
+{
+ struct list_head *curr = head;
+ struct sigqueue *q, *p;
+
+ p = (struct sigqueue *)new;
+ for (curr = head->next; curr != head; curr = curr->next)
+ {
+ q = (struct sigqueue *)curr;
+ if (q->info.si_signo >= p->info.si_signo)
+ break;
+ }
+ list_add(new, curr);
+}
+
+/*
+ * Removes the sigqueue element from the list of pending signals if it is in the signal queue
+ * of the thread specified in .thread. This routine is specifically for rt_send_alt_sigqueue
+ * for the case of a subsequent timing violation
+ * It must be called under lock
+ */
+
+int rt_dequeue_signal_thread(struct notify *nfb)
+{
+ struct list_head *curr, *head;
+ struct sigqueue *q;
+ int dequeued = 0;
+
+ head = &nfb->thread->rt_sigqueue_head;
+ for (curr = head->next; curr != head; curr = curr->next)
+ {
+ q = (struct sigqueue *)curr;
+ if (q == &nfb->sigq )
+ {
+ list_del_init(&nfb->sigq.list);
+ dequeued = 1;
+ }
+ }
+ return(dequeued);
+}
+
+/*
+ * dequeues the sigq element from whatever queue it is in
+ */
+
+int rt_dequeue_sigq (struct sigqueue* sigq)
+{
+ int flag;
+
+ spin_lock_irqsave_hw(&siglock, flag);
+ list_del_init(&sigq->list); // POSIX allows to cut corners
+ spin_unlock_irqrestore_hw(&siglock, flag);
+ return(0);
+}
+
+
+INLINE int copy_siginfo_to_user_rt(int overrun, siginfo_t *info, siginfo_t *src)
+{
+ int err = 0;
+
+ if (info == NULL)
+ return(0);
+ err = __put_user(src->si_signo, &info->si_signo);
+ err |= __put_user(src->si_errno, &info->si_errno);
+ err |= __put_user((short)src->si_code, &info->si_code);
+ err |= __put_user(src->si_int, &info->si_int);
+ err |= __put_user(src->si_tid, &info->si_tid);
+ err |= __put_user(overrun, &info->si_overrun);
+ return err;
+}
+
+int rt_dequeue_signal(struct task_struct *tsk, siginfo_t *info, int flag)
+{
+ int overrun;
+ struct sigqueue *q;
+ struct list_head *head, *curr;
+ int sig;
+
+
+
+ head = &tsk->rt_sigqueue_head;
+ spin_lock_irq_hw(&siglock);
+ for (curr = head->next; curr != head; curr = curr->next)
+ {
+ q = (struct sigqueue *)curr;
+ sig = q->info.si_signo;
+ if (likely(sigismember(&tsk->real_blocked, sig)))
+ {
+ list_del_init(curr); // dequeue element
+ overrun = q->info.si_overrun; // in case of PREALLOC elements
+ q->info.si_overrun = 0; // reset it for overrun detection
+ sigemptyset(¤t->real_blocked); // must be done here while
+ __set_current_state(RT_TASK_RUNNING); // still under lock
+ spin_unlock_irq_hw(&siglock);
+ if ((sig == SIGTIMER) && (current->rt_timer_list_hdr != NULL) && (q->info.si_code == SI_LHDR)) // carrier thread ?
+ return PSEUDO_SIG;
+ if (copy_siginfo_to_user_rt(overrun, info, &q->info))
+ return -EFAULT;
+ if (likely(q->flags == SIGQUEUE_PREALLOC))
+ return(sig);
+ spin_lock_irq_hw(&siglock);
+ list_add(curr, &nfb_pool.free_list);
+ spin_unlock_irq_hw(&siglock);
+ return sig;
+ }
+ }
+ if (flag == NEED) // no signal found
+ {
+ sigemptyset(¤t->real_blocked); // must be done here while
+ __set_current_state(RT_TASK_RUNNING); // still under lock
+ }
+ spin_unlock_irq_hw(&siglock);
+ return(flag);
+}
+
+
+asmlinkage long sys_rt_sigtimedwait_rt(const sigset_t *uthese, siginfo_t *uinfo,
+ const struct timespec *uts, size_t sigsetsize)
+{
+ int error, sig;
+ sigset_t waitset;
+ struct timespec ts;
+ _INT64 timeout64 = 0;
+ struct notify *nfb;
+ struct itimer *itmr;
+ int flag;
+ struct rt_list_hdr *hdr;
+
+ if (copy_from_user(&waitset, uthese, sizeof(waitset)))
+ return -EFAULT;
+ if ((current->rt_timer_list_hdr != NULL) && (sigismember(&waitset, SIGTIMER)))
+ {
+carrier_thread_handling:
+ hdr = current->rt_timer_list_hdr;
+ spin_lock_irq_hw(&ptimer_lock);
+ if ((itmr = rt_thread_list_hdr_handling(hdr)))
+ {
+ nfb = (struct notify*)itmr->action_par;
+ spin_unlock_irq_hw(&ptimer_lock);
+ if (RT_TIMER_VERBOSE)
+ printkGen("Timer: handler notification: timerid: %d\n", nfb->sigq.info._sifields._timer._tid);
+ if (copy_siginfo_to_user_rt(0,uinfo, &nfb ->sigq.info))
+ return -EFAULT;
+ return(SIGTIMER);
+ }
+ hdr-> run_cnt = 0;
+ spin_unlock_irq_hw(&ptimer_lock);
+ }
+ current->real_blocked = waitset;
+ __set_current_state(RT_TASK_UNINTERRUPTIBLE); // will be reset to RT_TASK_RUNNING under lock
+ // when a matching signal gets dequeued
+ if (!(sig = rt_dequeue_signal(current, uinfo, TRY)))
+ { // no matching signal is queued
+ flag = 0;
+ if (uts) // a check for a valid timespec is only needed
+ { // in case of waiting, POSIX allows for that
+ if (copy_from_user(&ts, uts, sizeof(ts)))
+ return -EFAULT;
+ if ((error = convert_to_internal(rt_clock.res, &timeout64, &ts)))
+ return(error);
+ flag = 1;
+ if (!timeout64)
+ return -EAGAIN;
+ }
+ timeout64 = rt_schedule_timeout(flag, timeout64);
+ sig = rt_dequeue_signal(current, uinfo, NEED);
+ if (sig == PSEUDO_SIG)
+ goto carrier_thread_handling;
+ if (sig > 0)
+ return sig; // valid signal number
+ if (flag && !timeout64)
+ return -EAGAIN;
+ }
+ if (sig == PSEUDO_SIG)
+ goto carrier_thread_handling;
+ return sig; // either signo or -EINTR
+}
+
+/*
+ * This is the path critical for response behavior. The function can be called from the ISR-level as well
+ * It assumes, that there will be no system call getoverrun. For events we don't have it anyway
+ * Therefore the overrun will always only be passed in the siginfo area
+ */
+int fastcall rt_send_sigqueue(struct notify *nfb)
+{
+ struct sigqueue *q = &nfb->sigq;
+ struct task_struct *p = nfb->thread;
+ int sig;
+ int flag;
+
+ sig = q->info.si_signo;
+ spin_lock_irqsave_hw(&siglock, flag);
+ if (unlikely(!sigismember(&p->blocked, sig)) ) // normally all signals should be blocked
+ {
+ if (sig_ignored(p, sig))
+ goto out;
+ }
+ if (likely(list_empty(&p->rt_sigqueue_head)) ) // most likely situation
+ { // then q->list also must be empty
+ __list_add(&q->list,&p->rt_sigqueue_head, &p->rt_sigqueue_head); // somewhat faster
+ }
+ else
+ {
+ if (!list_empty(&q->list))
+ { // sigq element is already queued in
+ q->info.si_overrun++;
+ goto out;
+ }
+ sigq_add_ordered(&q->list, &p->rt_sigqueue_head); // ordering according to bit no as required by POSIX
+ }
+ if (likely(sigismember(&p->real_blocked, sig))) // real_block = waiting
+ rt_wake_up_thread(p);
+out:
+ spin_unlock_irqrestore_hw(&siglock, flag);
+ return(0);
+}
+
+
+/* Based on thread_waiting() the function rt_timer_notify_alternative_thread() provides for supervising the timeliness of a
+ * thread to be notified. The assumption is, that a supervisor thread is waiting for the same signal as the thread to be
+ * notified and will pick up the signal, if the target thread is not already waiting
+ *
+ * returns 1 if the thread specified in tmr->it_process is waiting for the signal specified in tmr->it_sigev_signo
+ * returns zero if the specified thread is not waiting
+ */
+
+int fastcall rt_send_alt_sigqueue(struct notify *nfb)
+{
+ int qstat;
+ int flag;
+ struct task_struct *p;
+
+ spin_lock_irqsave_hw(&siglock, flag);
+ if (unlikely(!list_empty(&nfb->sigq.list)))
+ {
+ nfb->sigq.info.si_overrun++;
+ qstat = rt_dequeue_signal_thread(nfb); // dequeue it if in nfb->thread
+ spin_unlock_irqrestore_hw(&siglock, flag);
+ if (qstat)
+ {
+ p = nfb->thread;
+ nfb->thread = nfb->alt_thread;
+ rt_send_sigqueue(nfb); // queue it at the supervisor thread
+ nfb->thread = p;
+ }
+ return(0);
+ }
+ if (++(nfb->cycle) == abs(nfb->sigq.info.si_int))
+ {
+ nfb->cycle = 0;
+ spin_unlock_irqrestore_hw(&siglock, flag);
+ if (!(sigismember(&nfb->thread->blocked, nfb->sigq.info.si_signo))) // already waiting?
+ {
+ p = nfb->thread;
+ nfb->thread = nfb->alt_thread;
+ rt_send_sigqueue(nfb);
+ nfb->thread = p;
+ return 0;
+ }
+ return(rt_send_sigqueue(nfb));
+ }
+ if ((nfb->sigq.info.si_int < 0) && (sigismember(&nfb->thread->blocked, nfb->sigq.info.si_signo)))
+ nfb->cycle = 0;
+ spin_unlock_irqrestore_hw(&siglock, flag);
+ return(rt_send_sigqueue(nfb));
+}
+
+asmlinkage long sys_rt_sigprocmask_rt(int how, sigset_t *set, sigset_t *oset, size_t sigsetsize)
+{
+ sigset_t old_set, new_set;
+
+ old_set = current->blocked;
+ if (set) {
+ if (copy_from_user(&new_set, set, sizeof(*set)))
+ return -EFAULT;
+ sigdelsetmask(&new_set, sigmask(SIGKILL));
+ spin_lock_irq_hw(&siglock);
+
+ switch (how) {
+ case SIG_BLOCK:
+ sigorsets(¤t->blocked, ¤t->blocked, set);
+ break;
+ case SIG_UNBLOCK:
+ signandsets(¤t->blocked, ¤t->blocked, set);
+ break;
+ case SIG_SETMASK:
+ current->blocked = *set;
+ break;
+ default:
+ spin_unlock_irq_hw(&siglock);
+ return -EINVAL;
+ }
+ }
+ spin_unlock_irq_hw(&siglock);
+ if (oset)
+ if (copy_to_user(oset, &old_set, sizeof(*oset)))
+ return -EFAULT;
+ return 0;
+}
+
+asmlinkage long sys_rt_sigpending_rt(sigset_t __user *set, size_t sigsetsize)
+{
+ sigset_t pending_set;
+ struct sigqueue *q;
+ struct list_head *head, *curr;
+ int sig;
+
+ sigemptyset(&pending_set);
+
+ head = ¤t->rt_sigqueue_head;
+ spin_lock_irq_hw(&siglock);
+ for (curr = head->next; curr != head; curr = curr->next)
+ {
+ q = (struct sigqueue *)curr;
+ sig = q->info.si_signo;
+ sigaddset(&pending_set, sig);
+ }
+ spin_unlock_irq_hw(&siglock);
+ if (copy_to_user(set, &pending_set, sizeof(*set)))
+ return -EFAULT;
+ return 0;
+}
+
+/*
+ * allocates a pool of struct notify elements for use so that rt_do_kill() can use rt_send_sigqueue()
+ */
+
+int rt_init_sigqueue_pool(int no)
+{
+ struct sigqueue *qp;
+ struct notify *n;
+ int i;
+
+ spin_lock_init(&siglock);
+ INIT_LIST_HEAD(&nfb_pool.free_list);
+ if ((nfb_pool.mem = KMALLOC((no * sizeof(struct notify)), GFP_KERNEL)) == NULL)
+ return(-1);
+ n = (struct notify *)nfb_pool.mem;
+ for (i = 0; i < no; i++)
+ {
+ qp = &n->sigq;
+ qp->flags = 0;
+ qp->info.si_errno = 0;
+ qp->info.si_overrun = 0;
+ qp->info.si_code = SI_TKILL;
+ INIT_LIST_HEAD(&qp->list);
+ list_add(&qp->list, &nfb_pool.free_list);
+ n++;
+ }
+ return 0;
+}
+
+void rt_free_sigqueue_pool(void)
+{
+ KFREE(nfb_pool.mem);
+}
+
+long rt_do_kill(int pid, int sig)
+{
+ struct task_struct *p;
+ struct sigqueue *qp;
+ struct notify *nfb;
+ struct list_head *lh;
+
+ if ((p = rt_get_task_locked(pid)) == NULL)
+ return 0; // retry it in the Linux domain
+ up_rt(&aud_rt_hdr.rt_tl_sem); // in the realtime domain the semaphore is still locked
+ if (sig == 0)
+ return 0;
+ if ((sig == SIGTERM) || (sig == SIGABRT) || (sig == SIGKILL))
+ { // for SIGKILL the entire group may to be brought down ??
+ if (p == current)
+ {
+ do_rt_leave(); // have it executed in the Linux domain
+ do_exit(0);
+ }
+ rt_mark_exit_pending(p);
+ return 0;
+ }
+ if ((sig >= SIGRTMIN) && (sig <= SIGRTMAX))
+ {
+ spin_lock_irq_hw(&siglock);
+ if (list_empty(&nfb_pool.free_list))
+ {
+ spin_unlock_irq_hw(&siglock);
+ return -EAGAIN;
+ }
+ lh = nfb_pool.free_list.next;
+ list_del_init(lh);
+ spin_unlock_irq_hw(&siglock);
+ nfb = (struct notify*)list_entry(lh, struct notify, sigq.list);
+ nfb->thread = p;
+ qp = &nfb->sigq;
+ qp->info.si_pid = current->tgid;
+ qp->info.si_uid = current->uid;
+ qp->info.si_signo = sig;
+ rt_send_sigqueue(nfb);
+ return 0;
+ }
+ return -EINVAL;
+}
+
+asmlinkage long sys_rt_tkill(int pid, int sig)
+{
+ return rt_do_kill(pid, sig);
+}
+/*
+ * tgkill does only additional checking for group membership.
+ * Since all threads found in the rt_thread_list belong to the same group, the
+ * execution in the realtime domain is identical
+ */
+
+asmlinkage long sys_rt_tgkill(int tgid, int pid, int sig)
+{
+ return rt_do_kill(pid, sig);
+}
+
+
+
diff -N -a -u -r linux-2.6.15.4/drivers/aud/audrealtime/syscall_table.S aud_linux/drivers/aud/audrealtime/syscall_table.S
--- linux-2.6.15.4/drivers/aud/audrealtime/syscall_table.S 1970-01-01 01:00:00.000000000 +0100
+++ aud_linux/drivers/aud/audrealtime/syscall_table.S 2007-04-10 20:49:27.000000000 +0200
@@ -0,0 +1,313 @@
+
+.data
+.global rt_sys_call_table
+rt_sys_call_table:
+.long sys_rt_ni_syscall
+.long sys_rt_exit /* sys_exit */
+.long sys_rt_ni_syscall
+.long sys_rt_read
+.long sys_rt_write
+.long execute_in_lx /* 5 open */
+.long execute_in_lx /* close */
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long execute_in_lx /* 9: link */
+.long execute_in_lx /* 10: unlink */
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long execute_in_lx /* 13: time */
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_getpid /* 20 */
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long execute_in_lx /* 27: alarm */
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall /* 30 */
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long execute_in_lx
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall /* 40 */
+.long execute_in_lx /* dup */
+.long execute_in_lx /* pipe */
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long execute_in_lx /* brk */
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long execute_in_lx /* 49: geteuid16 */
+.long execute_in_lx /* 50 getegid16 */
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ioctl
+.long execute_in_lx /* 55: fcntl */
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long execute_in_lx /* 60 umask */
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long execute_in_lx /* dup2 */
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long execute_in_lx /* sigaction */
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall /* 70 */
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long execute_in_lx /* 75: setrtlimit */
+.long execute_in_lx /* 76: old_getrlimit */
+.long sys_rt_ni_syscall
+.long sys_rt_gettimeofday
+.long execute_in_lx /* settimeofday */
+.long sys_rt_ni_syscall /* 80 */
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long execute_in_lx /* 90: old mmap*/
+.long execute_in_lx /* munmap */
+.long execute_in_lx /* truncate */
+.long execute_in_lx /* 93: ftruncate */
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long execute_in_lx /* 99: sys_statfs */
+.long sys_rt_ni_syscall /* 100 */
+.long execute_in_lx /* ioperm */
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long execute_in_lx /* 106: newstat */
+.long execute_in_lx /* 107: newlstat */
+.long execute_in_lx /* 108: newfstat */
+.long sys_rt_ni_syscall
+.long execute_in_lx /* 110 iopl */
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long execute_in_lx /* sys_fsync */
+.long execute_in_lx /* sigreturn */
+.long execute_in_lx /* 120 clone */
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long execute_in_lx /* 125: mprotect */
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall /* 130 */
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long execute_in_lx /* 140: llseek */
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long execute_in_lx /* 144: msync */
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall /* 150 */
+.long sys_rt_ni_syscall
+.long execute_in_lx /* 152: mlockall */
+.long sys_rt_ni_syscall
+.long sys_rt_sched_setparam
+.long sys_rt_sched_getparam /*155 */
+.long sys_rt_sched_setscheduler
+.long sys_rt_sched_getscheduler
+.long sys_rt_sched_yield
+.long execute_in_lx /* sched_get_priority_max */
+.long execute_in_lx /* 160 sched_get_priority_min */
+.long sys_rt_ni_syscall
+.long sys_rt_nanosleep
+.long execute_in_lx /* mremap */
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall /* 165 */
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall /* 170 */
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long execute_in_lx /* sigaction */
+.long sys_rt_sigprocmask_rt /* 175 */
+.long sys_rt_sigpending_rt
+.long sys_rt_sigtimedwait_rt
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall /* 180 */
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall /* 185 */
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall /* 190 */
+.long execute_in_lx /* 191: getrlimit */
+.long execute_in_lx /* mmap2 */
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long execute_in_lx /* 195: stat64 */
+.long execute_in_lx /* 196: lstat64 */
+.long execute_in_lx /* fstat64 */
+.long sys_rt_ni_syscall
+.long sys_rt_getuid /* getuid */
+.long execute_in_lx /* 200; getgid */
+.long execute_in_lx /* 201: geteuid */
+.long execute_in_lx /* 202: getegid */
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall /* 210 */
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall /* 220 */
+.long execute_in_lx /* fcntl64 */
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_gettid /* 224 */
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall /* 230 */
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_tkill
+.long sys_rt_ni_syscall
+.long sys_rt_futex /* 240 */
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall /* 250 */
+.long sys_rt_ni_syscall
+.long sys_rt_exit_group /* exit_group */
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_timer_create
+.long sys_rt_timer_settime /* 260 */
+.long sys_rt_timer_gettime
+.long sys_rt_ni_syscall
+.long sys_rt_timer_delete
+.long sys_rt_clock_settime
+.long sys_rt_clock_gettime /* 265 */
+.long sys_rt_clock_getres
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_tgkill /* 270 */
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long execute_in_lx /* mq_open */
+.long execute_in_lx /* mq_unlink */
+.long sys_rt_mq_timedsend
+.long sys_rt_mq_timedreceive /* 280 */
+.long sys_rt_ni_syscall /* mq_notify */
+.long execute_in_lx /* mq_getsetattr */
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+
+
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+.long sys_rt_ni_syscall
+
+rt_syscall_table_size=(.-rt_sys_call_table)
+.globl rt_syscall_table_size_ref
+rt_syscall_table_size_ref:
+.int rt_syscall_table_size
diff -N -a -u -r linux-2.6.15.4/drivers/aud/audrealtime/thread.c aud_linux/drivers/aud/audrealtime/thread.c
--- linux-2.6.15.4/drivers/aud/audrealtime/thread.c 1970-01-01 01:00:00.000000000 +0100
+++ aud_linux/drivers/aud/audrealtime/thread.c 2007-04-10 20:49:27.000000000 +0200
@@ -0,0 +1,209 @@
+/*
+ * rtime/audrealtime/thread.c
+ *
+ * 2007-19-01: Karl-Heinz.Krause@siemens.com
+ * Copyright (c) 2007 Siemens AG
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * This file contains all the thread management functions needed of the RT domain
+ *
+ */
+
+
+#include "../include/rt_timer.h"
+
+void rt_mark_exit_pending(struct task_struct *);
+int rt_reschedule(struct task_struct *);
+fastcall NORET_TYPE void do_exit(long);
+int rt_notification(struct task_struct *);
+void rt_delete_timer_notification(void);
+void rt_delete_event_notification(int);
+
+
+
+struct task_struct * rt_find_task_by_pid(pid_t pid)
+{
+ task_t *proc = NULL;
+ struct list_head *lp, *head;
+
+ head = &aud_rt_hdr.rt_tl;
+ lp = head->next;
+ while(lp != head)
+ {
+ proc = (task_t*)list_entry(lp, task_t, rt_pid_list );
+ if (pid == proc->pid)
+ break;
+ proc = NULL;
+ lp = lp->next;
+ }
+ return proc;
+}
+
+/*
+ * just to centralize for all that calling places where the lock is not already taken
+ */
+
+struct task_struct * rt_find_task_by_pid_lock(pid_t pid)
+{
+ struct task_struct *p;
+
+ down_rt(&aud_rt_hdr.rt_tl_sem);
+ p = rt_find_task_by_pid(pid);
+ up_rt(&aud_rt_hdr.rt_tl_sem);
+ return p;
+}
+
+/*
+ * A thread calls either pthread_exit() or exit()
+ * Both calls are routed to Linux, from there all exit handling will take place
+ */
+asmlinkage long sys_rt_exit(int error_code)
+{
+ if (RT_SHUTDOWN_VERBOSE)
+ printkGen("pid: %d called exit in RT \n", current->pid );
+ return do_rt_leave(); // re-executed in the Linux domain
+}
+
+asmlinkage long sys_rt_exit_group(int error_code)
+{
+ if (RT_SHUTDOWN_VERBOSE)
+ printkGen("pid: %d called exit_group in RT \n", current->pid);
+ return do_rt_leave(); // re-executed in the Linux domain
+}
+
+asmlinkage long sys_rt_getpid(void)
+{
+ return aud_lx_tgid;
+}
+
+asmlinkage long sys_rt_getuid(void)
+{
+ return current->uid;
+}
+
+
+asmlinkage long sys_rt_gettid(void)
+{
+ return current->pid;
+}
+
+/*
+ * This routine locks the realtime thread list (aud_rt_hdr.rt_tl_sem) and looks it up. If found the realtime thread list
+ * stays locked. If not found the realtime thread list is released and execution propagated to the Linux domain. In this case the
+ * caller must return, so that the system call execution can get repeated in the Linux domain
+ */
+
+struct task_struct * rt_get_task_locked(pid_t pid)
+{
+ struct task_struct *p;
+
+ down_rt(&aud_rt_hdr.rt_tl_sem);
+ if (current->pid == pid)
+ return current; // most frequent case (for priority ceiling)
+ if ((p = rt_find_task_by_pid(pid)) == NULL)
+ {
+ up_rt(&aud_rt_hdr.rt_tl_sem);
+ execute_in_lx(); // retry call in the Linux domain
+ }
+ return p;
+}
+
+
+
+long rt_do_setscheduler(pid_t pid, int policy, struct sched_param __user *param)
+{
+ struct sched_param lp;
+ struct task_struct *p;
+ int prio;
+
+ if (copy_from_user(&lp, param, sizeof(struct sched_param)))
+ return -EFAULT;
+ if ((lp.sched_priority < 1)||(lp.sched_priority > (MAX_USER_RT_PRIO - 1)))
+ return -EINVAL;
+
+ if ((p = rt_get_task_locked(pid)) == NULL) // task not in realtime thread list
+ return 0; // execute the call in the Linux domain
+ if (policy != -1)
+ {
+ if (!((policy == SCHED_FIFO)||(policy == SCHED_RR)))
+ {
+ up_rt(&aud_rt_hdr.rt_tl_sem);
+ return -EINVAL;
+ }
+ p->policy = policy;
+ }
+ prio = MAX_USER_RT_PRIO-1 - lp.sched_priority;
+ if (prio >= MAX_NO_OF_RT_PRIO)
+ { // thread should migrate the call doesn't get executed
+ if (rt_notification(p))
+ { // can't migrate, there are notifications for this thread
+ up_rt(&aud_rt_hdr.rt_tl_sem);
+ return -EINVAL;
+ }
+ list_del_init(&p->rt_pid_list); // prepare for migration, thread cannot be found anymore,
+ } // therefore no new notification can be created
+
+ up_rt(&aud_rt_hdr.rt_tl_sem);
+ if (p->tgid == aud_rt_hdr.tgid_rt)
+ { // thread currently executes in the realtime domain
+ p->prio = prio; // only prio is used, so we don't have
+ p->rt_priority = lp.sched_priority; // an atomicity problem
+ return rt_reschedule(p);
+ }
+ if (RT_FAULT_VERBOSE)
+ printkGen("Tried to change prio during call execution of RT thread in LX\n");
+ return 0; // for the time being
+}
+
+asmlinkage long sys_rt_sched_setparam(pid_t pid, struct sched_param __user *param)
+{
+ return rt_do_setscheduler(pid, -1, param);
+}
+
+asmlinkage long sys_rt_sched_setscheduler(pid_t pid, int policy, struct sched_param __user *param)
+{
+ return rt_do_setscheduler(pid, policy, param);
+}
+
+asmlinkage long sys_rt_sched_getparam(pid_t pid, struct sched_param __user *param)
+{
+ struct sched_param lp;
+ struct task_struct *p;
+
+ if ((p = rt_get_task_locked(pid)) == NULL)
+ return 0; // execute the call in the Linux domain
+ lp.sched_priority = p->rt_priority;
+ up_rt(&aud_rt_hdr.rt_tl_sem);
+ return copy_to_user(param, &lp, sizeof(struct sched_param));
+}
+
+asmlinkage long sys_rt_sched_getscheduler(pid_t pid)
+{
+ struct task_struct *p;
+ int policy;
+
+ if ((p = rt_get_task_locked(pid)) == NULL)
+ return 0; // execute the call in the Linux domain
+ policy = p->policy;
+ up_rt(&aud_rt_hdr.rt_tl_sem);
+ return policy;
+}
+
+
+
+
+
diff -N -a -u -r linux-2.6.15.4/drivers/aud/include/auddriver.h aud_linux/drivers/aud/include/auddriver.h
--- linux-2.6.15.4/drivers/aud/include/auddriver.h 1970-01-01 01:00:00.000000000 +0100
+++ aud_linux/drivers/aud/include/auddriver.h 2007-04-10 20:49:27.000000000 +0200
@@ -0,0 +1,93 @@
+#ifndef AUDDRIVER_H_
+#define AUDDRIVER_H_
+
+/*
+ * All definition needed when writing a dual domain driver
+ */
+
+#define RT_IO_READ 1
+#define RT_IO_WRITE 2
+#define RT_IO_IOCTL 4
+#define RT_IO_ALLOWED (RT_IO_READ | RT_IO_WRITE | RT_IO_IOCTL)
+
+struct rt_io_acc {
+ int allowed_calls;
+ struct file *filp;
+};
+
+int rt_allow_access(struct file *, int);
+int rt_register_notify(void(*)(int));
+int rt_unregister_notify(void(*)(int));
+
+int rt_request_irq(unsigned int,
+ irqreturn_t (*)(int, void *, struct pt_regs *), unsigned long,
+ const char *, void *, int (*)(int, void *, struct pt_regs *));
+void rt_free_irq(int);
+int execute_nonrt_handler(int);
+
+/*
+ * All definitions needed for a driver which needs to do IO-event signalling
+ */
+
+#define EV_EMPTY 0
+#define EV_BUSY 1
+#define EV_REGISTERED 2
+
+#define RT_EVAR_BITS 8 // index range for evar index
+#define RT_EVAR_SIZE (1 << RT_EVAR_BITS)
+#define RT_EVAR_MASK (RT_EVAR_SIZE -1)
+#define RT_EVAR_MAX 16
+
+#define RT_EV_BITS 4 // index range for eventid
+#define RT_EV_SIZE (1 << RT_EV_BITS) // max number of events for a device
+#define RT_EV_MASK (RT_EV_SIZE - 1)
+#define EVSIG_ISR 1 // event is going to be fired from ISR level
+#define EVSIG_THREAD 2 // event is going to be fired from thread level
+
+
+struct ev_entry {
+ eventid_t event;
+ int attr;
+ unsigned long src_1;
+ unsigned long src_2;
+};
+
+/*
+ * All definitions needed for a driver which does event signalling
+ */
+
+int rt_init_event_area (struct ev_entry *, int);
+int rt_register_event(int, struct rt_ev_desc *);
+int rt_send_event(int, int);
+void rt_destroy_event_area(int);
+int rt_delete_events(int);
+
+
+/*
+ * All definitions needed for a driver which needs to register a sync clock
+ */
+
+int rt_register_sync_clock(struct file*, int, void(**)(void));
+int rt_unregister_sync_clock(struct file*);
+
+int printkGen(char *format, ...);
+
+// sleeping rt task: state TASK_UNINTERRUPTIBLE
+// (intermediate: RT_TASK_UNINTERRUPTIBLE)
+// running rt task: state TASK_UNINTERRUPTIBLE | RT_TASK_RUNNING
+// state RT_TASK_RUNNING
+// (intermediate: RT_TASK_UNINTERRUPTIBLE | RT_TASK_RUNNING)
+// the intermediate state RT_TASK_UNINTERRUPTIBLE changes to
+// TASK_UNINTERRUPTIBLE in rt_schedule()
+
+#define RT_STATE_BASE 0x10000 // base for additional states of p->state
+#define RT_TASK_RUNNING (RT_STATE_BASE << 0)
+#define RT_EXIT_PENDING (RT_STATE_BASE << 1)
+#define RT_MIGRATION_PENDING (RT_STATE_BASE << 2)
+#define RT_TASK_UNINTERRUPTIBLE (RT_STATE_BASE << 3)
+
+#define THREAD_IS_LINUX (!(current->state & (RT_TASK_RUNNING | RT_TASK_UNINTERRUPTIBLE)))
+#define THREAD_IS_REALTIME (current->state & (RT_TASK_RUNNING | RT_TASK_UNINTERRUPTIBLE))
+
+#endif /*AUDDRIVER_H_*/
+
diff -N -a -u -r linux-2.6.15.4/drivers/aud/include/clock_dev.h aud_linux/drivers/aud/include/clock_dev.h
--- linux-2.6.15.4/drivers/aud/include/clock_dev.h 1970-01-01 01:00:00.000000000 +0100
+++ aud_linux/drivers/aud/include/clock_dev.h 2007-04-10 20:49:27.000000000 +0200
@@ -0,0 +1,11 @@
+#ifndef CLOCK_DEV_H_
+#define CLOCK_DEV_H_
+
+#define AuD_DEV_SPECIFIC_BASE 0xc000
+#define TEST_START_SYNC_CLOCK (AuD_DEV_SPECIFIC_BASE + 0x00)
+#define TEST_STOP_SYNC_CLOCK (AuD_DEV_SPECIFIC_BASE + 0x01)
+#define TEST_START_EVENTS (AuD_DEV_SPECIFIC_BASE + 0x02)
+#define TEST_STOP_EVENTS (AuD_DEV_SPECIFIC_BASE + 0x03)
+
+
+#endif /*CLOCK_DEV_H_*/
diff -N -a -u -r linux-2.6.15.4/drivers/aud/include/rt_base.h aud_linux/drivers/aud/include/rt_base.h
--- linux-2.6.15.4/drivers/aud/include/rt_base.h 1970-01-01 01:00:00.000000000 +0100
+++ aud_linux/drivers/aud/include/rt_base.h 2007-04-16 21:37:26.000000000 +0200
@@ -0,0 +1,129 @@
+#ifndef RT_BASE_H_
+#define RT_BASE_H_
+
+#define INLINE inline
+#define _INT64 long long
+
+#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS)
+# define MODVERSIONS /* erzwingen */
+#endif
+
+#ifdef MODVERSIONS
+//# include <linux/modversions.h>
+#endif
+
+
+#include <linux/kernel.h>
+#include <asm-generic/errno-base.h>
+#include <linux/list.h>
+#include <linux/pid.h>
+#include <asm/processor.h>
+#include <asm/mmu_context.h>
+#include <asm/bitops.h>
+#include <linux/types.h>
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <asm/uaccess.h>
+#include <linux/signal.h>
+#include <asm/signal.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <asm/semaphore.h>
+#include <linux/time.h>
+#include <linux/futex.h>
+#include <linux/linkage.h>
+#include <linux/mm.h>
+#include <linux/mqueue.h>
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+
+#ifdef CONFIG_I386
+#include <asm/ldt.h>
+#endif
+#include <asm/processor.h>
+#ifdef CONFIG_I386
+#include <asm/i387.h>
+#include <asm/desc.h>
+#endif
+
+void kfree(const void *memPtr);
+#define KMALLOC kmalloc
+#define KFREE kfree
+
+
+#include "rt_semaphore.h"
+#include "rtime_kernel.h"
+#include "auddriver.h"
+
+#define IS_HARD_REALTIME_PROCESS(p) ((aud_rt_hdr.state == RT_INSTALLED) && (p->tgid == aud_lx_tgid))
+#define MAX_NO_OF_RT_PRIO 32
+#define AuD_REALTIME_PRIO(p) (p->prio < MAX_NO_OF_RT_PRIO)
+
+#define RT_EXEC 2
+#define LX_EXEC 1
+#define RT_DOMAIN (get_exec_domain() == RT_EXEC)
+#define LX_DOMAIN (get_exec_domain() == LX_EXEC)
+
+#define IRQ_RT_EXCLUSIVE IPIPE_WIRED_MASK
+
+#define NO_OF_FU_REQUESTS 64
+
+typedef struct runqueue runqueue_t;
+
+struct rq_head {
+ struct list_head qhead;
+ int idx;
+};
+
+struct runqueue {
+ unsigned intFlag;
+ unsigned long nr_running;
+ unsigned long bitmapPrio;
+ spinlock_t lock;
+ struct rq_head queue[32];
+};
+
+/*
+ * This structure holds all the setup parameters for the realtime system
+ * It gets initialized with default values, but may be overriden later via
+ * an ioctl(,AuD_DEV_RT_PARAM, )
+ */
+
+struct rt_config_par {
+ int max;
+ int val;
+ int min;
+};
+
+typedef struct rt_config_par confpar_t;
+
+struct rt_config_cntrl {
+ confpar_t no_of_timers;
+ confpar_t no_of_sigq;
+ confpar_t no_of_headers;
+ confpar_t no_of_fu_req; // for delegating futex_wake requests to Linux;
+ confpar_t buf_size; // buffer size for delegated write calls
+ confpar_t md_prio; // prio of the migration_to_rt daemon
+ confpar_t td_prio; // prio of the timeout daemon of the realtime domain
+ confpar_t dd_prio; // prio of the delegation daemon futex, other syscalls
+ confpar_t cd_prio; // prio of clock sync daemon for Linux
+ confpar_t ed_prio; // prio of event proxy daemon for Linux
+};
+
+#define RT_FUTEX_VERBOSE (aud_diagnostic & RT_FUTEX_VERBOSE_BIT)
+#define RT_INIT_VERBOSE (aud_diagnostic & RT_INIT_VERBOSE_BIT)
+#define RT_SHUTDOWN_VERBOSE (aud_diagnostic & RT_SHUTDOWN_VERBOSE_BIT)
+#define RT_CHECK_VERBOSE (aud_diagnostic & RT_CHECK_VERBOSE_BIT)
+#define RT_THREAD_VERBOSE (aud_diagnostic & RT_THREAD_VERBOSE_BIT)
+#define RT_WRITE_VERBOSE (aud_diagnostic & RT_WRITE_VERBOSE_BIT)
+#define RT_TIMER_VERBOSE (aud_diagnostic & RT_TIMER_VERBOSE_BIT)
+#define RT_EVENT_VERBOSE (aud_diagnostic & RT_EVENT_VERBOSE_BIT)
+#define RT_MIGRATE_VERBOSE (aud_diagnostic & RT_MIGRATE_VERBOSE_BIT)
+#define RT_FAULT_VERBOSE (aud_diagnostic & RT_FAULT_VERBOSE_BIT)
+#define RT_SYSCALL_VERBOSE (aud_diagnostic & RT_SYSCALL_VERBOSE_BIT)
+#define AUD_DEV_VERBOSE (aud_diagnostic & AUD_DEV_VERBOSE_BIT)
+#define RT_EXCEPTION_VERBOSE (aud_diagnostic & RT_EXCEPTION_VERBOSE_BIT)
+#endif /*RT_BASE_H_*/
diff -N -a -u -r linux-2.6.15.4/drivers/aud/include/rt_buffer.h aud_linux/drivers/aud/include/rt_buffer.h
--- linux-2.6.15.4/drivers/aud/include/rt_buffer.h 1970-01-01 01:00:00.000000000 +0100
+++ aud_linux/drivers/aud/include/rt_buffer.h 2007-04-10 20:49:27.000000000 +0200
@@ -0,0 +1,96 @@
+#ifndef BUFFER_RT_H_
+#define BUFFER_RT_H_
+
+
+#define BUFLEN 4096
+
+#define BUF_EMPTY 0
+#define BUF_REQUESTED 1
+#define BUF_FILLED 2
+
+#define PROP_STD_OUT 1
+#define PROP_STD_ERR 2
+#define PROP_STD_KERNEL 3
+#define PROP_ERROR_KERNEL 4
+#define PROP_KERNEL_DEFAULT 10
+
+#define FU_EMPTY 0
+#define FU_FILLED 1
+
+#define NO_OF_ORDERS 7
+
+
+
+/* buf_head contains only the items needed for buffer management.
+ * All other information e.g. an additional length value is
+ * type specific. (The additional length value is only needed for character buffers
+ * because of rounded up size of a buffer
+ */
+
+struct buf_head {
+ struct buf_head *link;
+ int state;
+ int overrun;
+ int type;
+};
+
+/*
+ * stdout / stderr specific header
+ */
+
+struct buf_std_info {
+ struct buf_head buffHead; // must always be first see above
+ int len;
+ char info[1];
+};
+
+/*
+ * kernel call specific header
+ */
+#define RT_KERNEL_REQU_START 1
+#define RT_KERNEL_REQU_LINUX 2
+#define RT_KERNEL_REQU_USER 3
+#define RT_KERNEL_REQU_DONE 15
+
+struct buf_kernel_ret_info {
+ unsigned kernelReplyState;
+ int kernelReply;
+ unsigned internalA;
+ unsigned internalB;
+};
+
+#define MAX_KERNEL_ARG 6
+struct buf_kernel_info {
+ struct buf_head buffHead; // must always be first see above
+ int len;
+ int kernelRequestNr;
+ int kernelReply;
+ struct buf_kernel_ret_info *kernelRetDescr;
+ unsigned arg[MAX_KERNEL_ARG];
+};
+
+/* message element for stdout, stderr visible at the user level.
+ * With the exception of the overrun element which must be
+ * visible also at the user level, nothing of the buffer managment is visible.
+ */
+
+struct msg_head {
+ int overrun;
+ int type;
+ int length;
+};
+
+
+/*
+ * A futex order contains all possible elements,
+ * although for FUTEX_WAKE only uaddr and val are needed
+ */
+struct fu_order {
+ int state;
+ unsigned callId;
+ unsigned orderArgs[MAX_KERNEL_ARG];
+};
+
+
+
+#endif /*BUFFER_RT_H_*/
diff -N -a -u -r linux-2.6.15.4/drivers/aud/include/rtime_internal2.h aud_linux/drivers/aud/include/rtime_internal2.h
--- linux-2.6.15.4/drivers/aud/include/rtime_internal2.h 1970-01-01 01:00:00.000000000 +0100
+++ aud_linux/drivers/aud/include/rtime_internal2.h 2007-04-10 20:49:27.000000000 +0200
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2005 by Siemens AG, AD ATS 11, 90327 Nuernberg, Germany,
+ * Manfred.Neugebauer@siemens.com, 16-Feb-2005
+ *
+ * common definitions for the interface between kernel / driver and library
+ * to support the AuD API driver related functions
+ * (realtime, synchronous timer, events)
+ *
+ * file "rtime_internal2.h"
+ *
+ */
+
+#ifndef _RTIME_INTERNAL2_H_
+#define _RTIME_INTERNAL2_H_
+
+#define SIGTIMER __SIGRTMIN // T B D: who needs this: khk driver => move to rtime_kernel.h?
+
+/* ioctls for the aud device driver */
+#define AuD_Dev_IOCTL_BASE 0x8000
+#define AuD_REGISTER_PROCESS (AuD_Dev_IOCTL_BASE + 0x00)
+#define AuD_UNREGISTER_PROCESS (AuD_Dev_IOCTL_BASE + 0x01)
+#define AuD_PROBE_REALTIME (AuD_Dev_IOCTL_BASE + 0x02)
+#define AuD_IS_REALTIME (AuD_Dev_IOCTL_BASE + 0x03)
+#define AuD_DEV_RT_PARAM (AuD_Dev_IOCTL_BASE + 0x04)
+#define AuD_REGISTER_AND_PROBE_REALTIME (AuD_Dev_IOCTL_BASE + 0x05)
+#define AuD_TEST_RT (AuD_Dev_IOCTL_BASE + 0x06)
+#define AuD_SET_DIAGNOSIS (AuD_Dev_IOCTL_BASE + 0x07)
+#define AuD_GET_VERSION (AuD_Dev_IOCTL_BASE + 0x08)
+
+/* definitions of ioctl to handle device based API extensions (synch timer, events) */
+#define AuD_API_IOCTL_BASE 0x44410000
+#define AuD_REGISTER_CLOCK (AuD_API_IOCTL_BASE + 0x08)
+#define AuD_EVENT_CREATE (AuD_API_IOCTL_BASE + 0x09)
+#define AuD_EVENT_SET_PAR (AuD_API_IOCTL_BASE + 0x0a)
+
+struct rt_clock_desc {
+ int clock_type;
+ struct timespec clock_res;
+};
+
+struct rt_ev_desc {
+ unsigned event;
+ sigevent_t sigevent;
+};
+
+#define SIGEV_SIGNAL_SV_MAGIC 0x5f6e7d00
+
+// T B D: separate events for Linux and/or realtime?
+
+struct rt_config {
+ int no_of_timers;
+ int no_of_sigq;
+ int no_of_headers;
+ int no_of_fu_req; // for delegating futex_wake requests to Linux;
+ int buf_size; // buffer size for delegated write calls
+ int md_prio; // prio of the migration_to_rt daemon
+ int td_prio; // prio of the timeout daemon of the realtime domain
+ int dd_prio; // prio of the delegation daemon futex, other syscalls
+ int cd_prio; // prio of clock sync daemon for Linux
+ int ed_prio; // prio of event proxy daemon for Linux
+};
+
+struct exec_rt_kernel {
+ unsigned version;
+ unsigned exec_flags;
+};
+
+struct aud_version {
+ unsigned version_rt;
+ unsigned version_dev;
+};
+
+struct aud_diag {
+ unsigned diag_rt;
+ unsigned diag_dev;
+};
+
+/* diagnostic flags for aud device and realtime driver */
+#define RT_FUTEX_VERBOSE_BIT 0x001
+#define RT_WRITE_VERBOSE_BIT 0x002
+#define RT_INIT_VERBOSE_BIT 0x004
+#define RT_SHUTDOWN_VERBOSE_BIT 0x008
+#define RT_CHECK_VERBOSE_BIT 0x010
+#define RT_THREAD_VERBOSE_BIT 0x020
+#define RT_TIMER_VERBOSE_BIT 0x040
+#define RT_EVENT_VERBOSE_BIT 0x080
+#define RT_MIGRATE_VERBOSE_BIT 0x100
+#define RT_FAULT_VERBOSE_BIT 0x200
+#define RT_SYSCALL_VERBOSE_BIT 0x400
+#define AUD_DEV_VERBOSE_BIT 0x800
+#define RT_EXCEPTION_VERBOSE_BIT 0x1000
+
+#endif //_RTIME_INTERNAL2_H_
diff -N -a -u -r linux-2.6.15.4/drivers/aud/include/rtime_internal.h aud_linux/drivers/aud/include/rtime_internal.h
--- linux-2.6.15.4/drivers/aud/include/rtime_internal.h 1970-01-01 01:00:00.000000000 +0100
+++ aud_linux/drivers/aud/include/rtime_internal.h 2007-04-10 20:49:27.000000000 +0200
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2004 by Siemens AG, AD ATS 11, 90327 Nuernberg, Germany,
+ * Manfred.Neugebauer@siemens.com, 23-Feb-2004
+ *
+ * These are the internal definitions to work with a realtime subsystem
+ *
+ * m.n. 24-Oct-2006: change in the real rt prios: the range from 68 to 99
+ * is distributed between RT_P16 to RT_P31
+ */
+
+#ifndef _RTIME_INTERNAL_H_
+#define _RTIME_INTERNAL_H_
+
+#define __RT_PRIORITY_MAX 99
+
+#define __LINUX_PRIORITY_MIN 0
+#define __LINUX_PRIORITY_DIST 3
+#define RT_P0 (__LINUX_PRIORITY_MIN + 0 * __LINUX_PRIORITY_DIST)
+#define RT_P1 (__LINUX_PRIORITY_MIN + 1 * __LINUX_PRIORITY_DIST)
+#define RT_P2 (__LINUX_PRIORITY_MIN + 2 * __LINUX_PRIORITY_DIST)
+#define RT_P3 (__LINUX_PRIORITY_MIN + 3 * __LINUX_PRIORITY_DIST)
+#define RT_P4 (__LINUX_PRIORITY_MIN + 4 * __LINUX_PRIORITY_DIST)
+#define RT_P5 (__LINUX_PRIORITY_MIN + 5 * __LINUX_PRIORITY_DIST)
+#define RT_P6 (__LINUX_PRIORITY_MIN + 6 * __LINUX_PRIORITY_DIST)
+#define RT_P7 (__LINUX_PRIORITY_MIN + 7 * __LINUX_PRIORITY_DIST)
+#define RT_P8 (__LINUX_PRIORITY_MIN + 8 * __LINUX_PRIORITY_DIST)
+#define RT_P9 (__LINUX_PRIORITY_MIN + 9 * __LINUX_PRIORITY_DIST)
+#define RT_P10 (__LINUX_PRIORITY_MIN + 10 * __LINUX_PRIORITY_DIST)
+#define RT_P11 (__LINUX_PRIORITY_MIN + 11 * __LINUX_PRIORITY_DIST)
+#define RT_P12 (__LINUX_PRIORITY_MIN + 12 * __LINUX_PRIORITY_DIST)
+#define RT_P13 (__LINUX_PRIORITY_MIN + 13 * __LINUX_PRIORITY_DIST)
+#define RT_P14 (__LINUX_PRIORITY_MIN + 14 * __LINUX_PRIORITY_DIST)
+#define RT_P15 (__LINUX_PRIORITY_MIN + 15 * __LINUX_PRIORITY_DIST)
+#define RT_P16 (__RT_PRIORITY_MAX - 31)
+#define RT_P17 (__RT_PRIORITY_MAX - 29)
+#define RT_P18 (__RT_PRIORITY_MAX - 27)
+#define RT_P19 (__RT_PRIORITY_MAX - 25)
+#define RT_P20 (__RT_PRIORITY_MAX - 23)
+#define RT_P21 (__RT_PRIORITY_MAX - 21)
+#define RT_P22 (__RT_PRIORITY_MAX - 19)
+#define RT_P23 (__RT_PRIORITY_MAX - 17)
+#define RT_P24 (__RT_PRIORITY_MAX - 15)
+#define RT_P25 (__RT_PRIORITY_MAX - 13)
+#define RT_P26 (__RT_PRIORITY_MAX - 11)
+#define RT_P27 (__RT_PRIORITY_MAX - 9)
+#define RT_P28 (__RT_PRIORITY_MAX - 7)
+#define RT_P29 (__RT_PRIORITY_MAX - 5)
+#define RT_P30 (__RT_PRIORITY_MAX - 3)
+#define RT_P31 (__RT_PRIORITY_MAX - 1)
+
+#define RT_PRIORITY_MIN RT_P16
+
+#define AuD_DRIVER_NAME "/dev/auddriver"
+
+/*
+ * The flags RT_SOFT and RT_HARD are used in ioctl and aud_rt_hdr.state.
+ * The remainder are flags in aud_rt_hdr.state only
+ */
+
+#define RT_SOFT 0x0010
+#define RT_HARD 0x0020
+
+#define RT_INSTALLED 0x0040
+#define RT_SHUTDOWN 0x0100
+#define RT_FAILED 0x0200
+#define RT_MASK (RT_SOFT | RT_HARD)
+/*
+ * special flag to wait for end of a real process within create_process_image()
+ */
+#define RT_WAIT_FOR_EXIT 0x4000
+
+/*
+ * prefered definitions of a set of realtime signals
+ */
+#define SIGRT0 (__SIGRTMIN + 8)
+#define SIGRT1 (__SIGRTMIN + 9)
+#define SIGRT2 (__SIGRTMIN + 10)
+#define SIGRT3 (__SIGRTMIN + 11)
+#define SIGRT4 (__SIGRTMIN + 12)
+#define SIGRT5 (__SIGRTMIN + 13)
+#define SIGRT6 (__SIGRTMIN + 14)
+#define SIGRT7 (__SIGRTMIN + 15)
+#define SIGRT8 (__SIGRTMIN + 16)
+#define SIGRT9 (__SIGRTMIN + 17)
+#define SIGRT10 (__SIGRTMIN + 18)
+#define SIGRT11 (__SIGRTMIN + 19)
+#define SIGRT12 (__SIGRTMIN + 20)
+#define SIGRT13 (__SIGRTMIN + 21)
+#define SIGRT14 (__SIGRTMIN + 22)
+#define SIGRT15 (__SIGRTMIN + 23)
+
+#define EXEC_T_STRUCT_VERSION 0x01072006
+
+typedef struct rt_exec_t_struct {
+ unsigned version;
+ unsigned exec_flags;
+} rt_exec_t;
+
+#define AuD_CLOCK_SYNC_TYPE 0x0008
+
+/* The final definition of this data type may look different.
+ * It'll be used for the event_create() function. */
+typedef unsigned int eventid_t;
+
+// from "asm-generic/siginfo.h" user segment
+// open issue: is '-8' a valid information?
+#define SI_IOEVENT (-8)
+#define si_eventid _sifields._timer._tid
+
+ // add on to siginfo.h for A&D API
+#define SIGEV_SIGNAL_SV (SIGEV_THREAD_ID | 0x10)
+ // end A&D API add on
+
+#endif //_RTIME_INTERNAL_H_
diff -N -a -u -r linux-2.6.15.4/drivers/aud/include/rtime_kernel.h aud_linux/drivers/aud/include/rtime_kernel.h
--- linux-2.6.15.4/drivers/aud/include/rtime_kernel.h 1970-01-01 01:00:00.000000000 +0100
+++ aud_linux/drivers/aud/include/rtime_kernel.h 2007-04-10 20:49:27.000000000 +0200
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2006 by Siemens AG, AD ATS 11, 90327 Nuernberg, Germany,
+ * Manfred.Neugebauer@siemens.com, 16-Feb-2005
+ *
+ * definitions for the kernel (realtime) driver interface to support
+ * the AuD API driver related functions
+ * (realtime, synchronous timer, events)
+ * ==> entry for the kernel and kernel drivers
+ *
+ * file "rtime_kernel.h"
+ *
+ */
+
+#ifndef RTIME_KERNEL_H_
+#define RTIME_KERNEL_H_
+
+/* we have common defines with rtime.h */
+#define __SIGRTMIN SIGRTMIN /* taken from the general definitions */
+#include "rtime_internal.h"
+/* we have common defines with rtime_lib.h */
+#include "rtime_internal2.h"
+
+/*
+ * auddriver.h contains the definitions a driver writer needs when exploiting the additional
+ * aud features register_clock(), event_create() provided by the moduel auddriver
+ */
+#include "auddriver.h"
+
+#endif /*RTIME_KERNEL_H_*/
diff -N -a -u -r linux-2.6.15.4/drivers/aud/include/rt_link.h aud_linux/drivers/aud/include/rt_link.h
--- linux-2.6.15.4/drivers/aud/include/rt_link.h 1970-01-01 01:00:00.000000000 +0100
+++ aud_linux/drivers/aud/include/rt_link.h 2007-04-10 20:49:27.000000000 +0200
@@ -0,0 +1,131 @@
+#ifndef RT_LINK_
+#define RT_LINK_
+
+ // request types for the do_execute_in_lx daemon
+#define EXEC_FUTEX_LX 1 // a futex operation must get executed by the daemon
+#define CHECK_NOTIFY 2 // the check triggers the waiting thread to continue
+ // if aud_rt_hdr.state != RT_INSTALLED the do_execute_in_lx daemon terminates
+
+#define USER_THREAD 0
+#define KERNEL_THREAD 1
+#define INITIAL_THREAD 2
+
+struct reg_proc {
+ struct list_head p_link;
+ unsigned long tgid;
+};
+
+/*
+struct proc_wait_queue {
+ struct list_head list;
+ struct task_struct *task;
+};
+*/
+struct lx_cmd { // command structure for delegation requests to Linux
+ struct list_head req_link;
+ int type; // so far EXEC_FUTEX_LX and CHECK_SETUP are defined
+ union {
+ struct task_struct *_proc;
+ struct fu {
+ unsigned long uaddr;
+ int op;
+ int val;
+ unsigned long uaddr2;
+ int val2;
+ int val3;
+ }_fuop;
+ }_req;
+};
+
+struct dom_hdr {
+ unsigned long state; // values in rtime_internal.h
+ struct semaphore setup_sm; // for coordinating the setup sequence
+ struct semaphore to_rt_op; // for protecting/serializing the migration to realtime operation
+ struct semaphore to_rt_sm; // for coordination with the migrate to realtime daemon
+ struct semaphore to_lx_sm; // for coordination with the migrate to Linux daemon
+ struct semaphore write_sm; // for coordination of the Linux printf daemon
+ struct semaphore dev_sem; // for serialization of auddevice functions
+ struct rt_semaphore rt_tl_sem; // for synchronizing notification channels with thread adds/deletes
+ spinlock_t to_lx_lock; // for locking the to_lx_list list operations
+ unsigned long tgid_rt; // It will be set to the pid of the first migrated user level thread
+ struct task_struct *rt_proc; // the process which registered with RT_HARD set
+ struct list_head rt_tl; // realtime task list for rt_find_task_by_pid
+ struct signal_struct *signal; // save location for pointer in struct task_struct;
+ unsigned long pid_wr; // pid of the Linux printf daemon
+ struct task_struct *to_rt_proc; // thread to get migrated to realtime
+ struct task_struct *timer_daemon; // the timer daemon is the first and the last thread
+ int td_prio;
+ struct task_struct *to_rt_daemon; // puts a thread waiting for migration into the realtime runqueue
+ int to_rt_prio;
+ struct task_struct *to_lx_daemon; // puts a thread waiting for migration into the Linux runqueue
+ int to_lx_prio;
+ struct list_head wake_lx_list; // list for threads to be woken up in Linux
+ struct list_head to_lx_list; // request list header for to_lx migration or futex operations
+ struct list_head free_list; // free list header for futex wake operations to be delegated
+ struct list_head reg_list; // threads which registered with RT_SOFT only will be queued temporarily
+ // reason: mlockall()doesn't survive an exec()
+
+};
+
+
+extern unsigned ex_lx_irq; // irq for notifying the linux daemon for futex and execution in Linux
+extern unsigned wr_lx_irq; // irq for notifying the linux thread for write buffer handling
+extern unsigned to_rt_irq; // irq for waking up the realtime domain;
+extern unsigned wake_up_lx_irq; // irq for functions which require only a wake_up_process and can therefore
+ // executed directly from ISR level
+extern struct dom_hdr aud_rt_hdr;
+extern unsigned long aud_lx_tgid;
+extern unsigned long aud_diagnostic;
+extern struct rt_link_desc *rtlpr;
+extern unsigned msg_count; //
+
+void rt_set_diagnosis(unsigned);
+int fastcall rt_send_sigqueue(struct notify *);
+int fastcall rt_send_alt_sigqueue(struct notify *);
+int rt_dequeue_sigq(struct sigqueue *);
+struct task_struct * rt_find_task_by_pid(int);
+int rt_register_clock(clockid_t, struct rtg_clock *);
+int rt_unregister_clock(clockid_t);
+int fastcall rt_wake_up_thread(void *);
+void fastcall rt_check_preemption(void);
+void fastcall rt_schedule(void);
+_INT64 rt_schedule_timeout(int, _INT64);
+void rt_enter_schedule(void);
+long do_rt_leave(void);
+int fastcall migrate_to_rt(int);
+asmlinkage void execute_in_lx(void);
+void rt_shutdown_realtime(void);
+int do_timer_rt(void*);
+int do_check_rt(void*);
+int do_execute_in_lx(void*);
+int do_migrate_to_rt(void*);
+void setup_internal_timer(struct itimer *, _INT64, int fastcall (*)(void *));
+int time_handling_rt(int, int, int);
+unsigned rt_get_exec_domain(void);
+
+void rt_delete_event_notification(int);
+void rt_delete_timer_notification(void);
+
+struct rt_link_desc {
+ unsigned rt_version;
+ int (*rt_register_clock)(clockid_t, struct rtg_clock *);
+ int (*rt_unregister_clock)(clockid_t);
+ int fastcall (*rt_send_sigqueue)(struct notify *);
+ int fastcall (*rt_send_alt_sigqueue)(struct notify *);
+ int (*rt_init_realtime)(void);
+ void (*rt_shutdown_realtime)(void);
+ int (*rt_dequeue_sigq)(struct sigqueue *nfb);
+ struct task_struct* (*rt_find_task_by_pid)(int);
+ int (*do_timer_rt)(void*);
+ int (*do_check_rt)(void*);
+ int (*do_migrate_to_rt)(void*);
+ int (*do_execute_in_lx)(void*);
+ void (*up_rt)(struct rt_semaphore *);
+ void (*down_rt)(struct rt_semaphore *);
+ int (*rt_read_buffer)(char *addr, int len);
+ int (*rt_write_buffered)(unsigned, void *, unsigned);
+ unsigned (*rt_get_exec_domain)(void);
+};
+
+
+#endif /*RT_LINK_*/
diff -N -a -u -r linux-2.6.15.4/drivers/aud/include/rt_semaphore.h aud_linux/drivers/aud/include/rt_semaphore.h
--- linux-2.6.15.4/drivers/aud/include/rt_semaphore.h 1970-01-01 01:00:00.000000000 +0100
+++ aud_linux/drivers/aud/include/rt_semaphore.h 2007-04-10 20:49:27.000000000 +0200
@@ -0,0 +1,33 @@
+#ifndef RT_SEMAPHORE_H_
+#define RT_SEMAPHORE_H_
+
+/*
+#ifdef APPL_SIM
+#define sema_init_rt sema_init
+#define up_rt up
+#define down_rt down
+#endif
+*/
+
+struct rt_wait {
+ struct list_head list;
+ struct task_struct *proc;
+};
+
+
+struct rt_wait_queue_head {
+ spinlock_t lock;
+ struct list_head list;
+};
+
+struct rt_semaphore {
+ int count;
+ int sleepers;
+ struct rt_wait_queue_head wait;
+};
+
+void up_rt(struct rt_semaphore *);
+void down_rt(struct rt_semaphore *);
+void sema_init_rt(struct rt_semaphore *, int);
+
+#endif /*RT_SEMAPHORE_H_*/
diff -N -a -u -r linux-2.6.15.4/drivers/aud/include/rt_timer.h aud_linux/drivers/aud/include/rt_timer.h
--- linux-2.6.15.4/drivers/aud/include/rt_timer.h 1970-01-01 01:00:00.000000000 +0100
+++ aud_linux/drivers/aud/include/rt_timer.h 2007-04-10 20:49:27.000000000 +0200
@@ -0,0 +1,168 @@
+#ifndef RT_TIMER_H_
+#define RT_TIMER_H_
+
+#include "rt_base.h"
+
+#include <linux/timex.h>
+#include <linux/timer.h>
+#include <linux/posix-timers.h>
+#include "sync_timer.h"
+
+#define POLL_TIME 20 // for checking if a task is out of the runqueue, should to be computed via ns per jiffy
+
+#define NS_IN_SEC 1000000000
+#define RT_TIMER_DELETED 0x80000000
+#define SI_LHDR 0xf0f0f0f0 // si_code distinction for list_hdr notification
+
+#define RT_TIME_SLICE 10
+
+#define RT_L1_BITS 5
+#define RT_L2_BITS 5
+#define RT_L1_SIZE (1 << RT_L1_BITS)
+#define RT_L2_SIZE (1 << RT_L2_BITS)
+#define RT_L1_MASK (RT_L1_SIZE - 1)
+#define RT_L2_MASK (RT_L2_SIZE - 1)
+#define RT_L1L2_MASK ((RT_L2_MASK << RT_L1_BITS) | RT_L1_MASK)
+
+
+struct posix_timer;
+
+struct sync_clock_hdr {
+ int act_cnt; // for not losing a tick only needed for Linux proxy threads
+ int res;
+ _INT64 clock_val;
+ clockid_t clockid;
+ struct file* fp;
+ struct list_head active_list;
+ struct list_head pending_list;
+ void (*rt_clock_isr)(void);
+ void (*lx_clock_isr)(void);
+ struct task_struct *proc; // proxy thread for Linux
+
+};
+
+
+struct notify {
+ int cycle; // for timeliness control
+ int sigev_notify; // notify word of sigevent struct
+ int notify_overrun; // overrun on pending signal
+ struct task_struct *thread;
+ struct task_struct *alt_thread; // alternative thread the signal has to be sent to
+ struct sigqueue sigq;
+};
+
+/* rt_list headers are the anchors for active CLOCK_REALTIME timers . This architecture allows for best possible
+ real time and performance behavior
+*/
+struct rt_list_hdr {
+ struct list_head hdr_link;
+ _INT64 clock_val; // jiffies at first thread activation (run_cnt 0 ->1)
+ int run_cnt; // tells how often the list header must get executed at thread level
+
+ struct list_head overflow_list;
+ struct list_head l2_list[RT_L2_SIZE];
+ struct list_head l1_list[RT_L1_SIZE];
+ int fastcall (*notification) (void *); // either rt_send_sigqueue() or rt_wake_up_thread()
+ void *notification_par; // either thread to be woken up or - when sending a signal -- &rt_notify
+ struct notify rt_notify; // in case notification is done via sending a signal;
+};
+
+ /* internal interval timer structure optimized for the RT domain
+ */
+
+struct itimer {
+ struct list_head it_link;
+ union {
+ int it_delay; // delay specified in jiffies for sync timers
+ _INT64 activation_time; // specified in jiffies for CLOCK_REALTIME timers
+ }fire;
+ unsigned long it_incr; // period specified in jiffies
+ unsigned flags; // TIMER_ABSTIME is the only flag;
+ int fastcall (*timer_action) (void *);
+ void *action_par; // address notification element or -- for internal timers - process to be notified ;
+ struct rt_list_hdr *lhdr; // address of rt_list_hdr, where to insert when a timer becomes active
+};
+
+
+/*
+ * POSIX interval timer structure optimized for the RT domain with a notification component
+ * also used for IO-events
+ */
+
+struct posix_timer {
+ struct list_head it_link; // timer linked either in free_list, created_list
+ _INT64 insert_offset;
+ clockid_t it_clock;
+ timer_t it_id;
+ int it_state; // DELETED is the only state
+ struct itimer itmr;
+ struct notify rt_notify; // uniform notification component
+};
+
+
+struct posix_timer_pool {
+ struct rt_semaphore sem;
+ struct list_head available_timer;
+ struct list_head created_timer;
+ struct list_head available_list_hdr;
+ int max_timer;
+ int used_timer;
+ int id_count;
+ unsigned *bitmap;
+ struct posix_timer **tmr_map;
+};
+
+struct rtg_clock {
+ int res;
+ _INT64 clock_val; // in jiffies
+ _INT64 offset; // delta time resulting from clock_settime call
+ int (*clock_set) (clockid_t clockid, struct timespec * tp);
+ int (*clock_get) (clockid_t clockid, struct timespec * tp);
+ int (*nsleep) (clockid_t clockid, int flags, struct timespec * new_setting);
+ int (*timer_set) (struct posix_timer *, int flags, struct itimerspec * new_setting, struct itimerspec * old_setting);
+ int (*timer_del) (struct posix_timer * );
+ void (*timer_get) (struct posix_timer *, struct itimerspec * cur_setting);
+ int (*timer_setup) (struct posix_timer *, sigevent_t *); // if additional setup such as list_hdr is required
+};
+
+
+/*
+ * Converts the external representation to an internal 64-Bit representation in entities of clock ticks.
+ * Returns zero if okay or a negative value in case of a fault or an invalid time specification
+*/
+
+static INLINE long convert_to_internal(int res, _INT64 *itr, struct timespec *tpr)
+{
+ int tv_nsec = tpr->tv_nsec;
+ _INT64 rt_jiffies = tpr->tv_sec;
+
+ if (((unsigned)tv_nsec >= NS_IN_SEC)||(tpr->tv_sec < 0))
+ return -EINVAL;
+ rt_jiffies = rt_jiffies * NS_IN_SEC + tv_nsec + res - 1;
+ do_div(rt_jiffies, res);
+ *itr = rt_jiffies;
+ return(0);
+}
+
+/*
+ * Converts the internal 64-Bit representation in entities of clock ticks to the external
+ * (POSIX) representation. In case internal representation is not read atomically,
+ * repeating takes care of it.
+ */
+
+static INLINE long convert_to_external(int res, _INT64 *itr, struct timespec *tpr)
+{
+ _INT64 timeval;
+
+ do { // handling the time window if no atomic 64-bit read
+ timeval = *itr;
+ }while (timeval != *itr);
+ timeval *= res;
+ tpr->tv_nsec = do_div(timeval, NS_IN_SEC);
+ tpr->tv_sec = timeval;
+ return(0);
+}
+
+#include "rt_link.h"
+#endif /*RT_TIMER_H_*/
+
diff -N -a -u -r linux-2.6.15.4/drivers/aud/include/sync_timer.h aud_linux/drivers/aud/include/sync_timer.h
--- linux-2.6.15.4/drivers/aud/include/sync_timer.h 1970-01-01 01:00:00.000000000 +0100
+++ aud_linux/drivers/aud/include/sync_timer.h 2007-04-10 20:49:27.000000000 +0200
@@ -0,0 +1,30 @@
+struct lx_itimer { // needs to have the same size as Linux timer list
+ struct list_head it_link;
+ union {
+ int it_delay; // delay specified in jiffies */
+ _INT64 activation_time;
+ }fire;
+ void (*action) (void *);
+ void *action_par; // address of enclosing posix_timer;
+ struct rt_list_hdr *lhdr; // address of rt_list_hdr, where to insert when a timer becomes active
+};
+
+struct lp_itimer { // must be kongruent with Linux k_itimer
+ struct list_head list; /* free/ allocate list */
+ spinlock_t it_lock;
+ clockid_t it_clock; /* which timer type */
+ timer_t it_id; /* timer id */
+ int it_overrun; /* overrun on pending signal */
+ int it_overrun_last; /* overrun on last delivered signal */
+ int it_requeue_pending; /* waiting to requeue this timer */
+ int it_sigev_notify; /* notify word of sigevent struct */
+ int it_sigev_signo; /* signo word of sigevent struct */
+ sigval_t it_sigev_value; /* value word of sigevent struct */
+ struct task_struct *it_process; /* process to send signal to */
+ struct sigqueue *sigq; /* signal queue entry. */
+ struct lx_itimer itmr; /* this structure is different but must have the same size as timer_list*/
+ unsigned long it_incr; /* interval specified in jiffies */
+ struct list_head abs_timer_entry; /* clock abs_timer_list */
+// struct timespec wall_to_prev; /* wall_to_monotonic used when set */
+
+};
diff -N -a -u -r linux-2.6.15.4/drivers/aud/Kconfig aud_linux/drivers/aud/Kconfig
--- linux-2.6.15.4/drivers/aud/Kconfig 1970-01-01 01:00:00.000000000 +0100
+++ aud_linux/drivers/aud/Kconfig 2007-04-10 20:49:27.000000000 +0200
@@ -0,0 +1,35 @@
+#
+# driver configuration for AuD Realtime Support
+# m.n. Siemens AG AD ATS 11 18-April-2006
+#
+
+
+menu "AuD Realtime support"
+
+config AuD_BASE_REALTIME
+ tristate "AuD basic realtime support"
+ depends on RTX_DOMAIN
+ ---help---
+ This option enables the general driver support
+ for the AuD Realtime extensions within Linux.
+ You have to provide the device node: mknod /dev/auddriver c 220 0
+
+ If you want to have this support embedded into your kernel, say Y.
+ To compile this driver as a module, choose M here.
+
+ more information m.n. <Manfred.Neugebauer@siemens.com>
+
+config AuD_HARD_REALTIME
+ tristate "AuD hard realtime support"
+ depends on AuD_BASE_REALTIME
+ ---help---
+ This option enables the driver extensions for the
+ AuD hard realtime support within Linux
+
+ If you want to have this support embedded into your kernel, say Y.
+ To compile this driver as a module, choose M here.
+
+ more information m.n. <Manfred.Neugebauer@siemens.com>
+
+endmenu
+
diff -N -a -u -r linux-2.6.15.4/drivers/aud/Makefile aud_linux/drivers/aud/Makefile
--- linux-2.6.15.4/drivers/aud/Makefile 1970-01-01 01:00:00.000000000 +0100
+++ aud_linux/drivers/aud/Makefile 2007-04-10 20:49:27.000000000 +0200
@@ -0,0 +1,10 @@
+#
+# Makefile for the AuD Realtime drivers.
+#
+# 18-April-2006 m.n. Manfred.Neugebauer@siemens.com
+#
+
+obj-$(CONFIG_AuD_BASE_REALTIME) += auddevice/
+
+obj-$(CONFIG_AuD_HARD_REALTIME) += audrealtime/
+
diff -N -a -u -r linux-2.6.15.4/drivers/Kconfig aud_linux/drivers/Kconfig
--- linux-2.6.15.4/drivers/Kconfig 2006-02-10 08:22:48.000000000 +0100
+++ aud_linux/drivers/Kconfig 2007-04-10 20:49:27.000000000 +0200
@@ -66,4 +66,7 @@
source "drivers/sn/Kconfig"
+# m.n.
+source "drivers/aud/Kconfig"
+
endmenu
diff -N -a -u -r linux-2.6.15.4/drivers/Makefile aud_linux/drivers/Makefile
--- linux-2.6.15.4/drivers/Makefile 2006-02-10 08:22:48.000000000 +0100
+++ aud_linux/drivers/Makefile 2007-04-10 20:49:27.000000000 +0200
@@ -70,3 +70,4 @@
obj-y += firmware/
obj-$(CONFIG_CRYPTO) += crypto/
obj-$(CONFIG_SUPERH) += sh/
+obj-$(CONFIG_AuD_BASE_REALTIME) += aud/
\ Kein Zeilenumbruch am Dateiende.
diff -N -a -u -r linux-2.6.15.4/include/asm-i386/i387.h aud_linux/include/asm-i386/i387.h
--- linux-2.6.15.4/include/asm-i386/i387.h 2006-02-10 08:22:48.000000000 +0100
+++ aud_linux/include/asm-i386/i387.h 2007-04-10 20:49:27.000000000 +0200
@@ -70,6 +70,34 @@
/*
* These disable preemption on their own and are safe
*/
+
+#ifdef CONFIG_RTX_DOMAIN
+
+static inline void save_init_fpu( struct task_struct *tsk )
+{
+ asm volatile("pushfl\n\t" \
+ "cli\n\t");
+ __save_init_fpu(tsk);
+ stts();
+ asm volatile ("popfl");
+}
+
+#define unlazy_fpu( tsk ) do { \
+ asm volatile("pushfl\n\t" \
+ "cli\n\t"); \
+ __unlazy_fpu(tsk); \
+ asm volatile ("popfl"); \
+} while (0)
+
+#define clear_fpu( tsk ) do { \
+ asm volatile("pushfl\n\t" \
+ "cli\n\t"); \
+ __clear_fpu( tsk ); \
+ asm volatile ("popfl"); \
+} while (0)
+ \
+#else
+
static inline void save_init_fpu( struct task_struct *tsk )
{
preempt_disable();
@@ -90,12 +118,15 @@
preempt_enable(); \
} while (0)
\
+
+#endif /*CONFIG_RTX_DOMAIN */
/*
* FPU state interaction...
*/
extern unsigned short get_fpu_cwd( struct task_struct *tsk );
extern unsigned short get_fpu_swd( struct task_struct *tsk );
extern unsigned short get_fpu_mxcsr( struct task_struct *tsk );
+extern asmlinkage void math_state_restore(void);
/*
* Signal frame handlers...
diff -N -a -u -r linux-2.6.15.4/include/asm-i386/ipipe.h aud_linux/include/asm-i386/ipipe.h
--- linux-2.6.15.4/include/asm-i386/ipipe.h 2007-04-16 22:23:50.000000000 +0200
+++ aud_linux/include/asm-i386/ipipe.h 2007-04-10 20:49:27.000000000 +0200
@@ -17,6 +17,9 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * 2006-11-20: Karl-Heinz Krause Copyright (c) 2006 Siemens AG
+ * Support for fast dual domain system added
*/
#ifndef __I386_IPIPE_H
@@ -136,7 +139,15 @@
#define IPIPE_EVENT_SETSCHED (IPIPE_FIRST_EVENT + 3)
#define IPIPE_EVENT_EXIT (IPIPE_FIRST_EVENT + 4)
#define IPIPE_EVENT_CLEANUP (IPIPE_FIRST_EVENT + 5)
+
+#ifdef CONFIG_RTX_DOMAIN
+/* aud realtime: we need an event when leaving a system call */
+#define IPIPE_EVENT_SYSCALL_EX (IPIPE_FIRST_EVENT + 6)
+#define IPIPE_LAST_EVENT IPIPE_EVENT_SYSCALL_EX
+#else /* CONFIG_RTX_DOMAIN */
#define IPIPE_LAST_EVENT IPIPE_EVENT_CLEANUP
+#endif /* CONFIG_RTX_DOMAIN */
+
#define IPIPE_NR_EVENTS (IPIPE_LAST_EVENT + 1)
struct ipipe_domain;
diff -N -a -u -r linux-2.6.15.4/include/asm-i386/system.h aud_linux/include/asm-i386/system.h
--- linux-2.6.15.4/include/asm-i386/system.h 2007-04-16 22:23:50.000000000 +0200
+++ aud_linux/include/asm-i386/system.h 2007-04-10 20:49:27.000000000 +0200
@@ -11,23 +11,71 @@
struct task_struct; /* one of the stranger aspects of C forward declarations.. */
extern struct task_struct * FASTCALL(__switch_to(struct task_struct *prev, struct task_struct *next));
+
+
+#ifdef CONFIG_RTX_DOMAIN
#define switch_to(prev,next,last) do { \
unsigned long esi,edi; \
- asm volatile("pushl %%ebp\n\t" \
+ asm volatile("pushfl\n\t" /* save flags added from 2.6.20 */ \
+ "cli\n\t" /* rt_switch_to must not interrupt __switch_to, gets reset by popfl */ \
+ "pushl %%ebp\n\t" \
"movl %%esp,%0\n\t" /* save ESP */ \
"movl %5,%%esp\n\t" /* restore ESP */ \
"movl $1f,%1\n\t" /* save EIP */ \
"pushl %6\n\t" /* restore EIP */ \
"jmp __switch_to\n" \
"1:\t" \
+ "popl %%ebp\n\t" \
+ "popfl" /* added from 2.6.20 */ \
+ :"=m" (prev->thread.esp),"=m" (prev->thread.eip), \
+ "=a" (last),"=S" (esi),"=D" (edi) \
+ :"m" (next->thread.esp),"m" (next->thread.eip), \
+ "2" (prev), "d" (next)); \
+} while (0)
+
+#define rt_switch_to(prev,next,last) do { \
+ unsigned long esi,edi; \
+ asm volatile("pushfl\n\t" \
+ "pushl %%ebx\n\t" \
+ "pushl %%ecx\n\t" \
+ "pushl %%ebp\n\t" \
+ "movl %%esp,%0\n\t" /* save ESP */ \
+ "movl %5,%%esp\n\t" /* restore ESP */ \
+ "movl $1f,%1\n\t" /* save EIP */ \
+ "pushl %6\n\t" /* restore EIP */ \
+ "jmp __switch_to\n" \
+ "1:\t" \
"popl %%ebp\n\t" \
+ "popl %%ecx\n\t" \
+ "popl %%ebx\n\t" \
+ "popfl" \
:"=m" (prev->thread.esp),"=m" (prev->thread.eip), \
"=a" (last),"=S" (esi),"=D" (edi) \
:"m" (next->thread.esp),"m" (next->thread.eip), \
"2" (prev), "d" (next)); \
} while (0)
+#else
+
+#define switch_to(prev,next,last) do { \
+ unsigned long esi,edi; \
+ asm volatile("pushl %%ebp\n\t" \
+ "movl %%esp,%0\n\t" /* save ESP */ \
+ "movl %5,%%esp\n\t" /* restore ESP */ \
+ "movl $1f,%1\n\t" /* save EIP */ \
+ "pushl %6\n\t" /* restore EIP */ \
+ "jmp __switch_to\n" \
+ "1:\t" \
+ "popl %%ebp\n\t" \
+ :"=m" (prev->thread.esp),"=m" (prev->thread.eip), \
+ "=a" (last),"=S" (esi),"=D" (edi) \
+ :"m" (next->thread.esp),"m" (next->thread.eip), \
+ "2" (prev), "d" (next)); \
+} while (0)
+
+#endif /*CONFIG_RTX_DOMAIN */
+
#define _set_base(addr,base) do { unsigned long __pr; \
__asm__ __volatile__ ("movw %%dx,%1\n\t" \
"rorl $16,%%edx\n\t" \
@@ -56,6 +104,12 @@
#define set_base(ldt,base) _set_base( ((char *)&(ldt)) , (base) )
#define set_limit(ldt,limit) _set_limit( ((char *)&(ldt)) , ((limit)-1)>>12 )
+#ifdef CONFIG_RTX_DOMAIN
+
+#define rt_switch_mm(pgdir) load_cr3(pgdir)
+
+#endif /* CONFIG_RTX_DOMAIN */
+
static inline unsigned long _get_base(char * addr)
{
unsigned long __base;
diff -N -a -u -r linux-2.6.15.4/include/linux/mqueue.h aud_linux/include/linux/mqueue.h
--- linux-2.6.15.4/include/linux/mqueue.h 2006-02-10 08:22:48.000000000 +0100
+++ aud_linux/include/linux/mqueue.h 2007-04-10 20:49:27.000000000 +0200
@@ -1,55 +1,127 @@
-/* Copyright (C) 2003 Krzysztof Benedyczak & Michal Wronski
-
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- It is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with this software; if not, write to the Free
- Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
- 02111-1307 USA. */
+/* POSIX message queues definitions
+ *
+ * Author: Stefan Assmann (S.Assmann AT gmx DOT de)
+ * Copyright (c) 2007 Siemens AG
+ * last change: 2007-01-29
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
#ifndef _LINUX_MQUEUE_H
#define _LINUX_MQUEUE_H
-#include <linux/types.h>
-
-#define MQ_PRIO_MAX 32768
-/* per-uid limit of kernel memory used by mqueue, in bytes */
-#define MQ_BYTES_MAX 819200
+/* default values */
+#define DFLT_QUEUESMAX 256 /* dflt number of message queues */
+#define DFLT_MSGMAX 10 /* dflt max number of messages per queue*/
+ /* hard max number of messages per queue*/
+#define HARD_MSGMAX (131072/sizeof(void*))
+#define DFLT_MSGSIZEMAX 8192 /* dflt message size (bytes) */
+#define MQ_BYTES_MAX 819200 /* per uid limit of kernel mem (bytes) */
+#define MQ_PRIO_MAX 32 /* max number of priorities in system */
struct mq_attr {
long mq_flags; /* message queue flags */
long mq_maxmsg; /* maximum number of messages */
long mq_msgsize; /* maximum message size */
long mq_curmsgs; /* number of messages currently queued */
- long __reserved[4]; /* ignored for input, zeroed for output */
};
-/*
- * SIGEV_THREAD implementation:
- * SIGEV_THREAD must be implemented in user space. If SIGEV_THREAD is passed
- * to mq_notify, then
- * - sigev_signo must be the file descriptor of an AF_NETLINK socket. It's not
- * necessary that the socket is bound.
- * - sigev_value.sival_ptr must point to a cookie that is NOTIFY_COOKIE_LEN
- * bytes long.
- * If the notification is triggered, then the cookie is sent to the netlink
- * socket. The last byte of the cookie is replaced with the NOTIFY_?? codes:
- * NOTIFY_WOKENUP if the notification got triggered, NOTIFY_REMOVED if it was
- * removed, either due to a close() on the message queue fd or due to a
- * mq_notify() that removed the notification.
- */
-#define NOTIFY_NONE 0
-#define NOTIFY_WOKENUP 1
-#define NOTIFY_REMOVED 2
+struct mq_list {
+ struct list_head list;
+ size_t msgsize; /* size of message (chars) */
+ char msg[1]; /* -- the message -- */
+};
+
+struct proc_wait_queue { /* queue of sleeping tasks */
+ struct list_head list;
+ struct task_struct *task;
+ void (*do_wakeup) (struct proc_wait_queue *wait);
+};
-#define NOTIFY_COOKIE_LEN 32
+struct mqueue_inode_info {
+ unsigned long bitmap;
+ struct inode vfs_inode;
+ struct mq_attr attr;
+ struct user_struct *user;/* user who created, for accounting */
+ struct list_head send_wait;
+ struct list_head recv_wait;
+ struct list_head free_list;
+ struct list_head queues[MQ_PRIO_MAX];
+ wait_queue_head_t wait_q;
+ spinlock_t lock;
+ struct sigevent notify;
+ pid_t notify_owner;
+ struct sock *notify_sock;
+ struct sk_buff *notify_cookie;
+};
+/* inline prototypes */
+inline struct mqueue_inode_info *MQUEUE_I(struct inode *inode);
+inline void set_cookie(struct sk_buff *skb, char code);
+
+/* inode prototypes */
+struct inode *mqueue_alloc_inode(struct super_block *sb);
+int mqueue_create(struct inode *dir, struct dentry *dentry,
+ int mode, struct nameidata *nd);
+int mqueue_unlink(struct inode *dir, struct dentry *dentry);
+void mqueue_destroy_inode(struct inode *inode);
+void mqueue_delete_inode(struct inode *inode);
+ssize_t mqueue_read_file(struct file *filp, char __user *u_data,
+ size_t count, loff_t * off);
+int mqueue_fill_super(struct super_block *sb, void *data, int silent);
+struct inode *mqueue_get_inode(struct super_block *sb, int mode,
+ struct mq_attr *attr);
+struct super_block *mqueue_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name,
+ void *data);
+
+/* signaling prototypes */
+void __do_notify(struct mqueue_inode_info *info);
+void remove_notification(struct mqueue_inode_info *info);
+asmlinkage long sys_mq_notify(mqd_t mqdes,
+ const struct sigevent __user *u_notification);
+int mqueue_flush_file(struct file *filp);
+
+/* mqueue prototypes */
+int mq_list_check(struct mqueue_inode_info *info, int choice);
+struct file *do_create(struct dentry *dir, struct dentry *dentry,
+ int oflag, mode_t mode, struct mq_attr __user *u_attr);
+struct file *do_open(struct dentry *dentry, int oflag);
+int mq_attr_ok(struct mq_attr *attr);
+long prepare_timeout(const struct timespec __user *u_arg);
+asmlinkage long sys_mq_open(const char __user *u_name, int oflag,
+ mode_t mode, struct mq_attr __user *u_attr);
+void lx_do_wakeup(struct proc_wait_queue *wait);
+int lx_mq_sleep(struct mqueue_inode_info *info,
+ struct list_head *wait_list, long timeout);
+int timedsend_common(struct file *filp, const char __user *u_msg_ptr,
+ size_t msg_len, unsigned int msg_prio,
+ const struct timespec __user *u_abs_timeout,
+ int (* sleep) (struct mqueue_inode_info *info,
+ struct list_head *wait_list, long timeout));
+asmlinkage long sys_mq_timedsend(mqd_t mqdes, const char __user *u_msg_ptr,
+ size_t msg_len, unsigned int msg_prio,
+ const struct timespec __user *u_abs_timeout);
+ssize_t timedreceive_common (struct file *filp, char __user *u_msg_ptr,
+ size_t msg_len, unsigned int __user *u_msg_prio,
+ const struct timespec __user *u_abs_timeout,
+ int (* sleep) (struct mqueue_inode_info *info,
+ struct list_head *wait_list, long timeout));
+asmlinkage ssize_t sys_mq_timedreceive(mqd_t mqdes, char __user *u_msg_ptr,
+ size_t msg_len, unsigned int __user *u_msg_prio,
+ const struct timespec __user *u_abs_timeout);
+void init_once(void *foo, kmem_cache_t * cachep, unsigned long flags);
+int init_mqueue_fs(void);
+
#endif
diff -N -a -u -r linux-2.6.15.4/include/linux/sched.h aud_linux/include/linux/sched.h
--- linux-2.6.15.4/include/linux/sched.h 2007-04-16 22:23:50.000000000 +0200
+++ aud_linux/include/linux/sched.h 2007-04-16 13:12:24.000000000 +0200
@@ -784,6 +784,7 @@
struct key *thread_keyring; /* keyring private to this thread */
unsigned char jit_keyring; /* default keyring to attach requested keys to */
#endif
+ unsigned char fpu_counter;
int oomkilladj; /* OOM kill score adjustment (bit shift). */
char comm[TASK_COMM_LEN]; /* executable name excluding path
- access with [gs]et_task_comm (which lock
@@ -864,8 +865,19 @@
#endif
atomic_t fs_excl; /* holding fs exclusive resources */
#ifdef CONFIG_IPIPE
+/*
+ * aud rt extensions need special list entries for every task
+ * we extend the ipipe configuration
+ */
+#ifdef CONFIG_RTX_DOMAIN
+
+ struct list_head rt_sigqueue_head;
+ struct list_head rt_pid_list; /* queues members of the realtime domain */
+ void *rt_timer_list_hdr; /* for threads handling timer list headers */
+
+#endif /* CONFIG_RTX_DOMAIN */
void *ptd[IPIPE_ROOT_NPTDKEYS];
-#endif
+#endif /* CONFIG_IPIPE */
};
static inline pid_t process_group(struct task_struct *tsk)
@@ -873,6 +885,7 @@
return tsk->signal->pgrp;
}
+
/**
* pid_alive - check that a task structure is not stale
* @p: Task structure to be checked.
diff -N -a -u -r linux-2.6.15.4/ipc/mqueue.c aud_linux/ipc/mqueue.c
--- linux-2.6.15.4/ipc/mqueue.c 2006-02-10 08:22:48.000000000 +0100
+++ aud_linux/ipc/mqueue.c 2007-04-10 20:49:27.000000000 +0200
@@ -1,342 +1,228 @@
-/*
- * POSIX message queues filesystem for Linux.
+/* POSIX message queues filesystem for Linux.
*
- * Copyright (C) 2003,2004 Krzysztof Benedyczak (golbi@mat.uni.torun.pl)
- * Michal Wronski (Michal.Wronski@motorola.com)
+ * Copyright (C) 2003,2004 Krzysztof Benedyczak (golbi@mat.uni.torun.pl)
+ * Michal Wronski (Michal.Wronski@motorola.com)
*
- * Spinlocks: Mohamed Abbas (abbas.mohamed@intel.com)
+ * Spinlocks: Mohamed Abbas (abbas.mohamed@intel.com)
* Lockless receive & send, fd based notify:
- * Manfred Spraul (manfred@colorfullife.com)
+ * Manfred Spraul (manfred@colorfullife.com)
+ *
+ * rewritten and adapted for realtime
+ * Stefan Assmann (S.Assmann AT gmx DOT de)
+ * Copyright (c) 2007 Siemens AG
+ * last change: 2007-01-29
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*
- * This file is released under the GPL.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
-
+
#include <linux/init.h>
-#include <linux/pagemap.h>
+#include <linux/syscalls.h>
#include <linux/file.h>
+#include <linux/pagemap.h>
#include <linux/mount.h>
#include <linux/namei.h>
-#include <linux/sysctl.h>
-#include <linux/poll.h>
-#include <linux/mqueue.h>
-#include <linux/msg.h>
+#include <linux/types.h>
+#include <linux/unistd.h>
#include <linux/skbuff.h>
-#include <linux/netlink.h>
-#include <linux/syscalls.h>
#include <linux/signal.h>
+#include <linux/mqueue.h>
#include <net/sock.h>
-#include "util.h"
-
-#define MQUEUE_MAGIC 0x19800202
-#define DIRENT_SIZE 20
-#define FILENT_SIZE 80
-#define SEND 0
-#define RECV 1
+MODULE_AUTHOR("Stefan Assmann");
+MODULE_DESCRIPTION("AuD POSIX Message Queue");
+MODULE_LICENSE("GPL");
+
+// message queue
+#define MQ_OCCUPIED 0
+#define MQ_FREE 1
-#define STATE_NONE 0
-#define STATE_PENDING 1
-#define STATE_READY 2
-
-/* used by sysctl */
+// sysctl
#define FS_MQUEUE 1
#define CTL_QUEUESMAX 2
#define CTL_MSGMAX 3
#define CTL_MSGSIZEMAX 4
-/* default values */
-#define DFLT_QUEUESMAX 256 /* max number of message queues */
-#define DFLT_MSGMAX 10 /* max number of messages in each queue */
-#define HARD_MSGMAX (131072/sizeof(void*))
-#define DFLT_MSGSIZEMAX 8192 /* max message size */
-
-#define NOTIFY_COOKIE_LEN 32
-
-struct ext_wait_queue { /* queue of sleeping tasks */
- struct task_struct *task;
- struct list_head list;
- struct msg_msg *msg; /* ptr of loaded message */
- int state; /* one of STATE_* values */
-};
-
-struct mqueue_inode_info {
- spinlock_t lock;
- struct inode vfs_inode;
- wait_queue_head_t wait_q;
-
- struct msg_msg **messages;
- struct mq_attr attr;
-
- struct sigevent notify;
- pid_t notify_owner;
- struct user_struct *user; /* user who created, for accounting */
- struct sock *notify_sock;
- struct sk_buff *notify_cookie;
+// signaling
+#define NOTIFY_NONE 0
+#define NOTIFY_WOKENUP 1
+#define NOTIFY_REMOVED 2
+#define NOTIFY_COOKIE_LEN 32
- /* for tasks waiting for free space and messages, respectively */
- struct ext_wait_queue e_wait_q[2];
+// fs
+#define MQUEUE_MAGIC 0x19800202
+#define DIRENT_SIZE 20
+#define FILENT_SIZE 80
- unsigned long qsize; /* size of queue in memory (sum of all msgs) */
-};
+// globals
+int msg_max_limit_min = 1;
+int msg_max_limit_max = HARD_MSGMAX;
+int msg_maxsize_limit_min = DFLT_MSGSIZEMAX;
+int msg_maxsize_limit_max = INT_MAX;
+unsigned int queues_max = DFLT_QUEUESMAX;
+unsigned int msg_max = DFLT_MSGMAX;
+unsigned int msgsize_max = DFLT_MSGSIZEMAX;
+unsigned int queues_count;
+struct ctl_table_header * mq_sysctl_table;
+struct super_operations mqueue_super_ops;
+struct file_operations mqueue_file_operations;
+struct inode_operations mqueue_dir_inode_operations;
+struct vfsmount *mqueue_mnt;
+kmem_cache_t *mqueue_inode_cachep;
+spinlock_t mq_lock;
-static struct inode_operations mqueue_dir_inode_operations;
-static struct file_operations mqueue_file_operations;
-static struct super_operations mqueue_super_ops;
-static void remove_notification(struct mqueue_inode_info *info);
-
-static spinlock_t mq_lock;
-static kmem_cache_t *mqueue_inode_cachep;
-static struct vfsmount *mqueue_mnt;
-
-static unsigned int queues_count;
-static unsigned int queues_max = DFLT_QUEUESMAX;
-static unsigned int msg_max = DFLT_MSGMAX;
-static unsigned int msgsize_max = DFLT_MSGSIZEMAX;
+void (*rtx_wake_lx_handling)(struct proc_wait_queue *wait) = NULL;
-static struct ctl_table_header * mq_sysctl_table;
+// end of variable declaration
-static inline struct mqueue_inode_info *MQUEUE_I(struct inode *inode)
-{
+inline struct mqueue_inode_info *MQUEUE_I(struct inode *inode) {
return container_of(inode, struct mqueue_inode_info, vfs_inode);
}
-static struct inode *mqueue_get_inode(struct super_block *sb, int mode,
- struct mq_attr *attr)
+/*
+ * inode handling
+ */
+struct inode *mqueue_alloc_inode(struct super_block *sb)
{
- struct inode *inode;
-
- inode = new_inode(sb);
- if (inode) {
- inode->i_mode = mode;
- inode->i_uid = current->fsuid;
- inode->i_gid = current->fsgid;
- inode->i_blksize = PAGE_CACHE_SIZE;
- inode->i_blocks = 0;
- inode->i_mtime = inode->i_ctime = inode->i_atime =
- CURRENT_TIME;
-
- if (S_ISREG(mode)) {
- struct mqueue_inode_info *info;
- struct task_struct *p = current;
- struct user_struct *u = p->user;
- unsigned long mq_bytes, mq_msg_tblsz;
-
- inode->i_fop = &mqueue_file_operations;
- inode->i_size = FILENT_SIZE;
- /* mqueue specific info */
- info = MQUEUE_I(inode);
- spin_lock_init(&info->lock);
- init_waitqueue_head(&info->wait_q);
- INIT_LIST_HEAD(&info->e_wait_q[0].list);
- INIT_LIST_HEAD(&info->e_wait_q[1].list);
- info->messages = NULL;
- info->notify_owner = 0;
- info->qsize = 0;
- info->user = NULL; /* set when all is ok */
- memset(&info->attr, 0, sizeof(info->attr));
- info->attr.mq_maxmsg = DFLT_MSGMAX;
- info->attr.mq_msgsize = DFLT_MSGSIZEMAX;
- if (attr) {
- info->attr.mq_maxmsg = attr->mq_maxmsg;
- info->attr.mq_msgsize = attr->mq_msgsize;
- }
- mq_msg_tblsz = info->attr.mq_maxmsg * sizeof(struct msg_msg *);
- mq_bytes = (mq_msg_tblsz +
- (info->attr.mq_maxmsg * info->attr.mq_msgsize));
-
- spin_lock(&mq_lock);
- if (u->mq_bytes + mq_bytes < u->mq_bytes ||
- u->mq_bytes + mq_bytes >
- p->signal->rlim[RLIMIT_MSGQUEUE].rlim_cur) {
- spin_unlock(&mq_lock);
- goto out_inode;
- }
- u->mq_bytes += mq_bytes;
- spin_unlock(&mq_lock);
+ struct mqueue_inode_info *info;
- info->messages = kmalloc(mq_msg_tblsz, GFP_KERNEL);
- if (!info->messages) {
- spin_lock(&mq_lock);
- u->mq_bytes -= mq_bytes;
- spin_unlock(&mq_lock);
- goto out_inode;
- }
- /* all is ok */
- info->user = get_uid(u);
- } else if (S_ISDIR(mode)) {
- inode->i_nlink++;
- /* Some things misbehave if size == 0 on a directory */
- inode->i_size = 2 * DIRENT_SIZE;
- inode->i_op = &mqueue_dir_inode_operations;
- inode->i_fop = &simple_dir_operations;
- }
- }
- return inode;
-out_inode:
- make_bad_inode(inode);
- iput(inode);
- return NULL;
+ info = kmem_cache_alloc(mqueue_inode_cachep, SLAB_KERNEL);
+ if (!info)
+ return NULL;
+ return &info->vfs_inode;
}
-static int mqueue_fill_super(struct super_block *sb, void *data, int silent)
+int mqueue_create(struct inode *dir, struct dentry *dentry,
+ int mode, struct nameidata *nd)
{
+ int error;
struct inode *inode;
+ struct mq_attr *attr = dentry->d_fsdata;
- sb->s_blocksize = PAGE_CACHE_SIZE;
- sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
- sb->s_magic = MQUEUE_MAGIC;
- sb->s_op = &mqueue_super_ops;
-
- inode = mqueue_get_inode(sb, S_IFDIR | S_ISVTX | S_IRWXUGO, NULL);
- if (!inode)
- return -ENOMEM;
+ spin_lock_irq_hw(&mq_lock);
+ if (queues_count >= queues_max && !capable(CAP_SYS_RESOURCE)) {
+ error = -ENOSPC;
+ goto out_lock;
+ }
+ queues_count++;
+ spin_unlock_irq_hw(&mq_lock);
- sb->s_root = d_alloc_root(inode);
- if (!sb->s_root) {
- iput(inode);
- return -ENOMEM;
+ inode = mqueue_get_inode(dir->i_sb, mode, attr);
+ if (!inode) {
+ error = -ENOMEM;
+ spin_lock_irq_hw(&mq_lock);
+ queues_count--;
+ goto out_lock;
}
+ dir->i_size += DIRENT_SIZE;
+ dir->i_ctime = dir->i_mtime = dir->i_atime = CURRENT_TIME;
+ d_instantiate(dentry, inode);
+ dget(dentry);
return 0;
+out_lock:
+ spin_unlock_irq_hw(&mq_lock);
+ return error;
}
-static struct super_block *mqueue_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name,
- void *data)
-{
- return get_sb_single(fs_type, flags, data, mqueue_fill_super);
-}
-
-static void init_once(void *foo, kmem_cache_t * cachep, unsigned long flags)
-{
- struct mqueue_inode_info *p = (struct mqueue_inode_info *) foo;
-
- if ((flags & (SLAB_CTOR_VERIFY | SLAB_CTOR_CONSTRUCTOR)) ==
- SLAB_CTOR_CONSTRUCTOR)
- inode_init_once(&p->vfs_inode);
-}
-
-static struct inode *mqueue_alloc_inode(struct super_block *sb)
+int mqueue_unlink(struct inode *dir, struct dentry *dentry)
{
- struct mqueue_inode_info *ei;
+ struct inode *inode = dentry->d_inode;
- ei = kmem_cache_alloc(mqueue_inode_cachep, SLAB_KERNEL);
- if (!ei)
- return NULL;
- return &ei->vfs_inode;
+ dir->i_ctime = dir->i_mtime = dir->i_atime = CURRENT_TIME;
+ dir->i_size -= DIRENT_SIZE;
+ inode->i_nlink--;
+ dput(dentry);
+ return 0;
}
-static void mqueue_destroy_inode(struct inode *inode)
+void mqueue_destroy_inode(struct inode *inode)
{
kmem_cache_free(mqueue_inode_cachep, MQUEUE_I(inode));
}
-static void mqueue_delete_inode(struct inode *inode)
+void mqueue_delete_inode(struct inode *inode)
{
+ int i;
+ unsigned long mq_list_size;
+ unsigned long mq_bytes;
struct mqueue_inode_info *info;
struct user_struct *user;
- unsigned long mq_bytes;
- int i;
+ struct list_head *pos;
+ struct mq_list *tmp;
if (S_ISDIR(inode->i_mode)) {
clear_inode(inode);
return;
}
+
info = MQUEUE_I(inode);
- spin_lock(&info->lock);
- for (i = 0; i < info->attr.mq_curmsgs; i++)
- free_msg(info->messages[i]);
- kfree(info->messages);
- spin_unlock(&info->lock);
+ while(!list_empty(&info->free_list) ) {
+ pos = info->free_list.next;
+ list_del(pos);
+ tmp = list_entry(pos, struct mq_list, list);
+ kfree(tmp);
+ }
+ for(i = 0 ; i < MQ_PRIO_MAX; i++)
+ while(!list_empty(&info->queues[i])) {
+ pos = info->queues[i].next;
+ list_del(pos);
+ tmp = list_entry(pos, struct mq_list, list);
+ kfree(tmp);
+ }
clear_inode(inode);
- mq_bytes = (info->attr.mq_maxmsg * sizeof(struct msg_msg *) +
- (info->attr.mq_maxmsg * info->attr.mq_msgsize));
+ mq_list_size = sizeof(struct list_head) +
+ sizeof(struct mq_attr) +
+ sizeof(char) * info->attr.mq_msgsize;
+
+ mq_bytes = mq_list_size * info->attr.mq_maxmsg;
user = info->user;
if (user) {
- spin_lock(&mq_lock);
+ spin_lock_irq_hw(&mq_lock);
user->mq_bytes -= mq_bytes;
queues_count--;
- spin_unlock(&mq_lock);
+ spin_unlock_irq_hw(&mq_lock);
free_uid(user);
}
}
-static int mqueue_create(struct inode *dir, struct dentry *dentry,
- int mode, struct nameidata *nd)
-{
- struct inode *inode;
- struct mq_attr *attr = dentry->d_fsdata;
- int error;
-
- spin_lock(&mq_lock);
- if (queues_count >= queues_max && !capable(CAP_SYS_RESOURCE)) {
- error = -ENOSPC;
- goto out_lock;
- }
- queues_count++;
- spin_unlock(&mq_lock);
-
- inode = mqueue_get_inode(dir->i_sb, mode, attr);
- if (!inode) {
- error = -ENOMEM;
- spin_lock(&mq_lock);
- queues_count--;
- goto out_lock;
- }
-
- dir->i_size += DIRENT_SIZE;
- dir->i_ctime = dir->i_mtime = dir->i_atime = CURRENT_TIME;
-
- d_instantiate(dentry, inode);
- dget(dentry);
- return 0;
-out_lock:
- spin_unlock(&mq_lock);
- return error;
-}
-
-static int mqueue_unlink(struct inode *dir, struct dentry *dentry)
-{
- struct inode *inode = dentry->d_inode;
-
- dir->i_ctime = dir->i_mtime = dir->i_atime = CURRENT_TIME;
- dir->i_size -= DIRENT_SIZE;
- inode->i_nlink--;
- dput(dentry);
- return 0;
-}
-
-/*
-* This is routine for system read from queue file.
-* To avoid mess with doing here some sort of mq_receive we allow
-* to read only queue size & notification info (the only values
-* that are interesting from user point of view and aren't accessible
-* through std routines)
-*/
-static ssize_t mqueue_read_file(struct file *filp, char __user *u_data,
- size_t count, loff_t * off)
+ssize_t mqueue_read_file(struct file *filp, char __user *u_data,
+ size_t count, loff_t * off)
{
- struct mqueue_inode_info *info = MQUEUE_I(filp->f_dentry->d_inode);
- char buffer[FILENT_SIZE];
size_t slen;
loff_t o;
-
+ char buffer[FILENT_SIZE];
+ struct mqueue_inode_info *info = MQUEUE_I(filp->f_dentry->d_inode);
+
if (!count)
return 0;
- spin_lock(&info->lock);
- snprintf(buffer, sizeof(buffer),
- "QSIZE:%-10lu NOTIFY:%-5d SIGNO:%-5d NOTIFY_PID:%-6d\n",
- info->qsize,
- info->notify_owner ? info->notify.sigev_notify : 0,
- (info->notify_owner &&
- info->notify.sigev_notify == SIGEV_SIGNAL) ?
- info->notify.sigev_signo : 0,
- info->notify_owner);
- spin_unlock(&info->lock);
+ spin_lock_irq_hw(&info->lock);
+
+ snprintf(buffer, sizeof(buffer),
+ "FREE: %-5d USE: %-5d NOTIFY:%-5d SIGNO:%-5d NOTIFY_PID:%-6d\n",
+ mq_list_check(info, MQ_FREE),
+ mq_list_check(info, MQ_OCCUPIED),
+ info->notify_owner ? info->notify.sigev_notify : 0,
+ (info->notify_owner &&
+ info->notify.sigev_notify == SIGEV_SIGNAL) ?
+ info->notify.sigev_signo : 0,
+ info->notify_owner);
+ spin_unlock_irq_hw(&info->lock);
buffer[sizeof(buffer)-1] = '\0';
+
slen = strlen(buffer)+1;
o = *off;
@@ -350,163 +236,235 @@
return -EFAULT;
*off = o + count;
- filp->f_dentry->d_inode->i_atime = filp->f_dentry->d_inode->i_ctime = CURRENT_TIME;
+ filp->f_dentry->d_inode->i_atime = filp->f_dentry->d_inode->i_ctime =
+ CURRENT_TIME;
return count;
}
-static int mqueue_flush_file(struct file *filp)
-{
- struct mqueue_inode_info *info = MQUEUE_I(filp->f_dentry->d_inode);
-
- spin_lock(&info->lock);
- if (current->tgid == info->notify_owner)
- remove_notification(info);
-
- spin_unlock(&info->lock);
- return 0;
-}
-
-static unsigned int mqueue_poll_file(struct file *filp, struct poll_table_struct *poll_tab)
+int mqueue_fill_super(struct super_block *sb, void *data, int silent)
{
- struct mqueue_inode_info *info = MQUEUE_I(filp->f_dentry->d_inode);
- int retval = 0;
+ struct inode *inode;
- poll_wait(filp, &info->wait_q, poll_tab);
+ sb->s_blocksize = PAGE_CACHE_SIZE;
+ sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
+ sb->s_magic = MQUEUE_MAGIC;
+ sb->s_op = &mqueue_super_ops;
- spin_lock(&info->lock);
- if (info->attr.mq_curmsgs)
- retval = POLLIN | POLLRDNORM;
+ inode = mqueue_get_inode(sb, S_IFDIR | S_ISVTX | S_IRWXUGO, NULL);
+ if (!inode)
+ return -ENOMEM;
- if (info->attr.mq_curmsgs < info->attr.mq_maxmsg)
- retval |= POLLOUT | POLLWRNORM;
- spin_unlock(&info->lock);
+ sb->s_root = d_alloc_root(inode);
+ if (!sb->s_root) {
+ iput(inode);
+ return -ENOMEM;
+ }
- return retval;
+ return 0;
}
-/* Adds current to info->e_wait_q[sr] before element with smaller prio */
-static void wq_add(struct mqueue_inode_info *info, int sr,
- struct ext_wait_queue *ewp)
+struct inode *mqueue_get_inode(struct super_block *sb, int mode,
+ struct mq_attr *attr)
{
- struct ext_wait_queue *walk;
+ int i;
+ unsigned long mq_bytes;
+ unsigned long mq_list_size;
+ struct inode *inode;
+ struct mq_list *tmp;
+
+ inode = new_inode(sb);
+ if (inode) {
+ inode->i_mode = mode;
+ inode->i_uid = current->fsuid;
+ inode->i_gid = current->fsgid;
+ inode->i_blksize = PAGE_CACHE_SIZE;
+ inode->i_blocks = 0;
+ inode->i_mtime = inode->i_ctime = inode->i_atime =
+ CURRENT_TIME;
- ewp->task = current;
+ if (S_ISREG(mode)) {
+ struct mqueue_inode_info *info;
+ struct task_struct *p = current;
+ struct user_struct *u = p->user;
+ inode->i_fop = &mqueue_file_operations;
+ inode->i_size = FILENT_SIZE;
+ // mqueue specific info
+ info = MQUEUE_I(inode);
+ info->user = NULL;
+ info->notify_owner = 0;
+ info->bitmap = 0;
+ memset(&info->attr, 0, sizeof(info->attr));
+ info->attr.mq_maxmsg = DFLT_MSGMAX;
+ info->attr.mq_msgsize = DFLT_MSGSIZEMAX;
+ info->attr.mq_curmsgs = 0;
+ if (attr) {
+ info->attr.mq_maxmsg = attr->mq_maxmsg;
+ info->attr.mq_msgsize = attr->mq_msgsize;
+ }
+ spin_lock_init(&info->lock);
+ init_waitqueue_head(&info->wait_q);
+ INIT_LIST_HEAD(&info->free_list);
+ INIT_LIST_HEAD(&info->send_wait);
+ INIT_LIST_HEAD(&info->recv_wait);
+ for (i=0 ; i<MQ_PRIO_MAX ; i++) {
+ INIT_LIST_HEAD(&info->queues[i]);
+ }
+ mq_list_size = sizeof(struct list_head) +
+ sizeof(struct mq_attr) +
+ sizeof(char) * info->attr.mq_msgsize;
+
+ for (i=0 ; i<info->attr.mq_maxmsg ; i++) {
+ tmp = kmalloc(mq_list_size, GFP_KERNEL);
+ list_add_tail(&tmp->list, &info->free_list);
+ }
+
+ // required space for accounting
+ mq_bytes = mq_list_size * info->attr.mq_maxmsg;
+
+ spin_lock_irq_hw(&mq_lock);
+
+ if (u->mq_bytes + mq_bytes < u->mq_bytes ||
+ u->mq_bytes + mq_bytes >
+ p->signal->rlim[RLIMIT_MSGQUEUE].rlim_cur) {
+ spin_unlock_irq_hw(&mq_lock);
+ goto out_inode;
+ }
+ u->mq_bytes += mq_bytes;
+ spin_unlock_irq_hw(&mq_lock);
+ if (!info->queues) {
+ spin_lock_irq_hw(&mq_lock);
+ u->mq_bytes -= mq_bytes;
+ spin_unlock_irq_hw(&mq_lock);
+ }
- list_for_each_entry(walk, &info->e_wait_q[sr].list, list) {
- if (walk->task->static_prio <= current->static_prio) {
- list_add_tail(&ewp->list, &walk->list);
- return;
+ // all is ok
+ info->user = get_uid(u);
+ } else if (S_ISDIR(mode)) {
+ inode->i_nlink++;
+ // Some things misbehave if size == 0 on a directory
+ inode->i_size = 2 * DIRENT_SIZE;
+ inode->i_op = &mqueue_dir_inode_operations;
+ inode->i_fop = &simple_dir_operations;
}
}
- list_add_tail(&ewp->list, &info->e_wait_q[sr].list);
+ return inode;
+out_inode:
+ make_bad_inode(inode);
+ iput(inode);
+ return NULL;
}
-/*
- * Puts current task to sleep. Caller must hold queue lock. After return
- * lock isn't held.
- * sr: SEND or RECV
- */
-static int wq_sleep(struct mqueue_inode_info *info, int sr,
- long timeout, struct ext_wait_queue *ewp)
-{
- int retval;
- signed long time;
-
- wq_add(info, sr, ewp);
+struct super_block *mqueue_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name,
+ void *data) {
+ return get_sb_single(fs_type, flags, data, mqueue_fill_super);
+}
- for (;;) {
- set_current_state(TASK_INTERRUPTIBLE);
+struct inode_operations mqueue_dir_inode_operations = {
+ .lookup = simple_lookup,
+ .create = mqueue_create,
+ .unlink = mqueue_unlink,
+};
- spin_unlock(&info->lock);
- time = schedule_timeout(timeout);
+struct file_operations mqueue_file_operations = {
+ .flush = mqueue_flush_file,
+ .read = mqueue_read_file,
+};
- while (ewp->state == STATE_PENDING)
- cpu_relax();
+struct super_operations mqueue_super_ops = {
+ .alloc_inode = mqueue_alloc_inode,
+ .destroy_inode = mqueue_destroy_inode,
+ .statfs = simple_statfs,
+ .delete_inode = mqueue_delete_inode,
+ .drop_inode = generic_delete_inode,
+};
- if (ewp->state == STATE_READY) {
- retval = 0;
- goto out;
- }
- spin_lock(&info->lock);
- if (ewp->state == STATE_READY) {
- retval = 0;
- goto out_unlock;
- }
- if (signal_pending(current)) {
- retval = -ERESTARTSYS;
- break;
- }
- if (time == 0) {
- retval = -ETIMEDOUT;
- break;
- }
- }
- list_del(&ewp->list);
-out_unlock:
- spin_unlock(&info->lock);
-out:
- return retval;
-}
+struct file_system_type mqueue_fs_type = {
+ .name = "mqueue",
+ .get_sb = mqueue_get_sb,
+ .kill_sb = kill_litter_super,
+};
/*
- * Returns waiting task that should be serviced first or NULL if none exists
+ * proc interface
*/
-static struct ext_wait_queue *wq_get_first_waiter(
- struct mqueue_inode_info *info, int sr)
-{
- struct list_head *ptr;
+ctl_table mq_sysctls[] = {
+ {
+ .ctl_name = CTL_QUEUESMAX,
+ .procname = "queues_max",
+ .data = &queues_max,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
+ {
+ .ctl_name = CTL_MSGMAX,
+ .procname = "msg_max",
+ .data = &msg_max,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec_minmax,
+ .extra1 = &msg_max_limit_min,
+ .extra2 = &msg_max_limit_max,
+ },
+ {
+ .ctl_name = CTL_MSGSIZEMAX,
+ .procname = "msgsize_max",
+ .data = &msgsize_max,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec_minmax,
+ .extra1 = &msg_maxsize_limit_min,
+ .extra2 = &msg_maxsize_limit_max,
+ },
+ { .ctl_name = 0 }
+};
- ptr = info->e_wait_q[sr].list.prev;
- if (ptr == &info->e_wait_q[sr].list)
- return NULL;
- return list_entry(ptr, struct ext_wait_queue, list);
-}
+ctl_table mq_sysctl_dir[] = {
+ {
+ .ctl_name = FS_MQUEUE,
+ .procname = "mqueue",
+ .mode = 0555,
+ .child = mq_sysctls,
+ },
+ { .ctl_name = 0 }
+};
-/* Auxiliary functions to manipulate messages' list */
-static void msg_insert(struct msg_msg *ptr, struct mqueue_inode_info *info)
-{
- int k;
+ctl_table mq_sysctl_root[] = {
+ {
+ .ctl_name = CTL_FS,
+ .procname = "fs",
+ .mode = 0555,
+ .child = mq_sysctl_dir,
+ },
+ { .ctl_name = 0 }
+};
- k = info->attr.mq_curmsgs - 1;
- while (k >= 0 && info->messages[k]->m_type >= ptr->m_type) {
- info->messages[k + 1] = info->messages[k];
- k--;
- }
- info->attr.mq_curmsgs++;
- info->qsize += ptr->m_ts;
- info->messages[k + 1] = ptr;
-}
-static inline struct msg_msg *msg_get(struct mqueue_inode_info *info)
-{
- info->qsize -= info->messages[--info->attr.mq_curmsgs]->m_ts;
- return info->messages[info->attr.mq_curmsgs];
-}
+/*
+ * signal handling
+ */
-static inline void set_cookie(struct sk_buff *skb, char code)
+inline void set_cookie(struct sk_buff *skb, char code)
{
((char*)skb->data)[NOTIFY_COOKIE_LEN-1] = code;
}
-/*
- * The next function is only to split too long sys_mq_timedsend
+/* __do_notify
+ * invoked when there is registered process and there isn't process
+ * waiting synchronously for message AND state of queue changed from
+ * empty to not empty. Here we are sure that no one is waiting
+ * synchronously.
*/
-static void __do_notify(struct mqueue_inode_info *info)
+void __do_notify(struct mqueue_inode_info *info)
{
- /* notification
- * invoked when there is registered process and there isn't process
- * waiting synchronously for message AND state of queue changed from
- * empty to not empty. Here we are sure that no one is waiting
- * synchronously. */
- if (info->notify_owner &&
- info->attr.mq_curmsgs == 1) {
+ if (info->notify_owner && (mq_list_check(info, MQ_OCCUPIED) == 1)) {
struct siginfo sig_i;
switch (info->notify.sigev_notify) {
case SIGEV_NONE:
break;
case SIGEV_SIGNAL:
- /* sends signal */
-
+ // sends signal
sig_i.si_signo = info->notify.sigev_signo;
sig_i.si_errno = 0;
sig_i.si_code = SI_MESGQ;
@@ -523,141 +481,309 @@
info->notify_cookie, 0);
break;
}
- /* after notification unregisters process */
+ // after notification unregisters process
info->notify_owner = 0;
}
wake_up(&info->wait_q);
}
-static long prepare_timeout(const struct timespec __user *u_arg)
+void remove_notification(struct mqueue_inode_info *info)
{
- struct timespec ts, nowts;
- long timeout;
+ if (info->notify_owner != 0 &&
+ info->notify.sigev_notify == SIGEV_THREAD) {
+ set_cookie(info->notify_cookie, NOTIFY_REMOVED);
+ netlink_sendskb(info->notify_sock, info->notify_cookie, 0);
+ }
+ info->notify_owner = 0;
+}
- if (u_arg) {
- if (unlikely(copy_from_user(&ts, u_arg,
- sizeof(struct timespec))))
- return -EFAULT;
+asmlinkage long sys_mq_notify(mqd_t mqdes,
+ const struct sigevent __user *u_notification)
+{
+ int ret;
+ struct file *filp;
+ struct sock *sock;
+ struct inode *inode;
+ struct sigevent notification;
+ struct mqueue_inode_info *info;
+ struct sk_buff *nc;
- if (unlikely(ts.tv_nsec < 0 || ts.tv_sec < 0
- || ts.tv_nsec >= NSEC_PER_SEC))
+ nc = NULL;
+ sock = NULL;
+
+ if (u_notification != NULL) {
+ if (copy_from_user(¬ification, u_notification,
+ sizeof(struct sigevent)))
+ return -EFAULT;
+ if (unlikely(notification.sigev_notify != SIGEV_NONE &&
+ notification.sigev_notify != SIGEV_SIGNAL &&
+ notification.sigev_notify != SIGEV_THREAD))
+ return -EINVAL;
+ if (notification.sigev_notify == SIGEV_SIGNAL &&
+ !valid_signal(notification.sigev_signo)) {
return -EINVAL;
- nowts = CURRENT_TIME;
- /* first subtract as jiffies can't be too big */
- ts.tv_sec -= nowts.tv_sec;
- if (ts.tv_nsec < nowts.tv_nsec) {
- ts.tv_nsec += NSEC_PER_SEC;
- ts.tv_sec--;
}
- ts.tv_nsec -= nowts.tv_nsec;
- if (ts.tv_sec < 0)
- return 0;
+ if (notification.sigev_notify == SIGEV_THREAD) {
+ // create the notify skb
+ nc = alloc_skb(NOTIFY_COOKIE_LEN, GFP_KERNEL);
+ ret = -ENOMEM;
+ if (!nc)
+ goto out;
+ ret = -EFAULT;
+ if (copy_from_user(nc->data,
+ notification.sigev_value.sival_ptr,
+ NOTIFY_COOKIE_LEN)) {
+ goto out;
+ }
- timeout = timespec_to_jiffies(&ts) + 1;
- } else
- return MAX_SCHEDULE_TIMEOUT;
+ skb_put(nc, NOTIFY_COOKIE_LEN);
+retry:
+ filp = fget(notification.sigev_signo);
+ ret = -EBADF;
+ if (!filp)
+ goto out;
+ sock = netlink_getsockbyfilp(filp);
+ fput(filp);
+ if (IS_ERR(sock)) {
+ ret = PTR_ERR(sock);
+ sock = NULL;
+ goto out;
+ }
- return timeout;
+ ret = netlink_attachskb(sock, nc, 0,
+ MAX_SCHEDULE_TIMEOUT);
+ if (ret == 1)
+ goto retry;
+ if (ret) {
+ sock = NULL;
+ nc = NULL;
+ goto out;
+ }
+ }
+ }
+
+ ret = -EBADF;
+ filp = fget(mqdes);
+ if (!filp)
+ goto out;
+
+ inode = filp->f_dentry->d_inode;
+ if (unlikely(filp->f_op != &mqueue_file_operations))
+ goto out_fput;
+ info = MQUEUE_I(inode);
+
+ ret = 0;
+ spin_lock_irq_hw(&info->lock);
+ if (u_notification == NULL) {
+ if (info->notify_owner == current->tgid) {
+ remove_notification(info);
+ inode->i_atime = inode->i_ctime = CURRENT_TIME;
+ }
+ } else if (info->notify_owner != 0) {
+ ret = -EBUSY;
+ } else {
+ switch (notification.sigev_notify) {
+ case SIGEV_NONE:
+ info->notify.sigev_notify = SIGEV_NONE;
+ break;
+ case SIGEV_THREAD:
+ info->notify_sock = sock;
+ info->notify_cookie = nc;
+ sock = NULL;
+ nc = NULL;
+ info->notify.sigev_notify = SIGEV_THREAD;
+ break;
+ case SIGEV_SIGNAL:
+ info->notify.sigev_signo = notification.sigev_signo;
+ info->notify.sigev_value = notification.sigev_value;
+ info->notify.sigev_notify = SIGEV_SIGNAL;
+ break;
+ }
+ info->notify_owner = current->tgid;
+ inode->i_atime = inode->i_ctime = CURRENT_TIME;
+ }
+ spin_unlock_irq_hw(&info->lock);
+out_fput:
+ fput(filp);
+out:
+ if (sock) {
+ netlink_detachskb(sock, nc);
+ } else if (nc) {
+ dev_kfree_skb(nc);
+ }
+ return ret;
}
-static void remove_notification(struct mqueue_inode_info *info)
+int mqueue_flush_file(struct file *filp)
{
- if (info->notify_owner != 0 &&
- info->notify.sigev_notify == SIGEV_THREAD) {
- set_cookie(info->notify_cookie, NOTIFY_REMOVED);
- netlink_sendskb(info->notify_sock, info->notify_cookie, 0);
- }
- info->notify_owner = 0;
+ struct mqueue_inode_info *info = MQUEUE_I(filp->f_dentry->d_inode);
+
+ spin_lock_irq_hw(&info->lock);
+ if (current->tgid == info->notify_owner)
+ remove_notification(info);
+ spin_unlock_irq_hw(&info->lock);
+ return 0;
}
-static int mq_attr_ok(struct mq_attr *attr)
+/*
+ * message queue
+ */
+
+/* mq_list_check
+ * counts the amount of free/occupied elements of specified message queue
+ */
+int mq_list_check(struct mqueue_inode_info *info, int choice)
{
- if (attr->mq_maxmsg <= 0 || attr->mq_msgsize <= 0)
- return 0;
- if (capable(CAP_SYS_RESOURCE)) {
- if (attr->mq_maxmsg > HARD_MSGMAX)
- return 0;
- } else {
- if (attr->mq_maxmsg > msg_max ||
- attr->mq_msgsize > msgsize_max)
- return 0;
+ int i;
+ int counter;
+ struct mq_list *tmp;
+ struct list_head *pos;
+
+ counter=0;
+
+ if (choice == MQ_FREE) {
+ if ( !list_empty(&info->free_list) ) {
+ list_for_each(pos, &info->free_list) {
+ tmp = list_entry(pos, struct mq_list, list);
+ counter++;
+ }
+ }
+ return counter;
}
- /* check for overflow */
- if (attr->mq_msgsize > ULONG_MAX/attr->mq_maxmsg)
- return 0;
- if ((unsigned long)(attr->mq_maxmsg * attr->mq_msgsize) +
- (attr->mq_maxmsg * sizeof (struct msg_msg *)) <
- (unsigned long)(attr->mq_maxmsg * attr->mq_msgsize))
- return 0;
- return 1;
+ if (choice == MQ_OCCUPIED) {
+
+ for(i=0 ; i<MQ_PRIO_MAX; i++) {
+ if ( !list_empty(&info->queues[i]) ) {
+ list_for_each(pos, &info->queues[i]) {
+ tmp = list_entry(
+ pos, struct mq_list, list);
+ counter++;
+ }
+ }
+ }
+ return counter;
+ }
+ return -1;
}
-/*
- * Invoked when creating a new queue via sys_mq_open
+/* do_create
+ * creates a message queue in the filesystem
*/
-static struct file *do_create(struct dentry *dir, struct dentry *dentry,
- int oflag, mode_t mode, struct mq_attr __user *u_attr)
+struct file *do_create(struct dentry *dir, struct dentry *dentry,
+ int oflag, mode_t mode, struct mq_attr __user *u_attr)
{
- struct mq_attr attr;
- int ret;
-
- if (u_attr) {
- ret = -EFAULT;
- if (copy_from_user(&attr, u_attr, sizeof(attr)))
- goto out;
- ret = -EINVAL;
- if (!mq_attr_ok(&attr))
- goto out;
- /* store for use during create */
- dentry->d_fsdata = &attr;
- }
+ int ret;
+ struct mq_attr attr;
- mode &= ~current->fs->umask;
- ret = vfs_create(dir->d_inode, dentry, mode, NULL);
- dentry->d_fsdata = NULL;
- if (ret)
- goto out;
+ if (u_attr) {
+ ret = -EFAULT;
+ if (copy_from_user(&attr, u_attr, sizeof(attr)))
+ goto out;
+ ret = -EINVAL;
+ if (!mq_attr_ok(&attr))
+ goto out;
+
+ // store for use during create
+ dentry->d_fsdata = &attr;
+ }
+ mode &= ~current->fs->umask;
+ ret = vfs_create(dir->d_inode, dentry, mode, NULL);
+ dentry->d_fsdata = NULL;
+ if (ret)
+ goto out;
- return dentry_open(dentry, mqueue_mnt, oflag);
+ return dentry_open(dentry, mqueue_mnt, oflag);
out:
- dput(dentry);
- mntput(mqueue_mnt);
- return ERR_PTR(ret);
+ dput(dentry);
+ mntput(mqueue_mnt);
+ return ERR_PTR(ret);
+}
+
+/* do_open
+ * opens existing message queue
+ */
+struct file *do_open(struct dentry *dentry, int oflag) {
+ int oflag2acc[O_ACCMODE] = { MAY_READ, MAY_WRITE,
+ MAY_READ | MAY_WRITE };
+
+ if ((oflag & O_ACCMODE) == (O_RDWR | O_WRONLY)) {
+ dput(dentry);
+ mntput(mqueue_mnt);
+ return ERR_PTR(-EINVAL);
+ }
+ if (permission(dentry->d_inode, oflag2acc[oflag & O_ACCMODE], NULL)) {
+ dput(dentry);
+ mntput(mqueue_mnt);
+ return ERR_PTR(-EACCES);
+ }
+
+ return dentry_open(dentry, mqueue_mnt, oflag);
}
-/* Opens existing queue */
-static struct file *do_open(struct dentry *dentry, int oflag)
+/* mq_attr_ok
+ * checks if message queue attributes are set correctly
+ */
+int mq_attr_ok(struct mq_attr *attr)
{
-static int oflag2acc[O_ACCMODE] = { MAY_READ, MAY_WRITE,
- MAY_READ | MAY_WRITE };
-
- if ((oflag & O_ACCMODE) == (O_RDWR | O_WRONLY)) {
- dput(dentry);
- mntput(mqueue_mnt);
- return ERR_PTR(-EINVAL);
- }
+ if ( !(attr->mq_flags == 0) && !(attr->mq_flags == O_NONBLOCK) )
+ return 0;
+ if (attr->mq_msgsize < msg_max_limit_min ||
+ attr->mq_msgsize > msgsize_max)
+ return 0;
+ if ( attr->mq_maxmsg < msg_max_limit_min ||
+ attr->mq_maxmsg > msg_max)
+ return 0;
+
+ return 1;
+}
- if (permission(dentry->d_inode, oflag2acc[oflag & O_ACCMODE], NULL)) {
- dput(dentry);
- mntput(mqueue_mnt);
- return ERR_PTR(-EACCES);
- }
+/* prepare timeout
+ * converts absolute time values to jiffies for scheduling timeouts
+ */
+long prepare_timeout(const struct timespec __user *u_arg)
+{
+ long timeout;
+ struct timespec ts, nowts;
- return dentry_open(dentry, mqueue_mnt, oflag);
+ if (u_arg) {
+ if (unlikely(copy_from_user(&ts, u_arg,
+ sizeof(struct timespec))))
+ return -EFAULT;
+ if (unlikely(ts.tv_nsec < 0 || ts.tv_sec < 0
+ || ts.tv_nsec >= NSEC_PER_SEC))
+ return -EINVAL;
+ nowts = CURRENT_TIME;
+ // first subtract as jiffies can't be too big
+ ts.tv_sec -= nowts.tv_sec;
+ if (ts.tv_nsec < nowts.tv_nsec) {
+ ts.tv_nsec += NSEC_PER_SEC;
+ ts.tv_sec--;
+ }
+ ts.tv_nsec -= nowts.tv_nsec;
+ if (ts.tv_sec < 0)
+ return 0;
+ timeout = timespec_to_jiffies(&ts) + 1;
+ } else
+ return MAX_SCHEDULE_TIMEOUT;
+
+ return timeout;
}
-asmlinkage long sys_mq_open(const char __user *u_name, int oflag, mode_t mode,
- struct mq_attr __user *u_attr)
+/*sys_mq_open
+ *system call to open a message queue
+ */
+asmlinkage long sys_mq_open(const char __user *u_name, int oflag,
+ mode_t mode, struct mq_attr __user *u_attr)
{
+ int fd;
+ int error;
+ char *name;
struct dentry *dentry;
struct file *filp;
- char *name;
- int fd, error;
if (IS_ERR(name = getname(u_name)))
return PTR_ERR(name);
-
fd = get_unused_fd();
if (fd < 0)
goto out_putname;
@@ -671,7 +797,7 @@
mntget(mqueue_mnt);
if (oflag & O_CREAT) {
- if (dentry->d_inode) { /* entry already exists */
+ if (dentry->d_inode) { // entry already exists
error = -EEXIST;
if (oflag & O_EXCL)
goto out;
@@ -710,6 +836,9 @@
return fd;
}
+/*sys_mq_unlink
+ *system call to unlink a message queue
+ */
asmlinkage long sys_mq_unlink(const char __user *u_name)
{
int err;
@@ -750,336 +879,289 @@
return err;
}
-/* Pipelined send and receive functions.
- *
- * If a receiver finds no waiting message, then it registers itself in the
- * list of waiting receivers. A sender checks that list before adding the new
- * message into the message array. If there is a waiting receiver, then it
- * bypasses the message array and directly hands the message over to the
- * receiver.
- * The receiver accepts the message and returns without grabbing the queue
- * spinlock. Therefore an intermediate STATE_PENDING state and memory barriers
- * are necessary. The same algorithm is used for sysv semaphores, see
- * ipc/sem.c fore more details.
- *
- * The same algorithm is used for senders.
- */
-
-/* pipelined_send() - send a message directly to the task waiting in
- * sys_mq_timedreceive() (without inserting message into a queue).
+/* lx_do_wakeup
+ * - wakes up a thread sleeping in lx
+ * - called either from lx or rt
*/
-static inline void pipelined_send(struct mqueue_inode_info *info,
- struct msg_msg *message,
- struct ext_wait_queue *receiver)
-{
- receiver->msg = message;
- list_del(&receiver->list);
- receiver->state = STATE_PENDING;
- wake_up_process(receiver->task);
- smp_wmb();
- receiver->state = STATE_READY;
+void lx_do_wakeup(struct proc_wait_queue *wait)
+{
+ if (current->array != NULL)
+ wake_up_process(wait->task);
+ else
+ rtx_wake_lx_handling(wait);
}
-/* pipelined_receive() - if there is task waiting in sys_mq_timedsend()
- * gets its message and put to the queue (we have one free place for sure). */
-static inline void pipelined_receive(struct mqueue_inode_info *info)
-{
- struct ext_wait_queue *sender = wq_get_first_waiter(info, SEND);
-
- if (!sender) {
- /* for poll */
- wake_up_interruptible(&info->wait_q);
- return;
+/* lx_mq_sleep
+ * - let task sleep for a specified time
+ * - called under lock and left under locked
+ */
+int lx_mq_sleep(struct mqueue_inode_info *info,
+ struct list_head *wait_list, long timeout)
+{
+ int time;
+ struct proc_wait_queue wait;
+
+ wait.do_wakeup = lx_do_wakeup;
+ wait.task = current;
+ list_add_tail(&wait.list, wait_list);
+ spin_unlock_irq_hw(&info->lock);
+ set_current_state(TASK_INTERRUPTIBLE);
+ time = schedule_timeout(timeout);
+
+ spin_lock_irq_hw(&info->lock);
+ if (signal_pending(current)) {
+ if (!list_empty(&wait.list))
+ // in case it got woken up by time or by signal
+ list_del(&wait.list);
+ return -ERESTARTSYS;
+ }
+ if (time == 0) {
+ if (!list_empty(&wait.list))
+ // in case it got woken up by time or by signal
+ list_del(&wait.list);
+ return -ETIMEDOUT;
}
- msg_insert(sender->msg, info);
- list_del(&sender->list);
- sender->state = STATE_PENDING;
- wake_up_process(sender->task);
- smp_wmb();
- sender->state = STATE_READY;
+ return time;
}
-asmlinkage long sys_mq_timedsend(mqd_t mqdes, const char __user *u_msg_ptr,
+/* timedsend_common
+ * part of syscall mq_timedsend that is shared by lx and rt
+ */
+int timedsend_common(struct file *filp, const char __user *u_msg_ptr,
size_t msg_len, unsigned int msg_prio,
- const struct timespec __user *u_abs_timeout)
+ const struct timespec __user *u_abs_timeout,
+ int (* sleep) (struct mqueue_inode_info *info,
+ struct list_head *wait_list, long timeout))
{
- struct file *filp;
- struct inode *inode;
- struct ext_wait_queue wait;
- struct ext_wait_queue *receiver;
- struct msg_msg *msg_ptr;
- struct mqueue_inode_info *info;
- long timeout;
+ int cp;
int ret;
-
- if (unlikely(msg_prio >= (unsigned long) MQ_PRIO_MAX))
- return -EINVAL;
-
- timeout = prepare_timeout(u_abs_timeout);
-
- ret = -EBADF;
- filp = fget(mqdes);
- if (unlikely(!filp))
- goto out;
+ int save_bitmap;
+ long timeout;
+ struct inode *inode;
+ struct mqueue_inode_info *info;
+ struct proc_wait_queue *wait;
+ struct list_head *queue_head, *pos;
+ struct mq_list *tmp;
inode = filp->f_dentry->d_inode;
- if (unlikely(filp->f_op != &mqueue_file_operations))
- goto out_fput;
+ if (unlikely(filp->f_op != &mqueue_file_operations)) {
+ return -EBADF;
+ }
info = MQUEUE_I(inode);
-
- if (unlikely(!(filp->f_mode & FMODE_WRITE)))
- goto out_fput;
-
+ if (unlikely(!(filp->f_mode & FMODE_WRITE))) {
+ return -EBADF;
+ }
if (unlikely(msg_len > info->attr.mq_msgsize)) {
- ret = -EMSGSIZE;
- goto out_fput;
+ return -EMSGSIZE;
}
-
- /* First try to allocate memory, before doing anything with
- * existing queues. */
- msg_ptr = load_msg(u_msg_ptr, msg_len);
- if (IS_ERR(msg_ptr)) {
- ret = PTR_ERR(msg_ptr);
- goto out_fput;
+ if (unlikely(msg_prio >= (unsigned long) MQ_PRIO_MAX)) {
+ return -EINVAL;
}
- msg_ptr->m_ts = msg_len;
- msg_ptr->m_type = msg_prio;
- spin_lock(&info->lock);
+ spin_lock_irq_hw(&info->lock);
+ if ( unlikely(list_empty(&info->free_list)) ) {
+ if (filp->f_flags & (O_NONBLOCK)) {
+ spin_unlock_irq_hw(&info->lock);
+ return -EAGAIN;
+ }
+ spin_unlock_irq_hw(&info->lock);
+ timeout = prepare_timeout(u_abs_timeout);
+ spin_lock_irq_hw(&info->lock);
+
+ while (list_empty(&info->free_list)) {
+ if (unlikely(timeout < 0)) {
+ spin_unlock_irq_hw(&info->lock);
+ return timeout;
+ }
+ ret = sleep(info, &info->send_wait, timeout);
+ if (ret < 0) {
+ spin_unlock_irq_hw(&info->lock);
+ return ret;
+ } else {
+ timeout = ret; // check again for a free element
+ }
+ }
+ }
+ // lock is held, remove element from free list
+ pos = info->free_list.next;
+ list_del(pos);
+ spin_unlock_irq_hw(&info->lock);
+ tmp = list_entry(pos, struct mq_list, list);
+ // copy msg from userspace
+ cp = copy_from_user(tmp->msg, u_msg_ptr, msg_len);
+ if (cp != 0)
+ return -EFAULT;
+ tmp->msgsize = msg_len;
+
+ queue_head = &info->queues[msg_prio];
+ spin_lock_irq_hw(&info->lock);
+ save_bitmap = info->bitmap;
+ list_add_tail(pos, queue_head);
+ set_bit(msg_prio, &info->bitmap);
+ info->attr.mq_curmsgs++;
+
+ if (!list_empty(&info->recv_wait))
+ {
+ pos = info->recv_wait.next;
+ // del_init allows to dequeue item in case of a critical race
+ list_del_init(pos);
+ spin_unlock_irq_hw(&info->lock);
+ wait = list_entry(pos, struct proc_wait_queue, list);
+ wait->do_wakeup(wait);
+ return 0;
+ }
+ spin_unlock_irq_hw(&info->lock);
+
+ if ((current->array != NULL) && (save_bitmap == 0) &&
+ list_empty(&info->recv_wait))
+ __do_notify(info);
+ return 0;
+}
+
+/* sys_mq_timedsend
+ * syscall to send a message to a message queue
+ */
+asmlinkage long sys_mq_timedsend(mqd_t mqdes, const char __user *u_msg_ptr,
+ size_t msg_len, unsigned int msg_prio,
+ const struct timespec __user *u_abs_timeout)
+{
+ int ret;
+ struct file *filp;
- if (info->attr.mq_curmsgs == info->attr.mq_maxmsg) {
- if (filp->f_flags & O_NONBLOCK) {
- spin_unlock(&info->lock);
- ret = -EAGAIN;
- } else if (unlikely(timeout < 0)) {
- spin_unlock(&info->lock);
- ret = timeout;
- } else {
- wait.task = current;
- wait.msg = (void *) msg_ptr;
- wait.state = STATE_NONE;
- ret = wq_sleep(info, SEND, timeout, &wait);
- }
- if (ret < 0)
- free_msg(msg_ptr);
- } else {
- receiver = wq_get_first_waiter(info, RECV);
- if (receiver) {
- pipelined_send(info, msg_ptr, receiver);
- } else {
- /* adds message to the queue */
- msg_insert(msg_ptr, info);
- __do_notify(info);
- }
- inode->i_atime = inode->i_mtime = inode->i_ctime =
- CURRENT_TIME;
- spin_unlock(&info->lock);
- ret = 0;
+ filp = fget(mqdes);
+ if (unlikely(!filp)) {
+ ret = -EBADF;
+ goto out;
}
-out_fput:
+
+ ret = timedsend_common(filp, u_msg_ptr, msg_len, msg_prio,
+ u_abs_timeout, lx_mq_sleep);
fput(filp);
out:
return ret;
}
-asmlinkage ssize_t sys_mq_timedreceive(mqd_t mqdes, char __user *u_msg_ptr,
+/* timedreceive_common
+ * part of syscall mq_timedreceive that is shared by lx and rt
+ */
+ssize_t timedreceive_common (struct file *filp, char __user *u_msg_ptr,
size_t msg_len, unsigned int __user *u_msg_prio,
- const struct timespec __user *u_abs_timeout)
+ const struct timespec __user *u_abs_timeout,
+ int (* sleep) (struct mqueue_inode_info *info,
+ struct list_head *wait_list, long timeout))
{
- long timeout;
+ int cp;
+ unsigned int msg_prio;
ssize_t ret;
- struct msg_msg *msg_ptr;
- struct file *filp;
+ long timeout;
struct inode *inode;
struct mqueue_inode_info *info;
- struct ext_wait_queue wait;
-
- timeout = prepare_timeout(u_abs_timeout);
-
- ret = -EBADF;
- filp = fget(mqdes);
- if (unlikely(!filp))
- goto out;
-
+ struct proc_wait_queue *wait;
+ struct list_head *pos, *queue_head;
+ struct mq_list *tmp;
+
inode = filp->f_dentry->d_inode;
- if (unlikely(filp->f_op != &mqueue_file_operations))
- goto out_fput;
+ if (unlikely(filp->f_op != &mqueue_file_operations)) {
+ return -EBADF;
+ }
info = MQUEUE_I(inode);
-
- if (unlikely(!(filp->f_mode & FMODE_READ)))
- goto out_fput;
-
- /* checks if buffer is big enough */
+ if (unlikely(!(filp->f_mode & FMODE_READ))) {
+ return -EBADF;
+ }
if (unlikely(msg_len < info->attr.mq_msgsize)) {
- ret = -EMSGSIZE;
- goto out_fput;
+ return -EMSGSIZE;
}
- spin_lock(&info->lock);
- if (info->attr.mq_curmsgs == 0) {
+ spin_lock_irq_hw(&info->lock);
+
+ if (unlikely(info->bitmap == 0)) {
if (filp->f_flags & O_NONBLOCK) {
- spin_unlock(&info->lock);
- ret = -EAGAIN;
- msg_ptr = NULL;
- } else if (unlikely(timeout < 0)) {
- spin_unlock(&info->lock);
- ret = timeout;
- msg_ptr = NULL;
- } else {
- wait.task = current;
- wait.state = STATE_NONE;
- ret = wq_sleep(info, RECV, timeout, &wait);
- msg_ptr = wait.msg;
- }
- } else {
- msg_ptr = msg_get(info);
-
- inode->i_atime = inode->i_mtime = inode->i_ctime =
- CURRENT_TIME;
-
- /* There is now free space in queue. */
- pipelined_receive(info);
- spin_unlock(&info->lock);
- ret = 0;
- }
- if (ret == 0) {
- ret = msg_ptr->m_ts;
-
- if ((u_msg_prio && put_user(msg_ptr->m_type, u_msg_prio)) ||
- store_msg(u_msg_ptr, msg_ptr, msg_ptr->m_ts)) {
- ret = -EFAULT;
+ spin_unlock_irq_hw(&info->lock);
+ return -EAGAIN;
+ }
+ spin_unlock_irq_hw(&info->lock);
+ timeout = prepare_timeout(u_abs_timeout);
+ spin_lock_irq_hw(&info->lock);
+
+ while (info->bitmap == 0) {
+ if (unlikely(timeout < 0)) {
+ spin_unlock_irq_hw(&info->lock);
+ return timeout;
+ }
+ ret = sleep(info, &info->recv_wait, timeout);
+ if (ret < 0) {
+ spin_unlock_irq_hw(&info->lock);
+ return ret;
+ } else {
+ timeout = ret; // check again for a free element
+ }
+ }
+ }
+ // lock is still held, one non-empty queue is guaranteed
+ msg_prio = fls(info->bitmap) - 1;
+
+ queue_head = &info->queues[msg_prio];
+ pos = queue_head->next;
+ list_del(pos);
+ if (list_empty(&info->queues[msg_prio]))
+ clear_bit(msg_prio, &info->bitmap);
+
+ spin_unlock_irq_hw(&info->lock);
+
+ tmp = list_entry(pos, struct mq_list, list);
+ cp = copy_to_user(u_msg_ptr, tmp->msg, tmp->msgsize);
+ if (cp != 0) {
+ return -EFAULT;
+ }
+ if (u_msg_prio != NULL) {
+ cp = copy_to_user(u_msg_prio, &msg_prio, sizeof(msg_prio));
+ if (cp != 0) {
+ return -EFAULT;
}
- free_msg(msg_ptr);
- }
-out_fput:
- fput(filp);
-out:
- return ret;
+ }
+
+ spin_lock_irq_hw(&info->lock);
+ list_add_tail(pos, &info->free_list); // recycle element into free_list
+ info->attr.mq_curmsgs--;
+ if (!list_empty(&info->send_wait))
+ {
+ pos = info->send_wait.next;
+ // del_init allows to dequeue item in case of a critical race
+ list_del_init(pos);
+ spin_unlock_irq_hw(&info->lock);
+ wait = list_entry(pos, struct proc_wait_queue, list);
+ wait->do_wakeup(wait);
+ return tmp->msgsize;
+ }
+ spin_unlock_irq_hw(&info->lock);
+ return tmp->msgsize;
}
-/*
- * Notes: the case when user wants us to deregister (with NULL as pointer)
- * and he isn't currently owner of notification, will be silently discarded.
- * It isn't explicitly defined in the POSIX.
+/* sys_mq_timedreceive
+ * syscall to receive a message from a message queue
*/
-asmlinkage long sys_mq_notify(mqd_t mqdes,
- const struct sigevent __user *u_notification)
+asmlinkage ssize_t sys_mq_timedreceive(mqd_t mqdes, char __user *u_msg_ptr,
+ size_t msg_len, unsigned int __user *u_msg_prio,
+ const struct timespec __user *u_abs_timeout)
{
- int ret;
+ ssize_t ret;
struct file *filp;
- struct sock *sock;
- struct inode *inode;
- struct sigevent notification;
- struct mqueue_inode_info *info;
- struct sk_buff *nc;
-
- nc = NULL;
- sock = NULL;
- if (u_notification != NULL) {
- if (copy_from_user(¬ification, u_notification,
- sizeof(struct sigevent)))
- return -EFAULT;
-
- if (unlikely(notification.sigev_notify != SIGEV_NONE &&
- notification.sigev_notify != SIGEV_SIGNAL &&
- notification.sigev_notify != SIGEV_THREAD))
- return -EINVAL;
- if (notification.sigev_notify == SIGEV_SIGNAL &&
- !valid_signal(notification.sigev_signo)) {
- return -EINVAL;
- }
- if (notification.sigev_notify == SIGEV_THREAD) {
- /* create the notify skb */
- nc = alloc_skb(NOTIFY_COOKIE_LEN, GFP_KERNEL);
- ret = -ENOMEM;
- if (!nc)
- goto out;
- ret = -EFAULT;
- if (copy_from_user(nc->data,
- notification.sigev_value.sival_ptr,
- NOTIFY_COOKIE_LEN)) {
- goto out;
- }
-
- /* TODO: add a header? */
- skb_put(nc, NOTIFY_COOKIE_LEN);
- /* and attach it to the socket */
-retry:
- filp = fget(notification.sigev_signo);
- ret = -EBADF;
- if (!filp)
- goto out;
- sock = netlink_getsockbyfilp(filp);
- fput(filp);
- if (IS_ERR(sock)) {
- ret = PTR_ERR(sock);
- sock = NULL;
- goto out;
- }
-
- ret = netlink_attachskb(sock, nc, 0, MAX_SCHEDULE_TIMEOUT);
- if (ret == 1)
- goto retry;
- if (ret) {
- sock = NULL;
- nc = NULL;
- goto out;
- }
- }
- }
- ret = -EBADF;
filp = fget(mqdes);
- if (!filp)
+ if (unlikely(!filp)) {
+ ret = -EBADF;
goto out;
-
- inode = filp->f_dentry->d_inode;
- if (unlikely(filp->f_op != &mqueue_file_operations))
- goto out_fput;
- info = MQUEUE_I(inode);
-
- ret = 0;
- spin_lock(&info->lock);
- if (u_notification == NULL) {
- if (info->notify_owner == current->tgid) {
- remove_notification(info);
- inode->i_atime = inode->i_ctime = CURRENT_TIME;
- }
- } else if (info->notify_owner != 0) {
- ret = -EBUSY;
- } else {
- switch (notification.sigev_notify) {
- case SIGEV_NONE:
- info->notify.sigev_notify = SIGEV_NONE;
- break;
- case SIGEV_THREAD:
- info->notify_sock = sock;
- info->notify_cookie = nc;
- sock = NULL;
- nc = NULL;
- info->notify.sigev_notify = SIGEV_THREAD;
- break;
- case SIGEV_SIGNAL:
- info->notify.sigev_signo = notification.sigev_signo;
- info->notify.sigev_value = notification.sigev_value;
- info->notify.sigev_notify = SIGEV_SIGNAL;
- break;
- }
- info->notify_owner = current->tgid;
- inode->i_atime = inode->i_ctime = CURRENT_TIME;
}
- spin_unlock(&info->lock);
-out_fput:
+ ret = timedreceive_common(filp, u_msg_ptr, msg_len, u_msg_prio,
+ u_abs_timeout, lx_mq_sleep);
fput(filp);
-out:
- if (sock) {
- netlink_detachskb(sock, nc);
- } else if (nc) {
- dev_kfree_skb(nc);
- }
+out:
return ret;
}
+/* sys_mq_getsetattr
+ * combined syscall that implements mq_getattr and mq_setattr
+ */
asmlinkage long sys_mq_getsetattr(mqd_t mqdes,
const struct mq_attr __user *u_mqstat,
struct mq_attr __user *u_omqstat)
@@ -1107,7 +1189,7 @@
goto out_fput;
info = MQUEUE_I(inode);
- spin_lock(&info->lock);
+ spin_lock_irq_hw(&info->lock);
omqstat = info->attr;
omqstat.mq_flags = filp->f_flags & O_NONBLOCK;
@@ -1120,7 +1202,7 @@
inode->i_atime = inode->i_ctime = CURRENT_TIME;
}
- spin_unlock(&info->lock);
+ spin_unlock_irq_hw(&info->lock);
ret = 0;
if (u_omqstat != NULL && copy_to_user(u_omqstat, &omqstat,
@@ -1133,91 +1215,24 @@
return ret;
}
-static struct inode_operations mqueue_dir_inode_operations = {
- .lookup = simple_lookup,
- .create = mqueue_create,
- .unlink = mqueue_unlink,
-};
-
-static struct file_operations mqueue_file_operations = {
- .flush = mqueue_flush_file,
- .poll = mqueue_poll_file,
- .read = mqueue_read_file,
-};
-
-static struct super_operations mqueue_super_ops = {
- .alloc_inode = mqueue_alloc_inode,
- .destroy_inode = mqueue_destroy_inode,
- .statfs = simple_statfs,
- .delete_inode = mqueue_delete_inode,
- .drop_inode = generic_delete_inode,
-};
-
-static struct file_system_type mqueue_fs_type = {
- .name = "mqueue",
- .get_sb = mqueue_get_sb,
- .kill_sb = kill_litter_super,
-};
-
-static int msg_max_limit_min = DFLT_MSGMAX;
-static int msg_max_limit_max = HARD_MSGMAX;
-
-static int msg_maxsize_limit_min = DFLT_MSGSIZEMAX;
-static int msg_maxsize_limit_max = INT_MAX;
-
-static ctl_table mq_sysctls[] = {
- {
- .ctl_name = CTL_QUEUESMAX,
- .procname = "queues_max",
- .data = &queues_max,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = &proc_dointvec,
- },
- {
- .ctl_name = CTL_MSGMAX,
- .procname = "msg_max",
- .data = &msg_max,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = &proc_dointvec_minmax,
- .extra1 = &msg_max_limit_min,
- .extra2 = &msg_max_limit_max,
- },
- {
- .ctl_name = CTL_MSGSIZEMAX,
- .procname = "msgsize_max",
- .data = &msgsize_max,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = &proc_dointvec_minmax,
- .extra1 = &msg_maxsize_limit_min,
- .extra2 = &msg_maxsize_limit_max,
- },
- { .ctl_name = 0 }
-};
-
-static ctl_table mq_sysctl_dir[] = {
- {
- .ctl_name = FS_MQUEUE,
- .procname = "mqueue",
- .mode = 0555,
- .child = mq_sysctls,
- },
- { .ctl_name = 0 }
-};
+/* init_once
+ * initialize inode for further use
+ */
+void init_once(void *foo, kmem_cache_t * cachep, unsigned long flags)
+{
+ struct mqueue_inode_info *p = (struct mqueue_inode_info *) foo;
-static ctl_table mq_sysctl_root[] = {
- {
- .ctl_name = CTL_FS,
- .procname = "fs",
- .mode = 0555,
- .child = mq_sysctl_dir,
- },
- { .ctl_name = 0 }
-};
+ if ((flags & (SLAB_CTOR_VERIFY | SLAB_CTOR_CONSTRUCTOR)) ==
+ SLAB_CTOR_CONSTRUCTOR)
+ inode_init_once(&p->vfs_inode);
+}
-static int __init init_mqueue_fs(void)
+/* init_mqueue_fs
+ * - get slab cache
+ * - register sysctl
+ * - register message queue filesystem
+ */
+int init_mqueue_fs(void)
{
int error;
@@ -1226,10 +1241,8 @@
SLAB_HWCACHE_ALIGN, init_once, NULL);
if (mqueue_inode_cachep == NULL)
return -ENOMEM;
-
- /* ignore failues - they are not fatal */
+ // ignore failures - they are not fatal
mq_sysctl_table = register_sysctl_table(mq_sysctl_root, 0);
-
error = register_filesystem(&mqueue_fs_type);
if (error)
goto out_sysctl;
@@ -1239,10 +1252,9 @@
goto out_filesystem;
}
- /* internal initialization - not common for vfs */
+ // internal initializations for message queues - not common for vfs
queues_count = 0;
spin_lock_init(&mq_lock);
-
return 0;
out_filesystem:
@@ -1251,10 +1263,36 @@
if (mq_sysctl_table)
unregister_sysctl_table(mq_sysctl_table);
if (kmem_cache_destroy(mqueue_inode_cachep)) {
- printk(KERN_INFO
- "mqueue_inode_cache: not all structures were freed\n");
+ printk("mqueue_inode_cache: not all structures were freed\n");
}
return error;
}
-__initcall(init_mqueue_fs);
+
+int __init mod_init(void)
+{
+ init_mqueue_fs();
+ return 0;
+}
+
+void __exit mod_exit(void)
+{
+ // unregister filesystem
+ unregister_filesystem(&mqueue_fs_type);
+ // unregister sysctl_table
+ if (mq_sysctl_table)
+ unregister_sysctl_table(mq_sysctl_table);
+ // unmount mqueue vfs before it can be released!!!
+ mntput(mqueue_mnt);
+ // free kmem_cache
+ if (kmem_cache_destroy(mqueue_inode_cachep)) {
+ printk("mqueue_inode_cache: not all structures were freed\n");
+ }
+}
+
+module_init(mod_init);
+module_exit(mod_exit);
+
+EXPORT_SYMBOL(timedsend_common);
+EXPORT_SYMBOL(timedreceive_common);
+EXPORT_SYMBOL(rtx_wake_lx_handling);
diff -N -a -u -r linux-2.6.15.4/kernel/futex.c aud_linux/kernel/futex.c
--- linux-2.6.15.4/kernel/futex.c 2006-02-10 08:22:48.000000000 +0100
+++ aud_linux/kernel/futex.c 2007-04-10 20:49:27.000000000 +0200
@@ -42,6 +42,11 @@
#include <linux/signal.h>
#include <asm/futex.h>
+#ifdef CONFIG_RTX_DOMAIN
+#include <linux/module.h>
+int (*rtx_futex_wake_handling)(unsigned long, int) = NULL; /* indirection because of the(dynamically) loaded realtime module */
+#endif /* CONFIG_RTX_DOMAIN */
+
#define FUTEX_HASHBITS (CONFIG_BASE_SMALL ? 4 : 8)
/*
@@ -822,6 +827,7 @@
goto out;
}
+
long do_futex(unsigned long uaddr, int op, int val, unsigned long timeout,
unsigned long uaddr2, int val2, int val3)
{
@@ -833,6 +839,10 @@
break;
case FUTEX_WAKE:
ret = futex_wake(uaddr, val);
+#ifdef CONFIG_RTX_DOMAIN
+ if ((ret < val)&& rtx_futex_wake_handling) // realtime domain present, try to satisfy nr of wakeups there
+ ret += rtx_futex_wake_handling(uaddr, val - ret);
+#endif
break;
case FUTEX_FD:
/* non-zero val means F_SETOWN(getpid()) & F_SETSIG(val) */
@@ -853,6 +863,10 @@
return ret;
}
+#ifdef CONFIG_RTX_DOMAIN
+EXPORT_SYMBOL(do_futex);
+EXPORT_SYMBOL(rtx_futex_wake_handling);
+#endif /* CONFIG_RTX_DOMAIN */
asmlinkage long sys_futex(u32 __user *uaddr, int op, int val,
struct timespec __user *utime, u32 __user *uaddr2,
diff -N -a -u -r linux-2.6.15.4/kernel/ipipe/core.c aud_linux/kernel/ipipe/core.c
--- linux-2.6.15.4/kernel/ipipe/core.c 2007-04-16 22:23:50.000000000 +0200
+++ aud_linux/kernel/ipipe/core.c 2007-04-10 20:49:27.000000000 +0200
@@ -19,6 +19,9 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Architecture-independent I-PIPE core support.
+ *
+ * 2006-11-20: Karl-Heinz Krause Copyright (c) 2006 Siemens AG
+ * Support for fast dual domain system added
*/
#include <linux/sched.h>
@@ -29,6 +32,27 @@
#include <linux/proc_fs.h>
#endif /* CONFIG_PROC_FS */
+#ifdef CONFIG_RTX_DOMAIN
+
+/*
+ * Addition for the rtx realtime system comprised of a pointer to the
+ * preemption check for threads to execute after an RTX ISR has been handled
+ */
+
+void (*rtx_preemption_handling)(void) = NULL;
+EXPORT_SYMBOL(rtx_preemption_handling);
+
+#ifdef CONFIG_RTX_FAST
+
+struct ipipe_domain *__rtx_domain = NULL;
+static int no_ack(void)
+{ // Having a noop ack-routine allows for a homogenous code
+ return 1; // in ipipe_handle_irq without penalizing
+} // the time critical scenarios
+
+#endif /* CONFIG_RTX_FAST */
+#endif /* CONFIG_RTX_DOMAIN */
+
static struct ipipe_domain ipipe_root =
{ .cpudata = {[0 ... IPIPE_NR_CPUS-1] =
{ .status = (1<<IPIPE_STALL_FLAG) } } };
@@ -81,8 +105,13 @@
__ipipe_printk_virq = ipipe_alloc_virq(); /* Cannot fail here. */
ipd->irqs[__ipipe_printk_virq].handler = &__ipipe_flush_printk;
ipd->irqs[__ipipe_printk_virq].cookie = NULL;
- ipd->irqs[__ipipe_printk_virq].acknowledge = NULL;
ipd->irqs[__ipipe_printk_virq].control = IPIPE_HANDLE_MASK;
+#ifdef CONFIG_RTX_FAST
+ ipd->irqs[__ipipe_printk_virq].acknowledge = (ipipe_irq_ackfn_t)&no_ack;
+#else
+ ipd->irqs[__ipipe_printk_virq].acknowledge = NULL;
+#endif
+
#endif /* CONFIG_PRINTK */
__ipipe_enable_pipeline();
@@ -477,6 +506,73 @@
return irq;
}
+#ifdef CONFIG_RTX_FAST
+
+
+
+/*
+ * rtx_virtualize_irq() -- prepare an irq entrie for the realtime domain or for virtual interrupts
+ * with the right control flags and acknowledge handler for fastest handling as required
+ * by the __ipipe_handle_irq routine of the rtx domain system
+ */
+
+int rtx_virtualize_irq(struct ipipe_domain *ipd,
+ unsigned irq,
+ ipipe_irq_handler_t handler,
+ void *cookie,
+ unsigned modemask)
+{
+ int flags;
+ irq_desc_t *desc = irq_desc + irq;
+
+ if (!__rtx_domain)
+ return -ENODEV;
+ if ((ipd == ipipe_root_domain) && (irq < IPIPE_VIRQ_BASE))
+ return -EINVAL; // for Linux device ISRs the native request_irq has to be used
+ spin_lock_irqsave_hw(&__ipipe_pipelock, flags);
+ if (irq >= IPIPE_VIRQ_BASE)
+ { // virtual interrupt
+ __rtx_domain->irqs[irq].acknowledge = (ipipe_irq_ackfn_t)&no_ack;
+ ipipe_root_domain->irqs[irq].acknowledge = (ipipe_irq_ackfn_t)&no_ack;
+ if (ipd == __rtx_domain)
+ { // virtual interrupts are always exclusive ones
+ ipipe_root_domain->irqs[irq].control &= ~IPIPE_HANDLE_MASK;
+ }
+ else
+ {
+ __rtx_domain->irqs[irq].handler = NULL;
+ if (!handler) { // unregister interrupt handler?
+ ipipe_root_domain->irqs[irq].control &= ~IPIPE_HANDLE_MASK;
+ }
+ else {
+ ipipe_root_domain->irqs[irq].control |= IPIPE_HANDLE_MASK;
+ }
+ }
+ }
+ else
+ { // handers for hw-interrupts are for the rtx_domain only
+ if ((modemask & IPIPE_WIRED_MASK) && (irq != __ipipe_tick_irq))
+ {
+ ipipe_root_domain->irqs[irq].control &= ~IPIPE_HANDLE_MASK;
+ __rtx_domain->irqs[irq].acknowledge = (ipipe_irq_ackfn_t)desc->handler->end;
+ }
+ else
+ {
+ __rtx_domain->irqs[irq].acknowledge = (ipipe_irq_ackfn_t)&no_ack;
+ }
+ if (!handler) // unregister interrupt handler?
+ { // enable Linux handler again
+ ipipe_root_domain->irqs[irq].control |= IPIPE_HANDLE_MASK;
+ }
+ }
+ ipd->irqs[irq].handler = handler;
+ ipd->irqs[irq].cookie = cookie;
+ spin_unlock_irqrestore_hw(&__ipipe_pipelock, flags);
+ return 0;
+}
+
+#endif /* CONFIG_RTX_FAST */
+
/* ipipe_virtualize_irq() -- Attach a handler (and optionally a hw
acknowledge routine) to an interrupt for a given domain. */
@@ -496,6 +592,13 @@
if (ipd->irqs[irq].control & IPIPE_SYSTEM_MASK)
return -EPERM;
+#ifdef CONFIG_RTX_FAST
+
+ if ((irq >= IPIPE_VIRQ_BASE) || (ipd != ipipe_root_domain))
+ return rtx_virtualize_irq(ipd, irq, handler, cookie, modemask);
+
+#endif /* CONFIG_RTX_FAST */
+
if (!test_bit(IPIPE_AHEAD_FLAG, &ipd->flags))
/* Silently unwire interrupts for non-heading domains. */
modemask &= ~IPIPE_WIRED_MASK;
@@ -842,6 +945,21 @@
}
__clear_bit(IPIPE_SYNC_FLAG, &cpudata->status);
+
+#ifdef CONFIG_RTX_DOMAIN
+
+/* extension for the aud realtime system. After all interrupts for the realtime domain
+ * have been handled, check whether a switch to the realtime scheduler has to take place.
+ * This routine cares for both scenarios
+ * -- the system has been in the Linux domain and an ISR woke up a realtime thread
+ * -- the system has been in the realtime domain and an ISR woke up a realtime thread
+ * of higher priority
+ */
+#ifndef CONFIG_RTX_FAST // there is no logging for the realtime domain and consequently no syncing
+ if (ipd != &ipipe_root)
+ rtx_preemption_handling(); // function pointer is always set
+#endif /* CONFIG_RTX_FAST */
+#endif /* CONFIG_RTX_DOMAIN */
}
#ifdef CONFIG_PROC_FS
diff -N -a -u -r linux-2.6.15.4/kernel/ipipe/generic.c aud_linux/kernel/ipipe/generic.c
--- linux-2.6.15.4/kernel/ipipe/generic.c 2007-04-16 22:23:50.000000000 +0200
+++ aud_linux/kernel/ipipe/generic.c 2007-04-10 20:49:27.000000000 +0200
@@ -37,6 +37,12 @@
static unsigned long __ipipe_ptd_key_map;
+#ifdef CONFIG_RTX_DOMAIN
+#ifdef CONFIG_RTX_FAST
+extern struct ipipe_domain *__rtx_domain;
+#endif
+#endif
+
/* ipipe_register_domain() -- Link a new domain to the pipeline. */
int ipipe_register_domain(struct ipipe_domain *ipd,
@@ -128,6 +134,12 @@
ipipe_unlock_cpu(flags);
}
+
+#ifdef CONFIG_RTX_DOMAIN
+#ifdef CONFIG_RTX_FAST
+ __rtx_domain = ipd;
+#endif
+#endif
return 0;
}
@@ -193,6 +205,11 @@
__ipipe_cleanup_domain(ipd);
+#ifdef CONFIG_RTX_DOMAIN
+#ifdef CONFIG_RTX_FAST
+ __rtx_domain = NULL;
+#endif
+#endif
printk(KERN_WARNING "I-pipe: Domain %s unregistered.\n", ipd->name);
return 0;
@@ -279,6 +296,15 @@
if (event >= IPIPE_NR_EVENTS)
return NULL;
+ // m.n. remove of event handlers:
+ // race conditions: event bit is still set but handler is gone
+ // we need to delete event bit first
+ if (ipd->evhand[event] && !handler) {
+ if (ipd->evself & (1LL << event))
+ ipd->evself &= ~(1LL << event);
+ else
+ __ipipe_event_monitors[event]--;
+ }
if (!(old_handler = xchg(&ipd->evhand[event],handler))) {
if (handler) {
if (self)
@@ -288,10 +314,12 @@
}
}
else if (!handler) {
+#if (0) // see above
if (ipd->evself & (1LL << event))
ipd->evself &= ~(1LL << event);
else
__ipipe_event_monitors[event]--;
+#endif
} else if ((ipd->evself & (1LL << event)) && !self) {
__ipipe_event_monitors[event]++;
ipd->evself &= ~(1LL << event);
diff -N -a -u -r linux-2.6.15.4/kernel/ipipe/Kconfig aud_linux/kernel/ipipe/Kconfig
--- linux-2.6.15.4/kernel/ipipe/Kconfig 2007-04-16 22:23:50.000000000 +0200
+++ aud_linux/kernel/ipipe/Kconfig 2007-04-10 20:49:27.000000000 +0200
@@ -2,5 +2,19 @@
bool "Interrupt pipeline"
default y
---help---
- Activate this option if you want the interrupt pipeline to be
- compiled in.
+ Activate this option if you want the general interrupt pipeline
+config RTX_DOMAIN
+ bool "rtx domain system"
+ default y
+ depends on IPIPE
+ ---help---
+ You need to activate this option
+ if you want the Linux / realtime domain implementation
+config RTX_FAST
+ bool "fast rtx dual domain system"
+ default y
+ depends on RTX_DOMAIN
+ ---help---
+ Activate this option if you want the fast version
+ of the Linux / realtime domain implementation
+
\ Kein Zeilenumbruch am Dateiende.
diff -N -a -u -r linux-2.6.15.4/kernel/posix-timers.c aud_linux/kernel/posix-timers.c
--- linux-2.6.15.4/kernel/posix-timers.c 2006-02-10 08:22:48.000000000 +0100
+++ aud_linux/kernel/posix-timers.c 2007-04-10 20:49:27.000000000 +0200
@@ -98,6 +98,8 @@
#endif
+
+
/*
* The timer ID is turned into a timer address by idr_find().
* Verifying a valid ID consists of:
@@ -519,8 +521,7 @@
if ((event->sigev_notify & SIGEV_THREAD_ID ) &&
(!(rtn = find_task_by_pid(event->sigev_notify_thread_id)) ||
- rtn->tgid != current->tgid ||
- (event->sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_SIGNAL))
+ rtn->tgid != current->tgid))
return NULL;
if (((event->sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_NONE) &&
@@ -1242,6 +1243,11 @@
}
EXPORT_SYMBOL_GPL(do_posix_clock_nonanosleep);
+
+#ifdef CONFIG_RTX_DOMAIN
+void (*rtx_settime_handling)(struct timespec *) = NULL;
+#endif /* CONFIG_RTX_DOMAIN */
+
asmlinkage long
sys_clock_settime(clockid_t which_clock, const struct timespec __user *tp)
{
@@ -1251,7 +1257,10 @@
return -EINVAL;
if (copy_from_user(&new_tp, tp, sizeof (*tp)))
return -EFAULT;
-
+#ifdef CONFIG_RTX_DOMAIN
+ if ((which_clock == CLOCK_REALTIME)&& rtx_settime_handling) // realtime domain time must also be set
+ rtx_settime_handling(&new_tp);
+#endif
return CLOCK_DISPATCH(which_clock, clock_set, (which_clock, &new_tp));
}
@@ -1532,3 +1541,67 @@
return -EFAULT;
return ret;
}
+
+#ifdef CONFIG_RTX_DOMAIN
+
+/*
+ * These additional functions are not mandatory as patches, but they make life somewhat safer as
+ * the currently exported function register_posix_clock is not very usable. It doesn't resolve
+ * the issue of assigning clock IDs to unrelated requestors
+ */
+
+
+
+int register_new_posix_clock(clockid_t clockid, struct k_clock *new_clock)
+{
+ int i;
+
+ if ((clockid >= 0) && (clockid < MAX_CLOCKS))
+ {
+ posix_clocks[clockid] = *new_clock;
+ return clockid;
+ }
+ for (i = MAX_CLOCKS -1; i > 0; i--)
+ if (posix_clocks[clockid].res == 0) // in a final version this must be done under a lock here
+ { // currently it is done outside
+ posix_clocks[i] = *new_clock;
+ return i;
+ }
+ return -ESRCH;
+}
+
+int unregister_posix_clock(clockid_t clockid)
+{
+ if (((unsigned) clockid >= MAX_CLOCKS) || ((unsigned) clockid < 2))
+ return -EINVAL;
+ posix_clocks[clockid].res = 0;
+ return clockid;
+}
+
+
+long unsigned clock_getres_int(int clockid)
+{
+ if (clockid >= MAX_CLOCKS)
+ return -EINVAL;
+ return(posix_clocks[clockid].res); // must get exported by posix-timers.c
+}
+
+
+/*
+ * These lower level symbols symbols don't get exported anymore in signal.c.
+ * They got replaced by the symbol posix_timer_event
+ * We still need them, as we want to send not only SI_TIMER type events
+ * As a shortcut we export them here
+ */
+
+int send_group_sigqueue(int, struct sigqueue *, struct task_struct *);
+int rt_send_sigqueue(struct sigqueue *, struct task_struct *);
+
+EXPORT_SYMBOL(send_sigqueue);
+EXPORT_SYMBOL(send_group_sigqueue);
+EXPORT_SYMBOL(register_new_posix_clock);
+EXPORT_SYMBOL(unregister_posix_clock);
+EXPORT_SYMBOL(clock_getres_int);
+EXPORT_SYMBOL(rtx_settime_handling);
+
+#endif /* CONFIG_RTX_DOMAIN */
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [Xenomai-core] Ipipe and Siemens A&D Realtime
2007-04-19 8:54 ` Krause, Karl-Heinz
@ 2007-04-19 12:39 ` Jan Kiszka
2007-04-19 16:09 ` Krause, Karl-Heinz
0 siblings, 1 reply; 7+ messages in thread
From: Jan Kiszka @ 2007-04-19 12:39 UTC (permalink / raw)
To: Krause, Karl-Heinz; +Cc: xenomai
[-- Attachment #1: Type: text/plain, Size: 3811 bytes --]
Krause, Karl-Heinz wrote:
> Hi Jan
>
> Sorry for attaching the wrong patch. Here is the right one.
Thanks. Am I right, it also contains the full A&D RT-kernel?
> From all the ipipe patches/hooks we use only a few one.
> The ipipe changes we did fall into two categories
> - one additional hook in entry.s which checks at system call exit whether
> the thread has to migrate to the realtime domain
> - optimizations for a dual domain system concerning the dispatching of
> events and interrupt handling.
The latter makes me wonder if you already analysed the "wired" top-most
domain optimisation in recent I-pipe and compared it to your approach.
> So if just that kind of dual domain system is of interest, the patches may be of general interest and we are willing to support it.
> To allow for a possible integration we made it configurable as follows
> [ ] interrupt pipeline
> [ ] rtx domain system
> [ ] fast rtx dual domain system
A wired ipipe domain is known to stay the top-most one in the pipeline,
but this optimisation still allows multiple lower domains, not just Linux.
Maybe it is worth looking at the I-pipe abstractions again with the
hard-wired scenario "dual domain system" in mind, checking for further
optimisation possibilities that do not kill the common model and its
clean realisation. Optimisations are not bad, but they also have to be
balanced against potentially increased porting effort for other archs.
>
> Common for both is the check for preemption which we have in the optimized handle_irq routine as well as in sync_stage.
>
> More generic are the patches we made for the POSIX message queues and for saving/restoring the fpu context
IIRC, sanitising xxx_fpu services in order to make them domain-agnostic
without hacking preempt_enable/disable is something of generic interest
for ipipe as well (Or are you patching fpu services for another
reason?). I recall to stumble over this on my own when trying
to detect invalid calls of Linux services from non-root domains
automatically.
>
> We are not specifically locked to 2.6.15.4 and we don't expect any surprises if we would upgrade.
Hmm, I wouldn't be surprised if things like genirq or upcoming
clockevent/hrtimers _will_ cause a few surprises. The latter is actually
also a to-do for vanilla ipipe in order to move to 2.6.21 and beyond.
> (Of course we know that we have to do some additions to hook into PI mutexes, despite the fact that for priority changes itself the domain boundary is already transparent). It is only caused by our general policy to keep the number of different versions minimal, since we cannot simply forget older versions, we have to maintain it.(It is not only a kernel for x86, it is for ARM with and without MMU and for MIPS as well and it is the complete tool chain). So we always will do some skipping and we haven't decided yet what our next version will be.
Does your RT-kernel run on ARM and MIPS as well already? Did you port
ipipe (or a subset) to MIPS?
>
> Concerning testing we took mainly the existing POSIX test suites which we
> had to make suitable for static priorities > 0. We added a few tests for checking the transparency of the domain boundary for POSIX message queues, futexes and priority changes and we combined them with performance measurement that is all.
Those changes may be of some interest for POSIX testing with Xenomai as
well, that's why I was asking for a complete, instrumented testsuite. If
you could share it with the community, that would be great.
>
> Just let me know what else you need.
>
>
> Karl-Heinz
>
Thanks for making your code available. I think both sides can benefit
from discussing new approaches based on public code.
Jan
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 250 bytes --]
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [Xenomai-core] Ipipe and Siemens A&D Realtime
2007-04-19 12:39 ` Jan Kiszka
@ 2007-04-19 16:09 ` Krause, Karl-Heinz
2007-04-19 18:13 ` Philippe Gerum
0 siblings, 1 reply; 7+ messages in thread
From: Krause, Karl-Heinz @ 2007-04-19 16:09 UTC (permalink / raw)
To: jan.kiszka; +Cc: xenomai
Yes, it contains the full A&D RT Kernel.
If it were only the path to ISR entry, there is not much difference to the wired optimization (the main difference is a stripped down ack-Routine). The
problem we saw with the wired-optimzation is, that -- if we want an interrupt dedicated exclusively to the RT domain -- it doesn't provide for a final ack-Routine. We always have to take the entire round trip.
If you look at the comment for the fast handle_irq, you will see what we had in mind.
For the other part --the system call entry/exit -- we simply put it under the same optimization decision, but I guess we can separate it.
The fpu stuff has two parts, first we borrowed somewhat from the 2.6.20 solution to avoid restore on exception, but had to disable the "256-exception". Second we hacked meaning we replaced the preempt_disable/enable in the three low level routines in i387.h, by local interrupt disable/enable. There may be a way around, but since we call the same __switch_to() routine, we had to avoid running into preempt_disable/enable.
Can understand, when I said I don't expect big surprises, then I assumed be based on an existing ipipe-patch. Yes HRT timers are a problem but doesn't cause us to much of a headache right now, since we are required to support only features available on all architectures.
This leads to the last point. No we haven't running RT on ARM and MIPS yet.
The main work so far was to have common base for the tool chain and the glibc. And having a working solution for TLS on ARM without MMU caused us some trouble. But now we are through and I expect having RT on ARM very soon. MIPS is scheduled for the third quarter.
As for the test suite, let me defer it to tomorrow.
Karl-Heinz
-----Ursprüngliche Nachricht-----
Von: jan.kiszka@domain.hid [mailto:jan.kiszka@domain.hid
Gesendet: Donnerstag, 19. April 2007 14:40
An: Krause, Karl-Heinz
Cc: xenomai@xenomai.org
Betreff: Re: AW: [Xenomai-core] Ipipe and Siemens A&D Realtime
Krause, Karl-Heinz wrote:
> Hi Jan
>
> Sorry for attaching the wrong patch. Here is the right one.
Thanks. Am I right, it also contains the full A&D RT-kernel?
> From all the ipipe patches/hooks we use only a few one.
> The ipipe changes we did fall into two categories
> - one additional hook in entry.s which checks at system call exit whether
> the thread has to migrate to the realtime domain
> - optimizations for a dual domain system concerning the dispatching of
> events and interrupt handling.
The latter makes me wonder if you already analysed the "wired" top-most
domain optimisation in recent I-pipe and compared it to your approach.
> So if just that kind of dual domain system is of interest, the patches may be of general interest and we are willing to support it.
> To allow for a possible integration we made it configurable as follows
> [ ] interrupt pipeline
> [ ] rtx domain system
> [ ] fast rtx dual domain system
A wired ipipe domain is known to stay the top-most one in the pipeline,
but this optimisation still allows multiple lower domains, not just Linux.
Maybe it is worth looking at the I-pipe abstractions again with the
hard-wired scenario "dual domain system" in mind, checking for further
optimisation possibilities that do not kill the common model and its
clean realisation. Optimisations are not bad, but they also have to be
balanced against potentially increased porting effort for other archs.
>
> Common for both is the check for preemption which we have in the optimized handle_irq routine as well as in sync_stage.
>
> More generic are the patches we made for the POSIX message queues and for saving/restoring the fpu context
IIRC, sanitising xxx_fpu services in order to make them domain-agnostic
without hacking preempt_enable/disable is something of generic interest
for ipipe as well (Or are you patching fpu services for another
reason?). I recall to stumble over this on my own when trying
to detect invalid calls of Linux services from non-root domains
automatically.
>
> We are not specifically locked to 2.6.15.4 and we don't expect any surprises if we would upgrade.
Hmm, I wouldn't be surprised if things like genirq or upcoming
clockevent/hrtimers _will_ cause a few surprises. The latter is actually
also a to-do for vanilla ipipe in order to move to 2.6.21 and beyond.
> (Of course we know that we have to do some additions to hook into PI mutexes, despite the fact that for priority changes itself the domain boundary is already transparent). It is only caused by our general policy to keep the number of different versions minimal, since we cannot simply forget older versions, we have to maintain it.(It is not only a kernel for x86, it is for ARM with and without MMU and for MIPS as well and it is the complete tool chain). So we always will do some skipping and we haven't decided yet what our next version will be.
Does your RT-kernel run on ARM and MIPS as well already? Did you port
ipipe (or a subset) to MIPS?
>
> Concerning testing we took mainly the existing POSIX test suites which we
> had to make suitable for static priorities > 0. We added a few tests for checking the transparency of the domain boundary for POSIX message queues, futexes and priority changes and we combined them with performance measurement that is all.
Those changes may be of some interest for POSIX testing with Xenomai as
well, that's why I was asking for a complete, instrumented testsuite. If
you could share it with the community, that would be great.
>
> Just let me know what else you need.
>
>
> Karl-Heinz
>
Thanks for making your code available. I think both sides can benefit
from discussing new approaches based on public code.
Jan
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [Xenomai-core] Ipipe and Siemens A&D Realtime
2007-04-19 16:09 ` Krause, Karl-Heinz
@ 2007-04-19 18:13 ` Philippe Gerum
2007-04-20 15:30 ` Krause, Karl-Heinz
0 siblings, 1 reply; 7+ messages in thread
From: Philippe Gerum @ 2007-04-19 18:13 UTC (permalink / raw)
To: Krause, Karl-Heinz; +Cc: jan.kiszka, xenomai
On Thu, 2007-04-19 at 18:09 +0200, Krause, Karl-Heinz wrote:
> Yes, it contains the full A&D RT Kernel.
There seems to be lot of work there. I had a look at this patch, and
basically, it looks like an effort to create an integrated POSIX
co-kernel that does not look like a co-kernel anymore, while still
exhibiting rt and non-rt domain separation though. This seems to have
required adding new real-time support in vanilla code, and ironing other
parts of the original code in order to allow mixed uses between both
domains (hence the glibc patching too).
>
> If it were only the path to ISR entry, there is not much difference to the wired optimization (the main difference is a stripped down ack-Routine).
Perhaps a bit too much stripped down; I see you don't handle the per-IRQ
locking bit anymore, which means that RT drivers are not allowed to
solely rely on the PIC to mask interrupts without going for
local_irq_disable(). This said, only vanilla Linux drivers might rely on
this trick, so this is ok in the fast mode approach, I guess.
> The
> problem we saw with the wired-optimzation is, that -- if we want an interrupt dedicated exclusively to the RT domain -- it doesn't provide for a final ack-Routine.
It does since genirq is supported by the I-pipe; it's the ipipe_end
handler from the irq descriptor.
> We always have to take the entire round trip.
It's due to the way this co-kernel is layered, but that's not a
requirement. For instance, Xenomai ISRs are in charge of ending the
interrupt by calling the ipipe_end hook for the processed IRQ channel;
this is no different than ending it upon return from your ISR to
__ipipe_handle_irq, except that the vanilla I-pipe never overrides any
decision the RTOS ISR could make regarding PIC manipulation.
> If you look at the comment for the fast handle_irq, you will see what we had in mind.
> For the other part --the system call entry/exit -- we simply put it under the same optimization decision, but I guess we can separate it.
>
I recall we once discussed about the SYSCALL_EXIT event, but did not
catch the idea behind this requirement, i.e. forcing a relaxed thread
back to the real-time domain after a syscall. Is there any reason why
you don't want the lazy scheme to be used, i.e. migrate to whatever
domain may process any given syscall upon entry, run the handler, then
leave the caller running in the current domain until the next syscall
occurs?
> The fpu stuff has two parts, first we borrowed somewhat from the 2.6.20 solution to avoid restore on exception, but had to disable the "256-exception". Second we hacked meaning we replaced the preempt_disable/enable in the three low level routines in i387.h, by local interrupt disable/enable. There may be a way around, but since we call the same __switch_to() routine, we had to avoid running into preempt_disable/enable.
>
> Can understand, when I said I don't expect big surprises, then I assumed be based on an existing ipipe-patch. Yes HRT timers are a problem but doesn't cause us to much of a headache right now, since we are required to support only features available on all architectures.
>
Generally speaking, this code has to know about a lot of kernel innards
through. I understand this is due to the effort to integrate this
co-kernel into the vanilla one, so that it does not look like a separate
extension anymore.
> This leads to the last point. No we haven't running RT on ARM and MIPS yet.
> The main work so far was to have common base for the tool chain and the glibc. And having a working solution for TLS on ARM without MMU caused us some trouble. But now we are through and I expect having RT on ARM very soon. MIPS is scheduled for the third quarter.
>
How much much would it require to be able to run more than a single RT
process? Is this only related to the RT futex support, or are there
other issues to solve?
> As for the test suite, let me defer it to tomorrow.
>
> Karl-Heinz
>
>
>
>
> -----Ursprüngliche Nachricht-----
> Von: jan.kiszka@domain.hid [mailto:jan.kiszka@domain.hid]
> Gesendet: Donnerstag, 19. April 2007 14:40
> An: Krause, Karl-Heinz
> Cc: xenomai@xenomai.org
> Betreff: Re: AW: [Xenomai-core] Ipipe and Siemens A&D Realtime
>
> Krause, Karl-Heinz wrote:
> > Hi Jan
> >
> > Sorry for attaching the wrong patch. Here is the right one.
>
> Thanks. Am I right, it also contains the full A&D RT-kernel?
>
> > From all the ipipe patches/hooks we use only a few one.
> > The ipipe changes we did fall into two categories
> > - one additional hook in entry.s which checks at system call exit whether
> > the thread has to migrate to the realtime domain
> > - optimizations for a dual domain system concerning the dispatching of
> > events and interrupt handling.
>
> The latter makes me wonder if you already analysed the "wired" top-most
> domain optimisation in recent I-pipe and compared it to your approach.
>
> > So if just that kind of dual domain system is of interest, the patches may be of general interest and we are willing to support it.
> > To allow for a possible integration we made it configurable as follows
> > [ ] interrupt pipeline
> > [ ] rtx domain system
> > [ ] fast rtx dual domain system
>
> A wired ipipe domain is known to stay the top-most one in the pipeline,
> but this optimisation still allows multiple lower domains, not just Linux.
>
> Maybe it is worth looking at the I-pipe abstractions again with the
> hard-wired scenario "dual domain system" in mind, checking for further
> optimisation possibilities that do not kill the common model and its
> clean realisation. Optimisations are not bad, but they also have to be
> balanced against potentially increased porting effort for other archs.
>
> >
> > Common for both is the check for preemption which we have in the optimized handle_irq routine as well as in sync_stage.
> >
> > More generic are the patches we made for the POSIX message queues and for saving/restoring the fpu context
>
> IIRC, sanitising xxx_fpu services in order to make them domain-agnostic
> without hacking preempt_enable/disable is something of generic interest
> for ipipe as well (Or are you patching fpu services for another
> reason?). I recall to stumble over this on my own when trying
> to detect invalid calls of Linux services from non-root domains
> automatically.
>
> >
> > We are not specifically locked to 2.6.15.4 and we don't expect any surprises if we would upgrade.
>
> Hmm, I wouldn't be surprised if things like genirq or upcoming
> clockevent/hrtimers _will_ cause a few surprises. The latter is actually
> also a to-do for vanilla ipipe in order to move to 2.6.21 and beyond.
>
> > (Of course we know that we have to do some additions to hook into PI mutexes, despite the fact that for priority changes itself the domain boundary is already transparent). It is only caused by our general policy to keep the number of different versions minimal, since we cannot simply forget older versions, we have to maintain it.(It is not only a kernel for x86, it is for ARM with and without MMU and for MIPS as well and it is the complete tool chain). So we always will do some skipping and we haven't decided yet what our next version will be.
>
> Does your RT-kernel run on ARM and MIPS as well already? Did you port
> ipipe (or a subset) to MIPS?
>
> >
> > Concerning testing we took mainly the existing POSIX test suites which we
> > had to make suitable for static priorities > 0. We added a few tests for checking the transparency of the domain boundary for POSIX message queues, futexes and priority changes and we combined them with performance measurement that is all.
>
> Those changes may be of some interest for POSIX testing with Xenomai as
> well, that's why I was asking for a complete, instrumented testsuite. If
> you could share it with the community, that would be great.
>
> >
> > Just let me know what else you need.
> >
> >
> > Karl-Heinz
> >
>
> Thanks for making your code available. I think both sides can benefit
> from discussing new approaches based on public code.
>
> Jan
>
>
>
> _______________________________________________
> Xenomai-core mailing list
> Xenomai-core@domain.hid
> https://mail.gna.org/listinfo/xenomai-core
--
Philippe.
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [Xenomai-core] Ipipe and Siemens A&D Realtime
2007-04-19 18:13 ` Philippe Gerum
@ 2007-04-20 15:30 ` Krause, Karl-Heinz
0 siblings, 0 replies; 7+ messages in thread
From: Krause, Karl-Heinz @ 2007-04-20 15:30 UTC (permalink / raw)
To: rpm; +Cc: jan.kiszka, xenomai
Hi Philippe,
thanks a lot for your comments
First to the overall positioning: My answer is yes and no
Yes you can view it that way, although I'm not quite sure what you exactly mean with "POSIX co-kernel that does not look like a co-kernel". But no with respect to the "mixing consequences". With other words, the changes we did to the library are not necessary because of the two kernel approach, they are necessary if you want to provide for realtime capability in general. For e.g. the implementation of the pthread_spinlock function in 2.3.6 cannot be used for static priorities > 0. (Since they are not protected by some kind of "scheduling lock", a system could get locked up). But using static priorities is a must for realtime.(But on the other side regular prio 0 processes by no means are allowed to get control over the CPU). So an RT_PREEMPT solution faces the same problem.
The changes we did to the sigevent handler notification are also completely independent of that. You simply cannot afford having a thread creation inside a time critical notification path. I admit the implementation of the changes itself has to consider the two kernel approach( the protection function for the spinlock has span two domains, for the sigevent handler we need two default thread_attribute objects).
For the kernel changes it is mixed. Yes we need three additional hooks (futex.c, mqueue., posix-timers.c) They are necessary for transparent communication and for tracking time across clock_setime(). But no with respect to a function where a device can provide a tick for a new clock type. POSIX allows for additional clocks but posix-timers.c doesn't export a function for safely allocating a new clock. An no with respect to the implementation of mq_send()/mq_receive(). The POSIX definition allows for a completely deterministic implemention, but the Linux implementation does
dynamic allocation from a slab pool. Again RT_PREEMPT faces the same problem.
Sharing the changed FPU routines is also not caused by the two kernel approach, it was basically a matter of saving work by using existing code an by not figuring out what it takes to have FPU save/restore interruptible.
The ISR stuff:
I haven't looked into the ipipe for genirq. In our pre genirq version we didn't find a place where to put end_ack and we cannot have it placed in the ISR itself.
I'll give it a try.
SYSCALL_EXIT event:
I don't know how to explain best the requirement that a thread as soon as
it is in user mode must be in its "home" domain. If that is not guaranteed our approach would fall apart.
One example:
Lets assume the last system call of a thread running in the realtime domain would be a mq_open() (end of a setup phase) and the next system call would be a sigtimedwait(). To route the system call to the realtime domain the thread must already execute in the realtime domain. Does this make sense?
If not then I have to dig deeper listing the other reasons dealing with decoupling of signalling of the two domains.
More RT processes:
Futexes have been surely the initial reason to restrict to one process.
Now in the light of RT-PREEMPT we see even less need as we may had seen initially. (the better the realtime capability of the base system,the more
we need to serve the hardcore realtime only).
The fact that the Linux kernel developers consider the introduction of local futexes encourages us to stay with that.
Testsuite (Jan):
We use the POSIX testsuite adapitestsuite-1.4.3. The sourc we loaded from sourceforge. Besides using only the part which deals with the calls, we additionally had to do some subsetting which is in line with our "subset API definition". For example: Since signal handlers for asynchronous events are an indeterministic construct and not usable for realtime, we deleted them.
Besides subsetting we added a few scripts for easier handling and a prolog which gets linked to a test. This prolog brings main to the right scheduling policy and priority. Of cources there have been a few tests which implicitly assumed prio 0 with SCHED_OTHER.
To figure out possible synergy I doesn't know enough about your build and runtime environment. Just let me know.
Don't be surprised about radio silence, I'll be in vacation for a week.
Karl-Heinz
-----Ursprüngliche Nachricht-----
Von: Philippe Gerum [mailto:philippe.gerum@domain.hid] Im Auftrag von Philippe Gerum
Gesendet: Donnerstag, 19. April 2007 20:14
An: Krause, Karl-Heinz
Cc: jan.kiszka@domain.hid; xenomai@xenomai.org
Betreff: Re: [Xenomai-core] Ipipe and Siemens A&D Realtime
On Thu, 2007-04-19 at 18:09 +0200, Krause, Karl-Heinz wrote:
> Yes, it contains the full A&D RT Kernel.
There seems to be lot of work there. I had a look at this patch, and
basically, it looks like an effort to create an integrated POSIX
co-kernel that does not look like a co-kernel anymore, while still
exhibiting rt and non-rt domain separation though. This seems to have
required adding new real-time support in vanilla code, and ironing other
parts of the original code in order to allow mixed uses between both
domains (hence the glibc patching too).
>
> If it were only the path to ISR entry, there is not much difference to the wired optimization (the main difference is a stripped down ack-Routine).
Perhaps a bit too much stripped down; I see you don't handle the per-IRQ
locking bit anymore, which means that RT drivers are not allowed to
solely rely on the PIC to mask interrupts without going for
local_irq_disable(). This said, only vanilla Linux drivers might rely on
this trick, so this is ok in the fast mode approach, I guess.
> The
> problem we saw with the wired-optimzation is, that -- if we want an interrupt dedicated exclusively to the RT domain -- it doesn't provide for a final ack-Routine.
It does since genirq is supported by the I-pipe; it's the ipipe_end
handler from the irq descriptor.
> We always have to take the entire round trip.
It's due to the way this co-kernel is layered, but that's not a
requirement. For instance, Xenomai ISRs are in charge of ending the
interrupt by calling the ipipe_end hook for the processed IRQ channel;
this is no different than ending it upon return from your ISR to
__ipipe_handle_irq, except that the vanilla I-pipe never overrides any
decision the RTOS ISR could make regarding PIC manipulation.
> If you look at the comment for the fast handle_irq, you will see what we had in mind.
> For the other part --the system call entry/exit -- we simply put it under the same optimization decision, but I guess we can separate it.
>
I recall we once discussed about the SYSCALL_EXIT event, but did not
catch the idea behind this requirement, i.e. forcing a relaxed thread
back to the real-time domain after a syscall. Is there any reason why
you don't want the lazy scheme to be used, i.e. migrate to whatever
domain may process any given syscall upon entry, run the handler, then
leave the caller running in the current domain until the next syscall
occurs?
> The fpu stuff has two parts, first we borrowed somewhat from the 2.6.20 solution to avoid restore on exception, but had to disable the "256-exception". Second we hacked meaning we replaced the preempt_disable/enable in the three low level routines in i387.h, by local interrupt disable/enable. There may be a way around, but since we call the same __switch_to() routine, we had to avoid running into preempt_disable/enable.
>
> Can understand, when I said I don't expect big surprises, then I assumed be based on an existing ipipe-patch. Yes HRT timers are a problem but doesn't cause us to much of a headache right now, since we are required to support only features available on all architectures.
>
Generally speaking, this code has to know about a lot of kernel innards
through. I understand this is due to the effort to integrate this
co-kernel into the vanilla one, so that it does not look like a separate
extension anymore.
> This leads to the last point. No we haven't running RT on ARM and MIPS yet.
> The main work so far was to have common base for the tool chain and the glibc. And having a working solution for TLS on ARM without MMU caused us some trouble. But now we are through and I expect having RT on ARM very soon. MIPS is scheduled for the third quarter.
>
How much much would it require to be able to run more than a single RT
process? Is this only related to the RT futex support, or are there
other issues to solve?
> As for the test suite, let me defer it to tomorrow.
>
> Karl-Heinz
>
>
>
>
> -----Ursprüngliche Nachricht-----
> Von: jan.kiszka@domain.hid [mailto:jan.kiszka@domain.hid
> Gesendet: Donnerstag, 19. April 2007 14:40
> An: Krause, Karl-Heinz
> Cc: xenomai@xenomai.org
> Betreff: Re: AW: [Xenomai-core] Ipipe and Siemens A&D Realtime
>
> Krause, Karl-Heinz wrote:
> > Hi Jan
> >
> > Sorry for attaching the wrong patch. Here is the right one.
>
> Thanks. Am I right, it also contains the full A&D RT-kernel?
>
> > From all the ipipe patches/hooks we use only a few one.
> > The ipipe changes we did fall into two categories
> > - one additional hook in entry.s which checks at system call exit whether
> > the thread has to migrate to the realtime domain
> > - optimizations for a dual domain system concerning the dispatching of
> > events and interrupt handling.
>
> The latter makes me wonder if you already analysed the "wired" top-most
> domain optimisation in recent I-pipe and compared it to your approach.
>
> > So if just that kind of dual domain system is of interest, the patches may be of general interest and we are willing to support it.
> > To allow for a possible integration we made it configurable as follows
> > [ ] interrupt pipeline
> > [ ] rtx domain system
> > [ ] fast rtx dual domain system
>
> A wired ipipe domain is known to stay the top-most one in the pipeline,
> but this optimisation still allows multiple lower domains, not just Linux.
>
> Maybe it is worth looking at the I-pipe abstractions again with the
> hard-wired scenario "dual domain system" in mind, checking for further
> optimisation possibilities that do not kill the common model and its
> clean realisation. Optimisations are not bad, but they also have to be
> balanced against potentially increased porting effort for other archs.
>
> >
> > Common for both is the check for preemption which we have in the optimized handle_irq routine as well as in sync_stage.
> >
> > More generic are the patches we made for the POSIX message queues and for saving/restoring the fpu context
>
> IIRC, sanitising xxx_fpu services in order to make them domain-agnostic
> without hacking preempt_enable/disable is something of generic interest
> for ipipe as well (Or are you patching fpu services for another
> reason?). I recall to stumble over this on my own when trying
> to detect invalid calls of Linux services from non-root domains
> automatically.
>
> >
> > We are not specifically locked to 2.6.15.4 and we don't expect any surprises if we would upgrade.
>
> Hmm, I wouldn't be surprised if things like genirq or upcoming
> clockevent/hrtimers _will_ cause a few surprises. The latter is actually
> also a to-do for vanilla ipipe in order to move to 2.6.21 and beyond.
>
> > (Of course we know that we have to do some additions to hook into PI mutexes, despite the fact that for priority changes itself the domain boundary is already transparent). It is only caused by our general policy to keep the number of different versions minimal, since we cannot simply forget older versions, we have to maintain it.(It is not only a kernel for x86, it is for ARM with and without MMU and for MIPS as well and it is the complete tool chain). So we always will do some skipping and we haven't decided yet what our next version will be.
>
> Does your RT-kernel run on ARM and MIPS as well already? Did you port
> ipipe (or a subset) to MIPS?
>
> >
> > Concerning testing we took mainly the existing POSIX test suites which we
> > had to make suitable for static priorities > 0. We added a few tests for checking the transparency of the domain boundary for POSIX message queues, futexes and priority changes and we combined them with performance measurement that is all.
>
> Those changes may be of some interest for POSIX testing with Xenomai as
> well, that's why I was asking for a complete, instrumented testsuite. If
> you could share it with the community, that would be great.
>
> >
> > Just let me know what else you need.
> >
> >
> > Karl-Heinz
> >
>
> Thanks for making your code available. I think both sides can benefit
> from discussing new approaches based on public code.
>
> Jan
>
>
>
> _______________________________________________
> Xenomai-core mailing list
> Xenomai-core@domain.hid
> https://mail.gna.org/listinfo/xenomai-core
--
Philippe.
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2007-04-20 15:30 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-04-18 15:07 [Xenomai-core] Ipipe and Siemens A&D Realtime Krause, Karl-Heinz
2007-04-18 17:53 ` Jan Kiszka
2007-04-19 8:54 ` Krause, Karl-Heinz
2007-04-19 12:39 ` Jan Kiszka
2007-04-19 16:09 ` Krause, Karl-Heinz
2007-04-19 18:13 ` Philippe Gerum
2007-04-20 15:30 ` Krause, Karl-Heinz
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.