2 Star 0 Fork 1

TenonOS-Mirror/lib-pthread-embedded

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
pte_osal.c 14.77 KB
一键复制 编辑 原始数据 按行查看 历史
Eduard Vintilă 提交于 2022-11-23 20:44 . Adapt to new scheduling API
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685
/* SPDX-License-Identifier: LGPL-2.0-or-later */
/*
* Unikraft port of POSIX Threads Library for embedded systems
* Copyright(C) 2019 Costin Lupu, University Politehnica of Bucharest
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library in the file COPYING.LIB;
* if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
/*
* This port is derived from hermit/pte_osal.c.
*/
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include <uk/essentials.h>
#include <uk/init.h>
#include <uk/arch/time.h>
#include <uk/arch/atomic.h>
#include <uk/print.h>
#include <uk/thread.h>
#include <uk/sched.h>
#include "pte_osal.h"
#include "pthread.h"
#include "tls-helper.h"
typedef struct pte_thread_data {
/* thread routine */
pte_osThreadEntryPoint entry_point;
/* thread routine arguments */
void *argv;
/* Unikraft thread */
struct uk_thread *uk_thread;
/* TLS */
void *tls;
/* Semaphore for triggering thread start */
struct uk_semaphore start_sem;
/* Semaphore for cancellation */
struct uk_semaphore cancel_sem;
/* Is non-zero if thread exited */
int done;
} pte_thread_data_t;
/****************************************************************************
*
* Initialization
*
***************************************************************************/
static bool initialized /* false */;
static int pthread_initcall(void)
{
int result;
uk_pr_info("Initialize pthread-embedded\n");
result = pthread_init();
if (result == PTE_TRUE)
initialized = true;
return result;
}
uk_early_initcall_prio(pthread_initcall, UK_PRIO_EARLIEST);
pte_osResult pte_osInit(void)
{
pte_osResult result = PTE_OS_OK;
pte_thread_data_t *ptd;
struct uk_thread *crnt;
/* Allocate and initialize TLS support */
result = pteTlsGlobalInit(CONFIG_LIBPTHREAD_EMBEDDED_MAX_TLS);
if (result != PTE_OS_OK) {
uk_pr_err("Could not init global TLS");
goto out;
}
/* Create a ptd for initializing thread. */
ptd = calloc(1, sizeof(pte_thread_data_t));
if (ptd == NULL) {
result = PTE_OS_NO_RESOURCES;
goto out;
}
ptd->tls = pteTlsThreadInit();
if (ptd->tls == NULL) {
uk_pr_err("Could not init TLS");
free(ptd);
result = PTE_OS_NO_RESOURCES;
goto out;
}
crnt = uk_thread_current();
crnt->priv = ptd;
ptd->uk_thread = crnt;
out:
return result;
}
/***************************************************************************
*
* Signal handling
*
**************************************************************************/
#if CONFIG_LIBUKSIGNAL
int pte_kill(pte_osThreadHandle threadId, int sig)
{
//return uk_sig_thread_kill(threadId->uk_thread, sig);
// FIXME after proper uksignal implementation is complete
return 0;
}
#endif
/****************************************************************************
*
* Threads
*
***************************************************************************/
static pte_thread_data_t *handle_to_ptd(pte_osThreadHandle h)
{
return h;
}
static pte_thread_data_t *current_ptd(void)
{
return uk_thread_current()->priv;
}
static void uk_stub_thread_entry(void *argv)
{
pte_thread_data_t *ptd =
(pte_thread_data_t *) uk_thread_current()->priv;
UK_ASSERT(ptd);
/* wait for the resume command */
uk_semaphore_down(&ptd->start_sem);
ptd->entry_point(argv);
}
/* NOTE: We need to be able to distinguish if we created a thread through
* pthread API or through uksched API. In case of pthread_create()
* we have to setup some different properties to the thread like creating
* it in paused state.
* In order to distinguish, we will use a magic number as entry function.
* With the thread argument we forward the actual entry point and argument
* vector. During creation our init callback will be executed by uksched
* and we are able to check if we find our magic number again and handle
* the initialization accordingly.
*/
/* Use a pointer that points to itself as magic number. This way we can be
* sure that the magic number (= pointer address) is unique and reserved
* for our purpose.
*/
static const void *PTE_CAPSULE_MAGIC = &PTE_CAPSULE_MAGIC;
struct pte_entry_capsule {
void *magic;
pte_osThreadEntryPoint entry_point;
void *argv;
};
pte_osResult pte_osThreadCreate(pte_osThreadEntryPoint entry_point,
int stack_size, int initial_prio, void *argv,
pte_osThreadHandle *ph)
{
struct pte_entry_capsule capsule;
struct uk_thread *th;
struct uk_sched *s = uk_sched_current();
capsule.magic = PTE_CAPSULE_MAGIC;
capsule.entry_point = entry_point;
capsule.argv = argv;
/* Create the Unikraft thread. This will cause that pte_osInitThread()
* is called. The thread's priv pointer will point to the capsule
* after thread creation.
*/
th = uk_sched_thread_create_fn1(s, uk_stub_thread_entry, argv,
0, 0, 0, NULL, &capsule, NULL);
if (!th)
return PTE_OS_NO_RESOURCES;
/* pte_osInitThread() should have setup a newly created
* pte_thread_data_t which should be stored on th->priv
*/
UK_ASSERT(th->priv);
/* Return the thread handle */
*ph = th->priv;
return PTE_OS_OK;
}
static int pte_osInitThread(struct uk_thread *th)
{
pte_thread_data_t *ptd;
struct pte_entry_capsule *capsule;
/* Initialize pte with first thread creation */
if (unlikely(!initialized)) {
uk_pr_warn("Thread %p created without " STRINGIFY(__LIBNAME__)
" initialized. Utilizing the pthread API from this context may lead to memory leaks.\n",
th);
return 0;
}
ptd = calloc(1, sizeof(pte_thread_data_t));
if (!ptd)
goto err_out;
/* Allocate TLS structure for this thread. */
ptd->tls = pteTlsThreadInit();
if (!ptd->tls) {
uk_pr_err("Could not allocate TLS\n");
goto err_free_ptd;
}
capsule = (struct pte_entry_capsule *)th->priv;
/* How did we enter this function? */
if (capsule && capsule->magic == PTE_CAPSULE_MAGIC) {
/*
* Found the magic value. Thread was created
* by pte_osThreadCreate().
*/
ptd->entry_point = capsule->entry_point;
ptd->argv = capsule->argv;
/* this thread has to wait for further setup */
uk_semaphore_init(&ptd->start_sem, 0);
} else {
/* Thread not created by pte_osThreadCreate()*/
free(ptd);
return 0;
/* TODO: Not implemented yet. */
/* We will encapsulate our thread entry point,
* we have to move our actual entry to ptd
*/
//ptd->entry_point = (pte_osThreadEntryPoint) th->entry;
//ptd->argv = th->arg;
/* uksched threads need to start automatically */
//uk_semaphore_init(&ptd->start_sem, 1);
}
/* Setup encapsulated entry point */
//th->entry = uk_stub_thread_entry;
//th->arg = ptd;
uk_semaphore_init(&ptd->cancel_sem, 0);
ptd->done = 0;
/* Store cross references (uk_thread <-> pte_thread_data_t) */
th->priv = ptd;
ptd->uk_thread = th;
#if CONFIG_LIBUKSIGNAL
/* FIXME after uksignal implementation: inherit signal mask */
//ptd->uk_thread->signals_container.mask =
// uk_thread_current()->signals_container.mask;
#endif
return 0;
err_free_ptd:
free(ptd);
err_out:
return -1;
}
static void pte_osFiniThread(struct uk_thread *th)
{
/* We clean up resources in pte_osThreadDelete() */
}
UK_THREAD_INIT_PRIO(pte_osInitThread, pte_osFiniThread, UK_PRIO_EARLIEST);
pte_osResult pte_osThreadStart(pte_osThreadHandle h)
{
pte_thread_data_t *ptd = handle_to_ptd(h);
/* wake up thread */
uk_semaphore_up(&ptd->start_sem);
return 0;
}
pte_osResult pte_osThreadDelete(pte_osThreadHandle h)
{
pte_thread_data_t *ptd = handle_to_ptd(h);
/* free resources */
pteTlsThreadDestroy(ptd->tls);
free(ptd);
return PTE_OS_OK;
}
pte_osResult pte_osThreadExitAndDelete(pte_osThreadHandle h)
{
pte_thread_data_t *ptd = handle_to_ptd(h);
UK_ASSERT(ptd->uk_thread);
if (ptd->uk_thread->sched)
uk_thread_terminate(ptd->uk_thread);
pte_osThreadDelete(h);
return PTE_OS_OK;
}
void pte_osThreadExit(void)
{
pte_thread_data_t *ptd = current_ptd();
ptd->done = 1;
uk_sched_thread_exit();
}
pte_osResult pte_osThreadWaitForEnd(pte_osThreadHandle h)
{
pte_thread_data_t *ptd = handle_to_ptd(h);
pte_thread_data_t *self_ptd = current_ptd();
while (1) {
if (ptd->done) {
if (ptd->uk_thread) {
uk_thread_block(ptd->uk_thread);
/* The thread is destroyed after the wait */
ptd->uk_thread = NULL;
}
return PTE_OS_OK;
}
if (self_ptd && self_ptd->cancel_sem.count > 0)
return PTE_OS_INTERRUPTED;
else
uk_sched_yield();
}
}
pte_osResult pte_osThreadCancel(pte_osThreadHandle h)
{
pte_thread_data_t *ptd = handle_to_ptd(h);
uk_semaphore_up(&ptd->cancel_sem);
return PTE_OS_OK;
}
pte_osResult pte_osThreadCheckCancel(pte_osThreadHandle h)
{
pte_thread_data_t *ptd = handle_to_ptd(h);
if (ptd && ptd->cancel_sem.count > 0)
return PTE_OS_INTERRUPTED;
return PTE_OS_OK;
}
pte_osThreadHandle pte_osThreadGetHandle(void)
{
return current_ptd();
}
int pte_osThreadGetPriority(pte_osThreadHandle h)
{
pte_thread_data_t *ptd = handle_to_ptd(h);
/* No priorities implemented. */
int ret = 0;
return ret ? PTE_OS_GENERAL_FAILURE : PTE_OS_OK;
}
pte_osResult pte_osThreadSetPriority(pte_osThreadHandle h, int new_prio)
{
pte_thread_data_t *ptd = handle_to_ptd(h);
/* No priorities implemented. */
int ret = 0;
return ret ? PTE_OS_GENERAL_FAILURE : PTE_OS_OK;
}
void pte_osThreadSleep(unsigned int msecs)
{
__nsec nsec = ukarch_time_msec_to_nsec(msecs);
uk_sched_thread_sleep(nsec);
}
int pte_osThreadGetMinPriority(void)
{
/* No priorities implemented. */
return 0;
}
int pte_osThreadGetMaxPriority(void)
{
/* No priorities implemented. */
return 0;
}
int pte_osThreadGetDefaultPriority(void)
{
/* No priorities implemented. */
return 0;
}
/****************************************************************************
*
* Mutexes
*
****************************************************************************/
pte_osResult pte_osMutexCreate(pte_osMutexHandle *ph)
{
struct uk_mutex *m;
if (!ph)
return PTE_OS_INVALID_PARAM;
m = malloc(sizeof(struct uk_mutex));
if (!m)
return PTE_OS_NO_RESOURCES;
uk_mutex_init(m);
*ph = m;
return PTE_OS_OK;
}
pte_osResult pte_osMutexDelete(pte_osMutexHandle h)
{
if (!h)
return PTE_OS_INVALID_PARAM;
free(h);
return PTE_OS_OK;
}
pte_osResult pte_osMutexLock(pte_osMutexHandle h)
{
if (!h)
return PTE_OS_INVALID_PARAM;
uk_mutex_lock(h);
return PTE_OS_OK;
}
pte_osResult pte_osMutexTimedLock(pte_osMutexHandle h,
unsigned int timeoutMsecs)
{
return PTE_OS_GENERAL_FAILURE;
}
pte_osResult pte_osMutexUnlock(pte_osMutexHandle h)
{
if (!h)
return PTE_OS_INVALID_PARAM;
uk_mutex_unlock(h);
return PTE_OS_OK;
}
/****************************************************************************
*
* Semaphores
*
***************************************************************************/
pte_osResult pte_osSemaphoreCreate(int init_value, pte_osSemaphoreHandle *ph)
{
struct uk_semaphore *s;
if (!ph)
return PTE_OS_INVALID_PARAM;
s = malloc(sizeof(struct uk_semaphore));
if (!s)
return PTE_OS_NO_RESOURCES;
uk_semaphore_init(s, init_value);
*ph = s;
return PTE_OS_OK;
}
pte_osResult pte_osSemaphoreDelete(pte_osSemaphoreHandle h)
{
if (!h)
return PTE_OS_INVALID_PARAM;
free(h);
return PTE_OS_OK;
}
pte_osResult pte_osSemaphorePost(pte_osSemaphoreHandle h, int count)
{
int i;
if (!h)
return PTE_OS_INVALID_PARAM;
for (i = 0; i < count; i++)
uk_semaphore_up(h);
return PTE_OS_OK;
}
pte_osResult pte_osSemaphorePend(pte_osSemaphoreHandle h,
unsigned int *ptimeout_msecs)
{
__nsec timeout;
if (!h)
return PTE_OS_INVALID_PARAM;
if (ptimeout_msecs) {
timeout = ukarch_time_msec_to_nsec(*ptimeout_msecs);
if (uk_semaphore_down_to(h, timeout) == __NSEC_MAX)
return PTE_OS_TIMEOUT;
} else
uk_semaphore_down(h);
return PTE_OS_OK;
}
pte_osResult pte_osSemaphoreCancellablePend(pte_osSemaphoreHandle h,
unsigned int *ptimeout_msecs)
{
pte_thread_data_t *ptd = current_ptd();
pte_osResult result = PTE_OS_OK;
__nsec timeout = 0, start_time = ukplat_monotonic_clock();
if (ptimeout_msecs)
timeout = ukarch_time_msec_to_nsec(*ptimeout_msecs);
while (1) {
if (uk_semaphore_down_try(h))
/* semaphore is up */
break;
else if (timeout &&
(ukplat_monotonic_clock() - start_time > timeout)) {
/* The timeout expired */
result = PTE_OS_TIMEOUT;
break;
} else if (ptd && ptd->cancel_sem.count > 0) {
/* The thread was cancelled */
result = PTE_OS_INTERRUPTED;
break;
} else
/* Maybe next time... */
uk_sched_yield();
}
return result;
}
#if 0
/* We use macros instead */
/****************************************************************************
*
* Atomic Operations
*
***************************************************************************/
static int atomic_add(int *ptarg, int val)
{
return __atomic_add_fetch(ptarg, val, __ATOMIC_SEQ_CST);
}
int pte_osAtomicExchange(int *ptarg, int val)
{
return ukarch_exchange_n(ptarg, val);
}
int pte_osAtomicCompareExchange(int *pdest, int exchange, int comp)
{
int orig = *pdest;
ukarch_compare_exchange_sync(pdest, comp, exchange);
return orig;
}
int pte_osAtomicExchangeAdd(int volatile *paddend, int value)
{
return ukarch_fetch_add(paddend, value);
}
int pte_osAtomicDecrement(int *pdest)
{
return atomic_add(pdest, -1);
}
int pte_osAtomicIncrement(int *pdest)
{
return atomic_add(pdest, 1);
}
#endif
/****************************************************************************
*
* Thread Local Storage
*
***************************************************************************/
static void *current_tls(void)
{
pte_thread_data_t *ptd = current_ptd();
return ptd ? ptd->tls : NULL;
}
pte_osResult pte_osTlsSetValue(unsigned int key, void *value)
{
return pteTlsSetValue(current_tls(), key, value);
}
void *pte_osTlsGetValue(unsigned int index)
{
return (void *) pteTlsGetValue(current_tls(), index);
}
pte_osResult pte_osTlsAlloc(unsigned int *pkey)
{
return pteTlsAlloc(pkey);
}
pte_osResult pte_osTlsFree(unsigned int index)
{
return pteTlsFree(index);
}
/***************************************************************************
*
* Miscellaneous
*
***************************************************************************/
int ftime(struct timeb *tb)
{
__nsec now = ukplat_monotonic_clock();
if (tb) {
tb->time = ukarch_time_nsec_to_sec(now);
tb->millitm = ukarch_time_nsec_to_msec(ukarch_time_subsec(now));
}
return 0;
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/tenonos-mirror/lib-pthread-embedded.git
git@gitee.com:tenonos-mirror/lib-pthread-embedded.git
tenonos-mirror
lib-pthread-embedded
lib-pthread-embedded
staging

搜索帮助

0d507c66 1850385 C8b1a773 1850385