Compare commits

...

2 Commits

Author SHA1 Message Date
mazen Adel
4482d84c9b Merge branch 'sem-clock-wait' into 'main'
Draft: Add: sem_clockwait() support to RTEMS

See merge request rtems/rtos/rtems!669
2025-11-15 01:08:15 +00:00
Mazen Adel Elmessady
61c35cff46 Adds: sem_clockwait() support to RTEMS
This commit adds support for the sem_clockwait() system call.
It also refactors code to avoid duplicating by implementing
_Semaphore_Wait_timed_clock() used in
sem_clockwait() and sem_timedwait()

The MR includes tests.
Updates
rtems/programs/gsoc#69
rtems#24
2025-10-10 00:25:52 +03:00
6 changed files with 184 additions and 42 deletions

View File

@@ -0,0 +1,62 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/**
* @file
*
* @ingroup POSIX_SEMAPHORE
*
* @brief This source file contains the implementation of sem_clockwait().
*/
/*
* Copyright (C) 2025 Mazen Adel Elmessady
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <rtems/posix/posixapi.h>
#include <rtems/posix/semaphoreimpl.h>
#include <rtems/score/todimpl.h>
int sem_clockwait(
sem_t *__restrict _sem,
clockid_t clock_id,
const struct timespec *__restrict abstime
)
{
if ( !_POSIX_Is_valid_clock_id( clock_id ) ) {
rtems_set_errno_and_return_minus_one( EINVAL );
}
POSIX_SEMAPHORE_VALIDATE_OBJECT( _sem );
int status = _Semaphore_Wait_timed_clock (
&_sem->_Semaphore,
abstime,
clock_id
);
return _POSIX_Zero_or_minus_one_plus_errno( status );
}

View File

@@ -5,7 +5,7 @@
*
* @ingroup POSIX_SEMAPHORE POSIX Semaphores Support
*
* @brief Lock a Semaphore
* @brief This source file contains the implementation of sem_timedwait().
*/
/*
@@ -48,48 +48,16 @@
*/
int sem_timedwait(
sem_t *__restrict _sem,
sem_t *__restrict _sem,
const struct timespec *__restrict abstime
)
{
Sem_Control *sem;
Thread_queue_Context queue_context;
ISR_Level level;
Thread_Control *executing;
unsigned int count;
POSIX_SEMAPHORE_VALIDATE_OBJECT( _sem );
sem = _Sem_Get( &_sem->_Semaphore );
_Thread_queue_Context_initialize( &queue_context );
_Thread_queue_Context_ISR_disable( &queue_context, level );
executing = _Sem_Queue_acquire_critical( sem, &queue_context );
count = sem->count;
if ( RTEMS_PREDICT_TRUE( count > 0 ) ) {
sem->count = count - 1;
_Sem_Queue_release( sem, level, &queue_context );
return 0;
} else {
Status_Control status;
_Thread_queue_Context_set_thread_state(
&queue_context,
STATES_WAITING_FOR_SEMAPHORE
);
_Thread_queue_Context_set_enqueue_timeout_realtime_timespec(
&queue_context,
abstime,
true
);
_Thread_queue_Context_set_ISR_level( &queue_context, level );
_Thread_queue_Enqueue(
&sem->Queue.Queue,
SEMAPHORE_TQ_OPERATIONS,
executing,
&queue_context
);
status = _Thread_Wait_get_status( executing );
return _POSIX_Zero_or_minus_one_plus_errno( status );
}
int status = _Semaphore_Wait_timed_clock(
&_sem->_Semaphore,
abstime,
CLOCK_REALTIME
);
return _POSIX_Zero_or_minus_one_plus_errno( status );
}

View File

@@ -95,6 +95,50 @@ void _Semaphore_Wait( struct _Semaphore_Control *_sem )
}
}
int _Semaphore_Wait_timed_clock(
struct _Semaphore_Control *_sem,
const struct timespec *abstime,
clockid_t clock_id
)
{
Sem_Control *sem;
Thread_queue_Context queue_context;
ISR_Level level;
Thread_Control *executing;
unsigned int count;
sem = _Sem_Get( _sem );
_Thread_queue_Context_initialize( &queue_context );
_Thread_queue_Context_ISR_disable( &queue_context, level );
executing = _Sem_Queue_acquire_critical( sem, &queue_context );
count = sem->count;
if ( RTEMS_PREDICT_TRUE( count > 0 ) ) {
sem->count = count - 1;
_Sem_Queue_release( sem, level, &queue_context );
return 0;
}
_Thread_queue_Context_set_thread_state(
&queue_context,
STATES_WAITING_FOR_SEMAPHORE
);
_Thread_queue_Context_set_enqueue_timeout_by_clock_id_timespec(
&queue_context,
abstime,
true,
clock_id
);
_Thread_queue_Context_set_ISR_level( &queue_context, level );
_Thread_queue_Enqueue(
&sem->Queue.Queue,
SEMAPHORE_TQ_OPERATIONS,
executing,
&queue_context
);
return _Thread_Wait_get_status( executing );
}
int _Semaphore_Wait_timed_ticks( struct _Semaphore_Control *_sem, uint32_t ticks )
{
Sem_Control *sem;

View File

@@ -1206,6 +1206,7 @@ source:
- cpukit/posix/src/sched_setscheduler.c
- cpukit/posix/src/sched_yield.c
- cpukit/posix/src/semaphoredeletesupp.c
- cpukit/posix/src/semclockwait.c
- cpukit/posix/src/semclose.c
- cpukit/posix/src/semdestroy.c
- cpukit/posix/src/semgetvalue.c

View File

@@ -213,6 +213,7 @@ static void test_sem_null(void)
int rv;
int val;
struct timespec to;
clockid_t clock_id;
/* This equality is important for POSIX_SEMAPHORE_VALIDATE_OBJECT() */
rtems_test_assert( NULL == SEM_FAILED );
@@ -249,6 +250,14 @@ static void test_sem_null(void)
rtems_test_assert( rv == -1 );
rtems_test_assert( errno == EINVAL );
to.tv_sec = 1;
to.tv_nsec = 1;
errno = 0;
clock_id = CLOCK_REALTIME;
rv = sem_clockwait( NULL, clock_id, &to );
rtems_test_assert( rv == -1 );
rtems_test_assert( errno == EINVAL );
errno = 0;
rv = sem_getvalue( NULL, &val );
rtems_test_assert( rv == -1 );
@@ -271,6 +280,7 @@ static void test_sem_not_initialized(void)
int rv;
int val;
struct timespec to;
clockid_t clock_id;
memset( &sem, 0xff, sizeof( sem ) );
@@ -301,6 +311,14 @@ static void test_sem_not_initialized(void)
rtems_test_assert( rv == -1 );
rtems_test_assert( errno == EINVAL );
to.tv_sec = 1;
to.tv_nsec = 1;
errno = 0;
clock_id = CLOCK_REALTIME;
rv = sem_clockwait( NULL, clock_id, &to );
rtems_test_assert( rv == -1 );
rtems_test_assert( errno == EINVAL );
errno = 0;
rv = sem_getvalue( &sem, &val );
rtems_test_assert( rv == -1 );
@@ -363,6 +381,7 @@ void *POSIX_Init(
sem_t *n_sem2;
struct timespec waittime;
char failure_msg[80];
clockid_t clock_id;
TEST_BEGIN();
@@ -488,6 +507,46 @@ void *POSIX_Init(
fatal_posix_service_status( errno, EINVAL, "sem_init errno EINVAL");
#endif
puts( "Init: sem_post - SUCCESSFUL" );
status = sem_post(&sems[2]);
fatal_posix_service_status( status, 0, "sem_post semaphore 2");
/* sem[2].count = 1 */
puts( "Init: sem_clockwait CLOCK_MONOTONIC - SUCCESSFUL" );
clock_id = CLOCK_MONOTONIC;
clock_gettime(clock_id, &waittime);
waittime.tv_sec += 1;
waittime.tv_nsec = 100;
status = sem_clockwait(&sems[2], clock_id, &waittime);
fatal_posix_service_status( status, 0, "sem_clockwait CLOCK_MONOTONIC semaphore 2");
/* sem[2].count = 0 */
puts( "Init: sem_clockwait CLOCK_MONOTONIC - UNSUCCESSFUL (ETIMEDOUT)" );
status = sem_clockwait(&sems[2], clock_id, &waittime);
fatal_posix_service_status( status, -1, "sem_clockwait CLOCK_MONOTONIC error return status");
fatal_posix_service_status(
errno, ETIMEDOUT, "sem_clockwait CLOCK_MONOTONIC errno ETIMEDOUT");
puts( "Init: sem_post - SUCCESSFUL" );
status = sem_post(&sems[2]);
fatal_posix_service_status( status, 0, "sem_post semaphore 2");
/* sem[2].count = 1 */
puts( "Init: sem_clockwait CLOCK_REALTIME - SUCCESSFUL" );
clock_id = CLOCK_REALTIME;
clock_gettime(clock_id, &waittime);
waittime.tv_sec += 1;
waittime.tv_nsec = 100;
status = sem_clockwait(&sems[2], clock_id, &waittime);
fatal_posix_service_status( status, 0, "sem_clockwait CLOCK_REALTIME semaphore 2");
/* sem[2].count = 0 */
puts( "Init: sem_clockwait CLOCK_REALTIME - UNSUCCESSFUL (ETIMEDOUT)" );
status = sem_clockwait(&sems[2], clock_id, &waittime);
fatal_posix_service_status( status, -1, "sem_clockwait CLOCK_REALTIME error return status");
fatal_posix_service_status(
errno, ETIMEDOUT, "sem_clockwait CLOCK_REALTIME errno ETIMEDOUT");
puts( "Init: sem_post - UNSUCCESSFUL (EINVAL)" );
status = sem_post(SEM_FAILED);
fatal_posix_service_status( status, -1, "sem_post error return status");

View File

@@ -1,8 +1,10 @@
*** BEGIN OF TEST PSXSEM 1 ***
Init: sem_init - SUCCESSFUL
Init: sem_destroy - SUCCESSFUL
Init: sem_init - UNSUCCESSFUL (EINVAL)
Init: sem_init - SUCCESSFUL
Init: sem_init - UNSUCCESSFUL (ENOSPC)
Init: sem_init - UNSUCCESSFUL (ENOSYS -- pshared not supported)
Init: sem_init - SUCCESSFUL
Init: sem_destroy - SUCCESSFUL
Init: sem_getvalue - SUCCESSFUL
Init: sem_getvalue - UNSUCCESSFUL
Init: sem_destroy - SUCCESSFUL
@@ -17,6 +19,12 @@ Init: sem_trywait - UNSUCCESSFUL (EINVAL)
Init: sem_timedwait - SUCCESSFUL
Init: sem_timedwait - UNSUCCESSFUL (ETIMEDOUT)
Init: sem_timedwait - UNSUCCESSFUL (EINVAL) -- skipping
Init: sem_post - SUCCESSFUL
Init: sem_clockwait CLOCK_MONOTONIC - SUCCESSFUL
Init: sem_clockwait CLOCK_MONOTONIC - UNSUCCESSFUL (ETIMEDOUT)
Init: sem_post - SUCCESSFUL
Init: sem_clockwait CLOCK_REALTIME - SUCCESSFUL
Init: sem_clockwait CLOCK_REALTIME - UNSUCCESSFUL (ETIMEDOUT)
Init: sem_post - UNSUCCESSFUL (EINVAL)
Init: sem_destroy - SUCCESSFUL
Init: sem_open - UNSUCCESSFUL (ENAMETOOLONG)