Ticket #1247: PR#1247-rtems-newlibc-locking.diff

File PR#1247-rtems-newlibc-locking.diff, 11.1 KB (added by strauman, on 08/23/07 at 23:53:38)

Implements locks needed by newlib

Line 
1 - this patch addresses PR#1247; it implements the mutexes required
2   to support proper locking for global newlib datastructures.
3 - new: cpukit/libcsupport/src/newlib_locks.c
4 - obsoletes: cpukit/libcsupport/src/envlock.c
5 - NOTE: configurable parameter NEWLIBC_USE_SHARED_GBL_LOCK
6         (consult newlib_locks.c for details)
7 - NOTE: NEWLIB ALSO NEEDS TO BE PATCHED -- otherwise the locks
8         won't be used. The newlib patch introduces sys/rtems/sys/lock.h
9                 (compilation of patched rtems with unpatched newlib headers
10                 will fail).
11
12Index: cpukit/libcsupport/Makefile.am
13===================================================================
14RCS file: /usr1/CVS/rtems/cpukit/libcsupport/Makefile.am,v
15retrieving revision 1.69.2.3
16diff -c -r1.69.2.3 Makefile.am
17*** cpukit/libcsupport/Makefile.am      28 Mar 2007 18:58:32 -0000      1.69.2.3
18--- cpukit/libcsupport/Makefile.am      20 Jun 2007 04:34:49 -0000
19***************
20*** 71,77 ****
21 
22  LIBC_GLUE_C_FILES = src/__getpid.c src/__gettod.c src/__times.c \
23      src/truncate.c src/access.c src/stat.c src/lstat.c src/pathconf.c \
24!     src/newlibc.c src/no_posix.c src/no_libc.c src/utsname.c
25 
26  BSD_LIBC_C_FILES = src/strlcpy.c src/strlcat.c
27 
28--- 71,77 ----
29 
30  LIBC_GLUE_C_FILES = src/__getpid.c src/__gettod.c src/__times.c \
31      src/truncate.c src/access.c src/stat.c src/lstat.c src/pathconf.c \
32!     src/newlibc.c src/newlibc_locks.c src/no_posix.c src/no_libc.c src/utsname.c
33 
34  BSD_LIBC_C_FILES = src/strlcpy.c src/strlcat.c
35 
36***************
37*** 84,90 ****
38  else
39  libcsupport_a_SOURCES += $(LIBC_GLUE_C_FILES) $(PASSWORD_GROUP_C_FILES) \
40      $(TERMINAL_IDENTIFICATION_C_FILES) $(SYSTEM_CALL_C_FILES) \
41!     $(DIRECTORY_SCAN_C_FILES) $(ID_C_FILES) src/envlock.c \
42      $(TERMIOS_C_FILES) src/getpagesize.c
43  endif
44 
45--- 84,90 ----
46  else
47  libcsupport_a_SOURCES += $(LIBC_GLUE_C_FILES) $(PASSWORD_GROUP_C_FILES) \
48      $(TERMINAL_IDENTIFICATION_C_FILES) $(SYSTEM_CALL_C_FILES) \
49!     $(DIRECTORY_SCAN_C_FILES) $(ID_C_FILES) \
50      $(TERMIOS_C_FILES) src/getpagesize.c
51  endif
52 
53*** cpukit/libcsupport/src/envlock.c.orig       2007-06-19 17:07:10.000000000 -0700
54--- cpukit/libcsupport/src/envlock.c    1969-12-31 16:00:00.000000000 -0800
55***************
56*** 1,108 ****
57- /*
58-  *  Author: Till Straumann <strauman@slac.stanford.edu>, 3/2002
59-  *
60-  *  $Id: envlock.c,v 1.3 2004/04/18 06:05:34 ralf Exp $
61-  */
62-
63- /* provide locking for the global environment 'environ' */
64-
65- #if HAVE_CONFIG_H
66- #include "config.h"
67- #endif
68-
69- #include <rtems.h>
70- #include <sys/reent.h>
71-
72- #include <assert.h>
73-
74- /*
75-  * NOTES:
76-  *  - although it looks like a classical multiple-readers / single writer (MRSW)
77-  *    locking problem, we still use a single lock for the following reasons:
78-  *     1) newlib has no provision / hook for calling different locking routines
79-  *        from setenv/putenv and getenv, respectively.
80-  *     2) MRSW involves calling several semaphore-primitives, even in the most
81-  *        likely case of a first-reader's access. This probably takes more CPU
82-  *        time than just waiting until another reader is done; environment
83-  *        access is fast.
84-  *  - the lock implementation must allow nesting (same thread may call
85-  *    lock-lock-unlock-unlock).
86-  *  - NEWLIB-1.8.2 has an ugly BUG: if environ is NULL, _findenv_r() bails
87-  *    out leaving the lock held :-(
88-  *
89-  *  Used by the following functions:
90-  *    findenv_r(), setenv_r(), and unsetenv_r() which are called by
91-  *    getenv(), getenv_r(), setenv(), and unsetenv().
92-  *
93-  */
94-
95- #if defined(ENVLOCK_DEDIDCATED_MUTEX)
96- static rtems_id envLock=0;
97-
98- static void
99- __rtems_envlock_init(void)
100- {
101-   extern char        **environ;
102-   rtems_status_code    rc;
103-
104-   if (envLock) /* already initialized */
105-     return;
106-
107-   assert(environ && "MUST have non-NULL 'environ' due to newlib bug");
108-
109-   rc = rtems_semaphore_create(
110-       rtems_build_name('E','N','V','S'),
111-       1,
112-       RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY | RTEMS_INHERIT_PRIORITY,
113-       0,
114-       &envLock);
115-   if (RTEMS_SUCCESSFUL!=rc)
116-     rtems_fatal_error_occurred(rc);
117- }
118-
119- void
120- __env_lock(struct _reent *r)
121- {
122-   /* Do lazy init */
123-   if (!envLock)
124-     __rtems_envlock_init();
125-   /*
126-    *  Must not use a semaphore before pre-tasking hook is called.
127-    *  - it will corrupt memory :-(
128-    */
129-
130-   if (_Thread_Executing)
131-     rtems_semaphore_obtain(envLock, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
132- }
133-
134- void
135- __env_unlock(struct _reent *r)
136- {
137-   /*
138-    *  Must not use a semaphore before pre-tasking hook is called.
139-    * - it will corrupt memory :-(
140-    */
141-   if (_Thread_Executing)
142-     rtems_semaphore_release(envLock);
143- }
144- #else
145-
146- /*
147-  *  Reuse the libio mutex -- it is always initialized before we
148-  *  could possibly run.
149-  */
150-
151- #include <rtems/libio_.h>
152-
153- void
154- __env_lock(struct _reent *r)
155- {
156-   rtems_semaphore_obtain( rtems_libio_semaphore, RTEMS_WAIT, RTEMS_NO_TIMEOUT );
157- }
158-
159- void
160- __env_unlock(struct _reent *r)
161- {
162-   rtems_semaphore_release( rtems_libio_semaphore );
163- }
164- #endif
165--- 0 ----
166*** cpukit/libcsupport/src/newlibc_locks.c.orig 1969-12-31 16:00:00.000000000 -0800
167--- cpukit/libcsupport/src/newlibc_locks.c      2007-06-20 16:53:08.000000000 -0700
168***************
169*** 0 ****
170--- 1,222 ----
171+ /* $Id$ */
172+
173+ /* Implement newlibc locks used by the library to protect internal
174+  * data structures.
175+  */
176+
177+ /* Till Straumann <strauman@slac.stanford.edu>, 2007
178+  *
179+  *  The license and distribution terms for this file may be
180+  *  found in the file LICENSE in this distribution or at
181+  *  http://www.rtems.com/license/LICENSE.
182+  */
183+
184+ /* Follows the implementation of the networking semaphore by Eric Norum */
185+
186+ /* Care has been taken so that this file is only linked if a newlib
187+  * facility that needs locking is linked.
188+  */
189+
190+ #if HAVE_CONFIG_H
191+ #include "config.h"
192+ #endif
193+
194+ #if defined(RTEMS_NEWLIB)
195+
196+ #define __RTEMS_VIOLATE_KERNEL_VISIBILITY__
197+ #include <rtems.h>
198+ #include <rtems/score/coremutex.h>
199+ #include <rtems/score/thread.h>
200+ #include <rtems/error.h>
201+
202+ #if defined(RTEMS_MULTIPROCESSING)
203+ #include <rtems/score/mpci.h>
204+ #endif
205+
206+ #include <sys/lock.h>
207+
208+ /* Compile-time options              */
209+
210+ /* debug messages */
211+ #define  DEBUG 0
212+ /* use one single shared lock; this saves resources but
213+  * has the side-effect of e.g., blocking threads calling 'getenv()'
214+  * until another thread is done with 'fclose()'.
215+  */
216+ #undef  NEWLIBC_USE_SHARED_GBL_LOCK
217+
218+ #ifdef DEBUG
219+ #include <rtems/bspIo.h>
220+ int __rtems_libc_lock_debug = DEBUG;
221+ #endif
222+
223+ void __rtems_libc_lock_create_recursive(_LOCK_RECURSIVE_T *plock);
224+
225+ #ifdef NEWLIBC_USE_SHARED_GBL_LOCK
226+ static struct __RTEMS_libc_lock_opaque * volatile theGblLock = 0;
227+ #endif
228+
229+ /* For reference:
230+ typedef struct __RTEMS_libc_lock_opaque * _LOCK_T;
231+ typedef _LOCK_T _LOCK_RECURSIVE_T;
232+ */
233+
234+ void __rtems_libc_lock_create_recursive(_LOCK_RECURSIVE_T *plock)
235+ {
236+ rtems_id          id;
237+ Objects_Locations loc;
238+ Semaphore_Control *l;
239+ rtems_status_code st;
240+
241+       st = rtems_semaphore_create(
242+               rtems_build_name('l','i','b','c'),
243+               1,
244+               RTEMS_LOCAL
245+               | RTEMS_PRIORITY
246+               | RTEMS_BINARY_SEMAPHORE
247+               | RTEMS_INHERIT_PRIORITY
248+               | RTEMS_NO_PRIORITY_CEILING
249+               ,
250+               0,
251+               &id);
252+
253+       if ( st != RTEMS_SUCCESSFUL )
254+               rtems_panic("__rtems_libc_lock_create_recursive: %s\n", rtems_status_text(st));
255+       l = _Semaphore_Get( id, &loc );
256+       _Thread_Enable_dispatch();
257+
258+ #ifdef DEBUG
259+       if ( __rtems_libc_lock_debug )
260+               printk("Created Lock %p (TID 0x%08x)\n", l, _Thread_Executing ? _Thread_Executing->Object.id : 0);
261+ #endif
262+       
263+       *plock = (_LOCK_RECURSIVE_T)l;
264+ }
265+
266+ void __rtems_libc_lock_close_recursive(_LOCK_RECURSIVE_T *plock)
267+ {
268+ Semaphore_Control *l = (Semaphore_Control*)*plock;
269+ rtems_status_code st;
270+
271+ #ifdef NEWLIBC_USE_SHARED_GBL_LOCK
272+       /* don't close the shared lock; this test allows coexistence
273+        * of a shared lock and individual locks.
274+        */
275+       if ( l == (Semaphore_Control*)theGblLock ) {
276+               *plock = 0;
277+               return; /* don't close the shared lock */
278+       }
279+ #endif
280+
281+       if ( l ) {
282+               st = rtems_semaphore_delete( l->Object.id );
283+               if ( RTEMS_SUCCESSFUL != st ) {
284+                       rtems_panic("__rtems_libc_lock_close_recursive: %s\n",rtems_status_text(st));
285+               }
286+               *plock = 0;
287+ #ifdef DEBUG
288+               if ( __rtems_libc_lock_debug )
289+                       printk("Deleted Lock %p (TID 0x%08x)\n", l, _Thread_Executing ? _Thread_Executing->Object.id : 0);
290+ #endif
291+       }
292+ }
293+
294+ /* do thread-safe lazy init and acquire lock */
295+ int __rtems_libc_lock_acquire_recursive(volatile _LOCK_RECURSIVE_T *plock, int wait)
296+ {
297+ _LOCK_RECURSIVE_T l;
298+ ISR_Level         level;
299+ CORE_mutex_Status s;
300+
301+       if ( ! (l = *plock) ) {
302+
303+               /* Lazy init required */
304+
305+ #ifdef NEWLIBC_USE_SHARED_GBL_LOCK
306+               if ( ! ( l = theGblLock ) )
307+               /* 1st use of single GBL lock; must create */
308+ #endif
309+               {
310+                       volatile _LOCK_RECURSIVE_T *nplock;
311+ #ifdef NEWLIBC_USE_SHARED_GBL_LOCK
312+                       nplock = &theGblLock;
313+ #else
314+                       nplock = plock;
315+ #endif
316+                       /* create a lock upfront. Then try to register it */
317+                       __rtems_libc_lock_create_recursive( &l );
318+                       _ISR_Disable( level );
319+                       /* still no lock ? */
320+                       if ( 0 == *nplock ) {
321+                               /* register our new lock */
322+                               *nplock  = l;
323+                               _ISR_Enable( level );
324+                       } else {
325+                               /* race condition: someone else registered theirs first */
326+                               _ISR_Enable( level );
327+                               __rtems_libc_lock_close_recursive( &l );
328+                               l = *nplock;
329+                       }
330+               }
331+ #ifdef NEWLIBC_USE_SHARED_GBL_LOCK
332+               /* At this point 'l == theGblLock' */
333+               *plock = l;
334+ #endif
335+       }
336+
337+       if ( _Thread_Executing ) {
338+ #ifdef DEBUG
339+               if ( __rtems_libc_lock_debug )
340+                       printk("Taking Lock %p (TID 0x%08x)\n", l, _Thread_Executing->Object.id);
341+ #endif
342+               _ISR_Disable( level );
343+               _CORE_mutex_Seize(
344+                       &((Semaphore_Control *)l)->Core_control.mutex,
345+                       ((Semaphore_Control *)l)->Object.id,
346+                       wait ? TRUE : FALSE,
347+                       0, /* other possiblity: (-1 == wait ? 0 : wait) to support timeout but
348+                           * result checking code below has to be adapted, too.
349+                               */
350+                       level
351+                       );
352+               s = _Thread_Executing->Wait.return_code;       
353+               if ( CORE_MUTEX_STATUS_SUCCESSFUL != s ) {
354+                       if ( CORE_MUTEX_STATUS_UNSATISFIED_NOWAIT != s || wait ) {
355+                               rtems_panic("__rtems_libc_lock_acquire_recursive: status %i\n",s);
356+                       }
357+ #ifdef DEBUG
358+                       if ( __rtems_libc_lock_debug )
359+                               printk("Lock %p is busy\n", l);
360+ #endif
361+                       return 1;
362+               }
363+       }
364+ #ifdef DEBUG
365+       if ( __rtems_libc_lock_debug )
366+               printk("Obtained Lock %p\n", l);
367+ #endif
368+       return 0;
369+ }
370+
371+ void __rtems_libc_lock_release_recursive(_LOCK_RECURSIVE_T *plock)
372+ {
373+ Semaphore_Control *l = (Semaphore_Control *)*plock;
374+ int               i;
375+
376+ #ifdef DEBUG
377+       if ( __rtems_libc_lock_debug )
378+               printk("Releasing Lock %p (TID 0x%08x)\n", l, _Thread_Executing ? _Thread_Executing->Object.id : 0);
379+ #endif
380+
381+       /* Must not use mutex if multithreading is not up yet */
382+       if ( l && _Thread_Executing ) {
383+               _Thread_Disable_dispatch();
384+               i = _CORE_mutex_Surrender( &l->Core_control.mutex, l->Object.id, 0 );
385+               _Thread_Enable_dispatch();
386+               if ( i ) {
387+                       rtems_panic("__rtems_libc_lock_release_recursive: failed with %i\n", i);
388+               }
389+       }
390+ }
391+
392+ #endif /* defined(RTEMS_NEWLIB) */