newlib-cygwin/newlib/libc/sys/or1k/mlock.c
Stafford Horne 8e53c58759 or1k: Fix compiler warnings
In my build the below are treated as error now and causing failures.  I
have described the fixes of each warning below.

In newlib/libc/sys/or1k/mlock.c:

      CC       libc/sys/or1k/libc_a-mlock.o
    newlib/libc/sys/or1k/mlock.c: In function ‘__malloc_lock’:
    newlib/libc/sys/or1k/mlock.c:56:19: warning: implicit declaration of function ‘or1k_critical_begin’ [-Wimplicit-function-declaration]
       56 |         restore = or1k_critical_begin();
	  |                   ^~~~~~~~~~~~~~~~~~~
    newlib/libc/sys/or1k/mlock.c: In function ‘__malloc_unlock’:
    newlib/libc/sys/or1k/mlock.c:93:17: warning: implicit declaration of function ‘or1k_critical_end’ [-Wimplicit-function-declaration]
       93 |                 or1k_critical_end(restore);
	  |                 ^~~~~~~~~~~~~~~~~

This patch adds prototypes for functions or1k_critical_begin and
or1k_critical_end to suppress the warning, inline with what we do for
or1k_sync_cas.

In libgloss/or1k/or1k_uart.c:

    libgloss/or1k/or1k_uart.c: In function ‘or1k_uart_set_read_cb’:
    libgloss/or1k/or1k_uart.c:163:25: warning: passing argument 2 of ‘or1k_interrupt_handler_add’ from incompatible pointer type [-Wincompatible-pointer-types]
      163 |                         _or1k_uart_interrupt_handler, 0);
	  |                         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
	  |                         |
	  |                         void (*)(uint32_t) {aka void (*)(long unsigned int)}
    In file included from libgloss/or1k/or1k_uart.c:19:
    libgloss/or1k/include/or1k-support.h:97:45: note: expected ‘or1k_interrupt_handler_fptr’ {aka ‘void (*)(void *)’} but argument is of type ‘void (*)(uint32_t)’ {aka ‘void (*)(long unsigned int)’}
       97 |                 or1k_interrupt_handler_fptr handler,
	  |                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~

The public API is ‘void (*)(void *)' for our interrupt handlers.  The
function _or1k_uart_interrupt_hander is the internal default
implementation of the uart IRQ handler and it doesn't use the data
argument.

This patch updates the _or1k_uart_interrupt_handler argument type from
uint32_t to void* allowing the function prototype to match the required
prototype.

If we did have a 64-bit implementation it would be an ABI issue. But,
there never has been one, or1k is only 32-bit.

In libgloss/or1k/interrupts.c:

    libgloss/or1k/interrupts.c: In function ‘or1k_interrupt_handler_add’:
    libgloss/or1k/interrupts.c:41:52: warning: assignment to ‘void *’ from ‘long unsigned int’ makes pointer from integer without a cast [-Wint-conversion]
       41 |         _or1k_interrupt_handler_data_ptr_table[id] = (uint32_t) data_ptr;
	  |                                                    ^

The table _or1k_interrupt_handler_data_ptr_table is an array of void*
and data_ptr is void*.  There is no need for the cast so remove it.

In libgloss/or1k/sbrk.c:

    libgloss/or1k/sbrk.c:23:29: warning: initialization of ‘uint32_t’ {aka ‘long unsigned int’} from ‘uint32_t *’ {aka ‘long unsigned int *’} makes integer from pointer without a cast [-Wint-conversion]
       23 | uint32_t _or1k_heap_start = &end;
	  |

This patch adds a cast, which is safe in or1k as the architecture in
32-bit only.  But this code would not be 64-compatible.

Signed-off-by: Stafford Horne <shorne@gmail.com>
2024-12-16 10:24:53 +01:00

97 lines
3.2 KiB
C

/* malloc-lock.c. Lock malloc.
*
* Copyright (C) 2014, Authors
*
* Contributor Stefan Wallentowitz <stefan.wallentowitz@tum.de>
*
* The authors hereby grant permission to use, copy, modify, distribute,
* and license this software and its documentation for any purpose, provided
* that existing copyright notices are retained in all copies and that this
* notice is included verbatim in any distributions. No written agreement,
* license, or royalty fee is required for any of the authorized uses.
* Modifications to this software may be copyrighted by their authors
* and need not follow the licensing terms described here, provided that
* the new terms are clearly indicated on the first page of each file where
* they apply.
*/
#include <reent.h>
#include <stdint.h>
/* Lock calls from different cores, but allows recursive calls from the same
* core. The lock is not only atomic to other cores calling malloc, but also
* disables all external interrupts. This is necessary as it could otherwise
* lead to a deadlock to interrupt while in malloc and then call it from an
* exception. But as we want the exceptions to be flexible to use all library
* calls and especially memory management this is necessary.
*/
// The lock. It is zero when unlocked and contains a unique value for each core.
// This value is not the core id (to avoid id zero), but the pointer value of
// the core specific struct _reent.
volatile uint32_t _or1k_malloc_lock;
// Count how often the current holder has entered the lock
volatile uint32_t _or1k_malloc_lock_cnt;
// The exception enable restore of the current mutex holder
volatile uint32_t _or1k_malloc_lock_restore;
extern uint32_t or1k_sync_cas(void *address, uint32_t compare, uint32_t swap);
extern uint32_t or1k_critical_begin();
extern void or1k_critical_end(uint32_t restore);
/**
* Recursive lock of the malloc
*/
void __malloc_lock(struct _reent *ptr) {
uint32_t restore;
uint32_t id;
// Each core is identified by its struct _reent pointer
id = (uint32_t) ptr;
// Disable timer and interrupt exception, save TEE and IEE flag
// temporarily to restore them later on unlock
restore = or1k_critical_begin();
// We cannot be disturbed by an interrupt or timer exception from here
// Check if we currently don't hold the lock
if (_or1k_malloc_lock != id) {
do {
// Repeatedly check the lock until it is set to zero
while (_or1k_malloc_lock != 0) {}
// .. and then try to set it atomically. As this may
// fail, we need to repeat this
} while (or1k_sync_cas((void*) &_or1k_malloc_lock, 0, id) != 0);
}
// Store the TEE and IEE flags for later restore
if (_or1k_malloc_lock_cnt == 0) {
_or1k_malloc_lock_restore = restore;
}
// Increment counter. The lock may be accessed recursively
_or1k_malloc_lock_cnt++;
return;
}
void __malloc_unlock(struct _reent *ptr) {
// Decrement counter. The lock may be unlocked recursively
_or1k_malloc_lock_cnt--;
// If this was the last recursive unlock call
if(_or1k_malloc_lock_cnt == 0){
// We need to temporarily store the value to avoid a race
// condition between unlocking and reading restore
uint32_t restore = _or1k_malloc_lock_restore;
// unset lock
_or1k_malloc_lock = 0;
// Restore flags
or1k_critical_end(restore);
}
return;
}