Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:04

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /*
0004  * Copyright (C) 2024 Matheus Pecoraro
0005  *
0006  * Redistribution and use in source and binary forms, with or without
0007  * modification, are permitted provided that the following conditions
0008  * are met:
0009  * 1. Redistributions of source code must retain the above copyright
0010  *    notice, this list of conditions and the following disclaimer.
0011  * 2. Redistributions in binary form must reproduce the above copyright
0012  *    notice, this list of conditions and the following disclaimer in the
0013  *    documentation and/or other materials provided with the distribution.
0014  *
0015  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0016  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0017  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0018  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0019  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0020  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0021  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0022  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0023  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0024  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0025  * POSSIBILITY OF SUCH DAMAGE.
0026  */
0027 
0028 #include <acpi/acpica/acpi.h>
0029 #include <rtems.h>
0030 
0031 #include <errno.h>
0032 #include <pthread.h>
0033 
0034 static void ms_timeout_to_abs_timespec(uint32_t timeout, struct timespec *abstime)
0035 {
0036   clock_gettime(CLOCK_REALTIME, abstime);
0037   abstime->tv_sec += timeout / 1000;
0038   abstime->tv_nsec += (timeout % 1000) * 1000000;
0039 }
0040 
0041 typedef struct {
0042   pthread_mutex_t mutex;
0043   pthread_cond_t wait_cond;
0044   pthread_cond_t delete_cond;
0045   uint32_t units;
0046   uint32_t max_units;
0047   uint32_t waiters;
0048   bool is_pending_delete;
0049 } acpi_semaphore;
0050 
0051 ACPI_STATUS AcpiOsCreateSemaphore(
0052   UINT32 MaxUnits,
0053   UINT32 InitialUnits,
0054   ACPI_SEMAPHORE* OutHandle
0055 )
0056 {
0057   acpi_semaphore* ac_sem;
0058 
0059   if (OutHandle == NULL || MaxUnits == 0 || InitialUnits > MaxUnits)
0060     return (AE_BAD_PARAMETER);
0061 
0062   ac_sem = malloc(sizeof(acpi_semaphore));
0063   if (ac_sem == NULL) {
0064     return (AE_NO_MEMORY);
0065   }
0066 
0067   if (pthread_mutex_init(&ac_sem->mutex, NULL) != 0 ||
0068       pthread_cond_init(&ac_sem->wait_cond, NULL) != 0 ||
0069       pthread_cond_init(&ac_sem->delete_cond, NULL) != 0)
0070   {
0071     free(ac_sem);
0072     return (AE_ERROR);
0073   }
0074   ac_sem->units = InitialUnits;
0075   ac_sem->max_units = MaxUnits;
0076   ac_sem->waiters = 0;
0077   ac_sem->is_pending_delete = false;
0078 
0079   /* Since we don't define ACPI_SEMAPHORE OutHandle is of type void** */
0080   *OutHandle = (ACPI_SEMAPHORE) ac_sem;
0081 
0082   return (AE_OK);
0083 }
0084 
0085 ACPI_STATUS AcpiOsDeleteSemaphore(ACPI_SEMAPHORE Handle)
0086 {
0087   int eno;
0088   acpi_semaphore* ac_sem = (acpi_semaphore*) Handle;
0089 
0090   if (ac_sem == NULL) {
0091     return (AE_BAD_PARAMETER);
0092   }
0093 
0094   eno = pthread_mutex_lock(&ac_sem->mutex);
0095   if (eno != 0) {
0096     return (AE_ERROR);
0097   }
0098 
0099   /* Ensure there are no waiters left */
0100   ac_sem->is_pending_delete = true;
0101   pthread_cond_broadcast(&ac_sem->wait_cond);
0102   while (ac_sem->waiters > 0) {
0103     pthread_cond_wait(&ac_sem->delete_cond, &ac_sem->mutex);
0104   }
0105 
0106   pthread_mutex_unlock(&ac_sem->mutex);
0107 
0108   pthread_mutex_destroy(&ac_sem->mutex);
0109   pthread_cond_destroy(&ac_sem->wait_cond);
0110   pthread_cond_destroy(&ac_sem->delete_cond);
0111 
0112   free(ac_sem);
0113 
0114   return (AE_OK);
0115 }
0116 
0117 ACPI_STATUS AcpiOsWaitSemaphore(
0118   ACPI_SEMAPHORE Handle,
0119   UINT32 Units,
0120   UINT16 Timeout
0121 )
0122 {
0123   int eno;
0124   ACPI_STATUS ac_status = (AE_OK);
0125   acpi_semaphore* ac_sem = (acpi_semaphore*) Handle;
0126 
0127   if (ac_sem == NULL || Units == 0) {
0128     return (AE_BAD_PARAMETER);
0129   }
0130 
0131   eno = pthread_mutex_lock(&ac_sem->mutex);
0132   if (eno != 0) {
0133     return (AE_ERROR);
0134   }
0135 
0136   if (ac_sem->max_units != ACPI_NO_UNIT_LIMIT && ac_sem->max_units < Units) {
0137     return (AE_LIMIT);
0138   }
0139 
0140   switch (Timeout) {
0141   case ACPI_DO_NOT_WAIT:
0142     if (ac_sem->units < Units) {
0143       ac_status = (AE_TIME);
0144     }
0145 
0146     break;
0147   case ACPI_WAIT_FOREVER:
0148     ac_sem->waiters++;
0149     while (ac_sem->units < Units) {
0150       pthread_cond_wait(&ac_sem->wait_cond, &ac_sem->mutex);
0151 
0152       if (ac_sem->is_pending_delete) {
0153         ac_status = (AE_ERROR);
0154         pthread_cond_signal(&ac_sem->delete_cond);
0155         break;
0156       }
0157     }
0158     ac_sem->waiters--;
0159 
0160     break;
0161   default:
0162     struct timespec abstime;
0163     ms_timeout_to_abs_timespec(Timeout, &abstime);
0164 
0165     ac_sem->waiters++;
0166     while (ac_sem->units < Units) {
0167       eno = pthread_cond_timedwait(&ac_sem->wait_cond, &ac_sem->mutex, &abstime);
0168 
0169       if (ac_sem->is_pending_delete) {
0170         ac_status = (AE_ERROR);
0171         pthread_cond_signal(&ac_sem->delete_cond);
0172         break;
0173       }
0174 
0175       if (eno == ETIMEDOUT) {
0176         ac_status = (AE_TIME);
0177         break;
0178       }
0179     }
0180     ac_sem->waiters--;
0181 
0182     break;
0183   }
0184 
0185   if (ac_status == (AE_OK)) {
0186     ac_sem->units -= Units;
0187   }
0188 
0189   pthread_mutex_unlock(&ac_sem->mutex);
0190 
0191   return ac_status;
0192 }
0193 
0194 ACPI_STATUS AcpiOsSignalSemaphore(ACPI_SEMAPHORE Handle, UINT32 Units)
0195 {
0196   int eno;
0197   acpi_semaphore* ac_sem = (acpi_semaphore*) Handle;
0198 
0199   if (ac_sem == NULL || Units == 0) {
0200     return (AE_BAD_PARAMETER);
0201   }
0202 
0203   eno = pthread_mutex_lock(&ac_sem->mutex);
0204   if (eno != 0) {
0205     return (AE_ERROR);
0206   }
0207 
0208   if (ac_sem->max_units != ACPI_NO_UNIT_LIMIT &&
0209       ac_sem->units + Units > ac_sem->max_units)
0210   {
0211     return (AE_LIMIT);
0212   }
0213 
0214   ac_sem->units += Units;
0215   /*
0216    * Signal condition "Units" times to wake up the maximum amount of threads
0217    * that could consume the new units
0218    */
0219   while (Units--) {
0220     pthread_cond_signal(&ac_sem->wait_cond);
0221   }
0222 
0223   pthread_mutex_unlock(&ac_sem->mutex);
0224 
0225   return (AE_OK);
0226 }
0227 
0228 typedef struct {
0229   pthread_mutex_t mutex;
0230 } acpi_spinlock;
0231 
0232 ACPI_STATUS AcpiOsCreateLock(ACPI_SPINLOCK* OutHandle)
0233 {
0234   acpi_spinlock* lock;
0235 
0236   if (OutHandle == NULL)
0237     return (AE_BAD_PARAMETER);
0238 
0239   lock = malloc(sizeof(acpi_spinlock));
0240   if (lock == NULL) {
0241     return (AE_NO_MEMORY);
0242   }
0243 
0244   pthread_mutex_init(&lock->mutex, NULL);
0245 
0246   /* Since we don't define ACPI_SPINLOCK OutHandle is of type void** */
0247   *OutHandle = (ACPI_SPINLOCK) lock;
0248 
0249   return (AE_OK);
0250 }
0251 
0252 void AcpiOsDeleteLock(ACPI_SPINLOCK Handle)
0253 {
0254   acpi_spinlock* lock = (acpi_spinlock*) Handle;
0255 
0256   if (lock == NULL) {
0257     return;
0258   }
0259 
0260   pthread_mutex_destroy(&lock->mutex);
0261 
0262   free(lock);
0263 }
0264 
0265 ACPI_CPU_FLAGS AcpiOsAcquireLock(ACPI_SPINLOCK Handle)
0266 {
0267   acpi_spinlock* lock = (acpi_spinlock*) Handle;
0268 
0269   if (lock == NULL) {
0270     return 0;
0271   }
0272 
0273   pthread_mutex_lock(&lock->mutex);
0274 
0275   return 0;
0276 }
0277 
0278 void AcpiOsReleaseLock(ACPI_SPINLOCK Handle, ACPI_CPU_FLAGS Flags)
0279 {
0280   acpi_spinlock* lock = (acpi_spinlock*) Handle;
0281 
0282   if (lock == NULL) {
0283     return;
0284   }
0285 
0286   pthread_mutex_unlock(&lock->mutex);
0287 }