mirror of
https://github.com/apache/nuttx.git
synced 2026-10-02 19:58:01 +00:00
The base firmware and an FDPIC module disagree about what a function pointer is. Firmware is not built FDPIC, so to it a pointer is a code address and it branches there. A module passes the address of a two word descriptor instead, because its code and data are placed independently and a bare code address would leave the callee unable to find its own data. A firmware routine that takes a callback therefore branches into the module's data segment and faults. So the ten entry points that can be handed a callback by a module resolve the descriptor before storing or branching to it: qsort, bsearch, pthread_create, signal, sigaction, task_create and task_create_with_stack, task_spawn, pthread_once, scandir, and mq_notify and timer_create with SIGEV_THREAD. Which one resolves matters as much as that one does. Resolving twice would take an already resolved code address for a descriptor and read two words from the instruction stream, so each pointer is resolved exactly once, at the outermost point that sees it. signal() passes its argument through untouched because sigaction() and then nxsig_action() will resolve it, which covers a module calling sigaction() directly as well. qsort() is split so that the public entry resolves and the recursive implementation does not. scandir() resolves its filter but not its comparison function, which it hands to qsort(). Whether a caller is a module at all is asked of the PIC base register, which up_initial_state() sets only for a task that has a D-Space. A plain kernel task therefore reads zero and is left alone. SIGEV_THREAD is the case the register cannot answer, because the callback runs later on a work queue worker that carries no module's base at all. The base is captured instead when the notification is registered, in the module's own context, and installed around the call. All of it is behind CONFIG_FDPIC, which defaults off. Built for mps3-an547:picostest both ways; with it off the entry points compile to what they were. Assisted-by: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
105 lines
3.3 KiB
C
105 lines
3.3 KiB
C
/****************************************************************************
|
|
* libs/libc/pthread/pthread_once.c
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed with
|
|
* this work for additional information regarding copyright ownership. The
|
|
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
|
* "License"); you may not use this file except in compliance with the
|
|
* License. You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
* License for the specific language governing permissions and limitations
|
|
* under the License.
|
|
*
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Included Files
|
|
****************************************************************************/
|
|
|
|
#include <nuttx/config.h>
|
|
|
|
#include <assert.h>
|
|
#include <errno.h>
|
|
#include <stdbool.h>
|
|
#include <pthread.h>
|
|
#include <nuttx/mutex.h>
|
|
#include <nuttx/debug.h>
|
|
|
|
#ifdef CONFIG_FDPIC
|
|
# include <nuttx/fdpic.h>
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
* Public Functions
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Name: pthread_once
|
|
*
|
|
* Description:
|
|
* The first call to pthread_once() by any thread with a given
|
|
* once_control, will call the init_routine with no arguments. Subsequent
|
|
* calls to pthread_once() with the same once_control will have no effect.
|
|
* On return from pthread_once(), init_routine will have completed.
|
|
*
|
|
* Input Parameters:
|
|
* once_control - Determines if init_routine should be called.
|
|
* once_control should be declared and initialized as follows:
|
|
*
|
|
* pthread_once_t once_control = PTHREAD_ONCE_INIT;
|
|
*
|
|
* PTHREAD_ONCE_INIT is defined in pthread.h
|
|
* init_routine - The initialization routine that will be called once.
|
|
*
|
|
* Returned Value:
|
|
* 0 (OK) on success or an error number shall be returned to
|
|
* indicate the error.
|
|
*
|
|
* Assumptions:
|
|
*
|
|
****************************************************************************/
|
|
|
|
int pthread_once(FAR pthread_once_t *once_control,
|
|
CODE void (*init_routine)(void))
|
|
{
|
|
/* Sanity checks */
|
|
|
|
if (once_control == NULL || init_routine == NULL)
|
|
{
|
|
return EINVAL;
|
|
}
|
|
|
|
#ifdef CONFIG_FDPIC
|
|
/* Resolve the descriptor here. The value is a local copy, so a later
|
|
* call through the same once_control resolves afresh.
|
|
*/
|
|
|
|
init_routine = (CODE void (*)(void))
|
|
fdpic_callback((FAR void *)init_routine);
|
|
#endif
|
|
|
|
if (!once_control->done)
|
|
{
|
|
pthread_mutex_lock(&once_control->mutex);
|
|
|
|
if (!once_control->done)
|
|
{
|
|
/* Call the init_routine with pre-emption enabled. */
|
|
|
|
init_routine();
|
|
once_control->done = true;
|
|
}
|
|
|
|
pthread_mutex_unlock(&once_control->mutex);
|
|
}
|
|
|
|
return OK;
|
|
}
|