mirror of
https://github.com/plappermaul/realtek-doc.git
synced 2026-01-27 23:47:18 +01:00
456 lines
11 KiB
C
456 lines
11 KiB
C
/*
|
|
* Copyright (C) 2009 Realtek Semiconductor Corp.
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program 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 General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
* $Revision$
|
|
* $Date$
|
|
*
|
|
* Purpose : Definition those APIs interface for separating OS depend system call.
|
|
* Let the RTK SDK call the layer and become OS independent SDK package.
|
|
*
|
|
* Feature : thread relative API
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* Include Files
|
|
*/
|
|
#include <linux/version.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/list.h>
|
|
#if defined(CONFIG_KERNEL_2_6_30 )
|
|
#include <linux/smp_lock.h>
|
|
#else
|
|
#include <linux/mutex.h>
|
|
#include <linux/kthread.h>
|
|
#endif
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0)
|
|
#include <linux/sched/signal.h>
|
|
#endif
|
|
#include <linux/delay.h>
|
|
#include <linux/hardirq.h>
|
|
#include <common/debug/rt_log.h>
|
|
#include <osal/thread.h>
|
|
#include <osal/time.h>
|
|
#include <osal/lib.h>
|
|
#include <osal/memory.h>
|
|
#include <osal/sem.h>
|
|
|
|
/*
|
|
* Symbol Definition
|
|
*/
|
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
|
|
#define MY_INIT_WORK(_t, _f, _d) INIT_WORK((_t), (_f), (_d))
|
|
#else
|
|
#define MY_INIT_WORK(_t, _f, _d) INIT_WORK((_t), (_f))
|
|
#endif
|
|
|
|
/*
|
|
* Data Declaration
|
|
*/
|
|
|
|
/* Data structure used to control and record the information of the generated thread.*/
|
|
typedef struct kthread_ctrl_s
|
|
{
|
|
osal_mutex_t wait_sem;
|
|
struct list_head list;
|
|
struct task_struct *thread;
|
|
struct work_struct wq;
|
|
void (*f)(void *);
|
|
void *pArg;
|
|
char name[16];
|
|
int priority;
|
|
} kthread_ctrl_t;
|
|
|
|
/* list head of thread list. */
|
|
LIST_HEAD(kthread_list);
|
|
|
|
|
|
/*
|
|
* Macro Definition
|
|
*/
|
|
#define TO_POSIX_NICE_PRIO(p) ((((p) * 39) / 255) - 20)
|
|
|
|
/*
|
|
* Function Declaration
|
|
*/
|
|
|
|
/* Function Name:
|
|
* search_thread_byID
|
|
* Description:
|
|
* Search for the thread by thread id.
|
|
* Input:
|
|
* t_id - The searched thread id.
|
|
* Output:
|
|
* None
|
|
* Return:
|
|
* NULL - No thread with the given thread id.
|
|
* Others - the pointer pointed to kthread_ctrl_t data structure with the given thread id.
|
|
* Note:
|
|
* Used for internal implementation.
|
|
*/
|
|
static kthread_ctrl_t *
|
|
search_thread_byID(osal_thread_t t_id)
|
|
{
|
|
struct list_head *pH;
|
|
kthread_ctrl_t *pKt_ctrl;
|
|
|
|
/* Iterate the whole list to search the thread. */
|
|
list_for_each(pH, &kthread_list)
|
|
{
|
|
pKt_ctrl = list_entry(pH, kthread_ctrl_t, list);
|
|
|
|
if (pKt_ctrl->thread->pid == t_id)
|
|
{
|
|
return pKt_ctrl;
|
|
}
|
|
}
|
|
|
|
return (kthread_ctrl_t *)NULL;
|
|
} /* end of search_thread_byID */
|
|
|
|
|
|
/* Function Name:
|
|
* thread_entry_point
|
|
* Description:
|
|
* The function used to set necessary setting for the thread before runng it.
|
|
* Input:
|
|
* pKt_ctrl - The pointer points to the kthread_ctrl_t data of the created thread.
|
|
* Output:
|
|
* None
|
|
* Return:
|
|
* None
|
|
* Note:
|
|
* Used for internal implementation.
|
|
*/
|
|
static void
|
|
thread_entry_point(kthread_ctrl_t *pKt_ctrl)
|
|
{
|
|
/* daemonize the thread, therefore it won't be affect by its creator. */
|
|
#if defined(CONFIG_KERNEL_2_6_30)
|
|
daemonize(pKt_ctrl->name);
|
|
#endif
|
|
|
|
/* kernel thread disable all signals by default. enable SIGKILL signal. */
|
|
allow_signal(SIGKILL);
|
|
|
|
/*
|
|
* Since we can't get thread information before creating it,
|
|
* we complete kthread_ctrl_t data before running it.
|
|
*/
|
|
osal_strcpy(current->comm, pKt_ctrl->name);
|
|
current->policy = SCHED_NORMAL;
|
|
set_user_nice(current, TO_POSIX_NICE_PRIO(pKt_ctrl->priority));
|
|
pKt_ctrl->thread = current;
|
|
|
|
/* Add kthread_list into pKt_ctrl->list. */
|
|
#if defined(CONFIG_KERNEL_2_6_30)
|
|
lock_kernel();
|
|
#endif
|
|
list_add(&pKt_ctrl->list, &kthread_list);
|
|
#if defined(CONFIG_KERNEL_2_6_30)
|
|
unlock_kernel();
|
|
#endif
|
|
|
|
/* Signal the completion of the thread initializaion. */
|
|
osal_sem_give(pKt_ctrl->wait_sem);
|
|
|
|
/* Call the real thread function. */
|
|
pKt_ctrl->f(pKt_ctrl->pArg);
|
|
|
|
/* Do the jobs for exiting. */
|
|
osal_thread_exit(0);
|
|
} /* end of thread_entry_point */
|
|
|
|
|
|
/* Function Name:
|
|
* thread_creator_callby_kevnetd
|
|
* Description:
|
|
* called by kevnetd thread in the linux kernel to create the thread.
|
|
* Input:
|
|
* data - The private data which is passed to the created thread.
|
|
* Output:
|
|
* None
|
|
* Return:
|
|
* None
|
|
* Note:
|
|
* Used for internal implementation.
|
|
*/
|
|
#if defined(CONFIG_KERNEL_2_6_30)
|
|
static void
|
|
thread_creator_callby_kevnetd(void *pData)
|
|
{
|
|
kernel_thread((int (*)(void *))thread_entry_point, pData, 0);
|
|
} /* end of thread_creator_callby_kevnetd */
|
|
#else
|
|
static void
|
|
thread_creator_callby_kevnetd(kthread_ctrl_t *pData)
|
|
{
|
|
kthread_run((int (*)(void *))thread_entry_point, pData, pData->name);
|
|
|
|
} /* end of thread_creator_callby_kevnetd */
|
|
#endif
|
|
|
|
/*
|
|
* For the reason that the child thread will inherent the features of the parent,
|
|
* we switch the thread creation to keventd kernel thread and wait for the wait_sem semaphore
|
|
* for the thread initialization. This might avoid some bothering jobs like closing signals ...
|
|
*/
|
|
|
|
/* Function Name:
|
|
* osal_thread_create
|
|
* Description:
|
|
* Create a thread for running the main routine
|
|
* Input:
|
|
* pName - name of thread
|
|
* stack_size - stack size of thread
|
|
* thread_pri - priority of thread
|
|
* f - main routine
|
|
* pArg - input argument of the main routine
|
|
* Output:
|
|
* None
|
|
* Return:
|
|
* thread id
|
|
* Note:
|
|
* Linux - stack_size is currently using kernel default value.
|
|
*/
|
|
osal_thread_t
|
|
osal_thread_create(char *pName, int stack_size, int thread_pri, void (f)(void *), void *pArg)
|
|
{
|
|
kthread_ctrl_t *pKt_ctrl;
|
|
|
|
/* allocate memory */
|
|
pKt_ctrl = osal_alloc(sizeof(kthread_ctrl_t));
|
|
if(NULL == pKt_ctrl)
|
|
{
|
|
/* memory allocation error. */
|
|
return (osal_thread_t)NULL;
|
|
}
|
|
|
|
/* clear the data */
|
|
osal_memset(pKt_ctrl, 0, sizeof(kthread_ctrl_t));
|
|
|
|
/* fill up the field in the pKt_ctrl */
|
|
if (NULL != pName)
|
|
{
|
|
if(strlen(pName) < sizeof(pKt_ctrl->name))
|
|
{
|
|
osal_strcpy(pKt_ctrl->name, pName);
|
|
}
|
|
else
|
|
{
|
|
osal_memcpy(pKt_ctrl->name, pName, sizeof(pKt_ctrl->name)-1);
|
|
pKt_ctrl->name[sizeof(pKt_ctrl->name)-1] = '\0';
|
|
}
|
|
}
|
|
pKt_ctrl->f = f;
|
|
pKt_ctrl->pArg = pArg;
|
|
pKt_ctrl->thread = NULL;
|
|
pKt_ctrl->priority = thread_pri;
|
|
pKt_ctrl->wait_sem = osal_sem_create(0); /* create semaphore. */
|
|
if (0 == pKt_ctrl->wait_sem)
|
|
{
|
|
/* fail to create semaphore. */
|
|
osal_free(pKt_ctrl);
|
|
return (osal_thread_t)NULL;
|
|
}
|
|
|
|
/* deliver the creation of the thread to kevnetd. */
|
|
#if 0
|
|
INIT_WORK(&pKt_ctrl->wq, thread_creator_callby_kevnetd, pKt_ctrl);
|
|
#else
|
|
MY_INIT_WORK(&pKt_ctrl->wq, thread_creator_callby_kevnetd, pKt_ctrl);
|
|
#endif
|
|
schedule_work(&pKt_ctrl->wq);
|
|
|
|
/* waiting for thread_creator_callby_kevnetd to create the thread. */
|
|
osal_sem_take(pKt_ctrl->wait_sem, OSAL_SEM_WAIT_FOREVER);
|
|
|
|
if(NULL != pKt_ctrl->thread)
|
|
{
|
|
return (osal_thread_t)pKt_ctrl->thread->pid;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
} /* end of osal_thread_create */
|
|
|
|
/* Function Name:
|
|
* osal_thread_destroy
|
|
* Description:
|
|
* Destroy the thread
|
|
* Input:
|
|
* thread - thread id
|
|
* Output:
|
|
* None
|
|
* Return:
|
|
* RT_ERR_OK
|
|
* RT_ERR_FAILED
|
|
* Note:
|
|
* None
|
|
*/
|
|
int32
|
|
osal_thread_destroy(osal_thread_t thread_id)
|
|
{
|
|
kthread_ctrl_t *pTarget_thread;
|
|
#if 1
|
|
struct pid *pid;
|
|
#endif
|
|
/* Find the thread control data. */
|
|
pTarget_thread = search_thread_byID(thread_id);
|
|
|
|
/* We found the thread control data. */
|
|
if (NULL != pTarget_thread)
|
|
{
|
|
#if 0
|
|
kill_proc(((struct task_struct *)(pTarget_thread->thread))->pid, SIGKILL, 1);
|
|
#else
|
|
rcu_read_lock();
|
|
pid = get_pid(find_vpid(((struct task_struct *)(pTarget_thread->thread))->pid));
|
|
rcu_read_unlock();
|
|
kill_pid(pid, SIGKILL, 1);
|
|
#endif
|
|
return RT_ERR_OK;
|
|
}
|
|
/* We find no thread control data. */
|
|
else
|
|
{
|
|
return RT_ERR_FAILED;
|
|
}
|
|
} /* end of osal_thread_destroy */
|
|
|
|
/* Function Name:
|
|
* osal_thread_self
|
|
* Description:
|
|
* Return thread id of caller
|
|
* Input:
|
|
* None
|
|
* Output:
|
|
* None
|
|
* Return:
|
|
* thread id
|
|
* Note:
|
|
* None
|
|
*/
|
|
osal_thread_t
|
|
osal_thread_self(void)
|
|
{
|
|
return (osal_thread_t)current->pid;
|
|
} /* end of osal_thread_self */
|
|
|
|
|
|
/* Function Name:
|
|
* osal_thread_name
|
|
* Description:
|
|
* Return thread name
|
|
* Input:
|
|
* thread - thread id
|
|
* size - size of thread_name buffer
|
|
* Output:
|
|
* pThread_name - buffer to return thread name
|
|
* Return:
|
|
* RT_ERR_OK
|
|
* RT_ERR_FAILED
|
|
* RT_ERR_NULL_POINTER - input parameter may be null pointer
|
|
* Note:
|
|
* None
|
|
*/
|
|
int32
|
|
osal_thread_name(osal_thread_t thread_id, char *pThread_name, uint32 size)
|
|
{
|
|
kthread_ctrl_t *pTarget_thread;
|
|
|
|
RT_INTERNAL_PARAM_CHK((NULL == pThread_name), RT_ERR_NULL_POINTER);
|
|
|
|
pTarget_thread = search_thread_byID(thread_id);
|
|
|
|
if (NULL != pTarget_thread)
|
|
{
|
|
if (osal_strlen(pTarget_thread->name) >= size)
|
|
{
|
|
return RT_ERR_FAILED;
|
|
}
|
|
else
|
|
{
|
|
osal_strcpy(pThread_name, pTarget_thread->name);
|
|
|
|
return RT_ERR_OK;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pThread_name[0] = '\0';
|
|
|
|
return RT_ERR_FAILED;
|
|
}
|
|
|
|
return RT_ERR_OK;
|
|
} /* end of osal_thread_name */
|
|
|
|
|
|
/* Function Name:
|
|
* osal_thread_exit
|
|
* Description:
|
|
* Exit the calling thread
|
|
* Input:
|
|
* ret_code - return code from thread.
|
|
* Output:
|
|
* None
|
|
* Return:
|
|
* None
|
|
* Note:
|
|
* None
|
|
*/
|
|
void
|
|
osal_thread_exit(int32 ret_code)
|
|
{
|
|
kthread_ctrl_t *pExit;
|
|
#if 1
|
|
struct pid *pid;
|
|
#endif
|
|
|
|
pExit = search_thread_byID(current->pid);
|
|
/* Not the thread under our management. */
|
|
if (NULL == pExit)
|
|
{
|
|
return;
|
|
}
|
|
/* Remove the thread from the list. */
|
|
#if defined(CONFIG_KERNEL_2_6_30)
|
|
lock_kernel();
|
|
#endif
|
|
list_del(&pExit->list);
|
|
#if defined(CONFIG_KERNEL_2_6_30)
|
|
unlock_kernel();
|
|
#endif
|
|
/* Relase the memory. */
|
|
osal_free(pExit);
|
|
|
|
/* Signal the parent thread. */
|
|
#if 0
|
|
kill_proc(2, SIGCHLD, 1);
|
|
#else
|
|
rcu_read_lock();
|
|
pid = get_pid(find_vpid(current->pid));
|
|
rcu_read_unlock();
|
|
kill_pid(pid, SIGCHLD, 1);
|
|
#endif
|
|
|
|
complete_and_exit(NULL, ret_code);
|
|
} /* end of osal_thread_exit */
|
|
|