372 lines
		
	
	
		
			9.3 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			372 lines
		
	
	
		
			9.3 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
| /**
 | |
| 	@brief vos task (virtual-os user-space)
 | |
| 
 | |
| 	@file vos_user_task.c
 | |
| 
 | |
| 	@ingroup vos_user
 | |
| 
 | |
| 	@note Nothing.
 | |
| 
 | |
| 	Copyright Novatek Microelectronics Corp. 2019.  All rights reserved.
 | |
| */
 | |
| /*-----------------------------------------------------------------------------*/
 | |
| /* Include Header Files                                                        */
 | |
| /*-----------------------------------------------------------------------------*/
 | |
| #define _GNU_SOURCE /* define this for pthread_setname_np */
 | |
| 
 | |
| #define __MODULE__    vos_user_task
 | |
| #define __DBGLVL__    2
 | |
| #include <kwrap/debug.h>
 | |
| #include <kwrap/task.h>
 | |
| #include "vos_ioctl.h"
 | |
| 
 | |
| #include <errno.h>
 | |
| #include <fcntl.h>
 | |
| #include <limits.h> /* to get PTHREAD_STACK_MIN */
 | |
| #include <pthread.h>
 | |
| #include <stdio.h>
 | |
| #include <string.h>
 | |
| #include <sys/ioctl.h>
 | |
| #include <sys/syscall.h>
 | |
| #include <sys/types.h>
 | |
| #include <unistd.h>
 | |
| /*-----------------------------------------------------------------------------*/
 | |
| /* Local Types Declarations                                                    */
 | |
| /*-----------------------------------------------------------------------------*/
 | |
| #define VOS_STRCPY(dst, src, dst_size) do { \
 | |
| 	strncpy(dst, src, (dst_size)-1); \
 | |
| 	dst[(dst_size)-1] = '\0'; \
 | |
| } while(0)
 | |
| 
 | |
| #ifndef MIN_NICE
 | |
| #define MIN_NICE -20
 | |
| #endif
 | |
| 
 | |
| #define USER_NICE_TO_VOS_PRIO(nice) ((nice) - MIN_NICE + VK_TASK_HIGHEST_PRIORITY)
 | |
| 
 | |
| typedef void *(*USER_FP) (void *);
 | |
| /*-----------------------------------------------------------------------------*/
 | |
| /* Local Constant Definitions                                                  */
 | |
| /*-----------------------------------------------------------------------------*/
 | |
| /*-----------------------------------------------------------------------------*/
 | |
| /* Local Global Variables                                                      */
 | |
| /*-----------------------------------------------------------------------------*/
 | |
| static pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;
 | |
| static int g_ioctl_fd = -1;
 | |
| 
 | |
| /*-----------------------------------------------------------------------------*/
 | |
| /* Interface Functions                                                         */
 | |
| /*-----------------------------------------------------------------------------*/
 | |
| static int vos_task_get_fd(void)
 | |
| {
 | |
| 	pthread_mutex_lock(&g_mutex);
 | |
| 
 | |
| 	if (g_ioctl_fd < 0) {
 | |
| 		g_ioctl_fd = open("/dev/"VOS_IOCTL_DEV_NAME, O_RDWR);
 | |
| 		if (g_ioctl_fd < 0) {
 | |
| 			DBG_ERR("open %s failed", "/dev/"VOS_IOCTL_DEV_NAME);
 | |
| 			pthread_mutex_unlock(&g_mutex);
 | |
| 			return -1;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	pthread_mutex_unlock(&g_mutex);
 | |
| 
 | |
| 	return g_ioctl_fd;
 | |
| }
 | |
| 
 | |
| static int vos_task_check_priority(int priority)
 | |
| {
 | |
| 	STATIC_ASSERT(VK_TASK_LOWEST_PRIORITY >= VK_TASK_HIGHEST_PRIORITY);
 | |
| 
 | |
| 	if (priority > VK_TASK_LOWEST_PRIORITY || priority < VK_TASK_HIGHEST_PRIORITY) {
 | |
| 		DBG_ERR("Invalid %d, Lowest(%d) ~ Highest(%d)\r\n", priority, VK_TASK_LOWEST_PRIORITY, VK_TASK_HIGHEST_PRIORITY);
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static void* vos_task_run_func(void *param)
 | |
| {
 | |
| 	VOS_TASK_IOARG_REG_N_RUN ioarg = {0};
 | |
| 	int fd;
 | |
| 	int oldtype = 0;
 | |
| 	int pthread_ret;
 | |
| 
 | |
| 	fd = vos_task_get_fd();
 | |
| 	if (fd < 0) {
 | |
| 		DBG_ERR("get fd failed\r\n");
 | |
| 		return 0;
 | |
| 	}
 | |
| 
 | |
| 	//VOS_TASK_IOCMD_REG_N_RUN will do:
 | |
| 	//1. register tid to vos driver
 | |
| 	//2. set priority (nice value)
 | |
| 	//3. get user_fp and user_parm to run
 | |
| 	ioarg.pthread_id = (unsigned long)pthread_self();
 | |
| 	ioarg.drv_task_id = (int)((long)param);
 | |
| 	ioarg.tid = (unsigned long)syscall(__NR_gettid);
 | |
| 	if (-1 == ioctl(fd, VOS_TASK_IOCMD_REG_N_RUN, &ioarg)) {
 | |
| 		DBG_ERR("ioctl fails, error = %d\r\n", errno);
 | |
| 		return NULL;
 | |
| 	}
 | |
| 
 | |
| 	//set pthread other attributes
 | |
| 	pthread_ret = pthread_setname_np(ioarg.pthread_id, ioarg.name);
 | |
| 	if (0 != pthread_ret) {
 | |
| 		DBG_WRN("%s set comm name failed, ret %d\r\n", ioarg.name, pthread_ret);
 | |
| 	}
 | |
| 
 | |
| 	//set thread type can be canceled immediately,
 | |
| 	//combine this type with xxx_interruptible to let threads can be terminated cleanly
 | |
| 	if (0 != pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldtype)) {
 | |
| 		DBG_WRN("setcanceltype failed\r\n");
 | |
| 	}
 | |
| 
 | |
| 	//run user function
 | |
| 	return ((USER_FP)ioarg.user_fp)(ioarg.user_parm);
 | |
| }
 | |
| 
 | |
| void vos_task_set_priority(VK_TASK_HANDLE task_hdl, int priority)
 | |
| {
 | |
| 	VOS_TASK_IOARG_PRIORITY ioarg = {0};
 | |
| 	int fd;
 | |
| 
 | |
| 	if (0 != vos_task_check_priority(priority)) {
 | |
| 		DBG_ERR("skip, task_hdl 0x%X\r\n", (unsigned int)task_hdl);
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	fd = vos_task_get_fd();
 | |
| 	if (fd < 0) {
 | |
| 		DBG_ERR("get fd failed\r\n");
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	ioarg.drv_task_id = (int)task_hdl;
 | |
| 	ioarg.vos_prio = priority;
 | |
| 	if (-1 == ioctl(fd, VOS_TASK_IOCMD_SET_PRIORITY, &ioarg)) {
 | |
| 		DBG_ERR("ioctl fails, error = %d\r\n", errno);
 | |
| 		return;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| VK_TASK_HANDLE vos_task_create(void *fp, void *parm, const char name[], int priority, int stksize)
 | |
| {
 | |
| 	VOS_TASK_IOARG_UINFO uinfo = {0};
 | |
| 	int fd;
 | |
| 
 | |
| 	// if priority is not set, mapping it to nice(0)
 | |
| 	if (0 == priority) {
 | |
| 		priority = USER_NICE_TO_VOS_PRIO(0);
 | |
| 	}
 | |
| 
 | |
| 	if (0 != vos_task_check_priority(priority)) {
 | |
| 		DBG_ERR("check_priority %d failed\n", priority);
 | |
| 		return 0;
 | |
| 	}
 | |
| 
 | |
| 	if (NULL == fp) {
 | |
| 		DBG_ERR("fp is NULL\r\n");
 | |
| 		return 0;
 | |
| 	}
 | |
| 
 | |
| 	fd = vos_task_get_fd();
 | |
| 	if (fd < 0) {
 | |
| 		DBG_ERR("get fd failed\r\n");
 | |
| 		return 0;
 | |
| 	}
 | |
| 
 | |
| 	if (stksize < PTHREAD_STACK_MIN) {
 | |
| 		stksize = PTHREAD_STACK_MIN;
 | |
| 	}
 | |
| 
 | |
| 	VOS_STRCPY(uinfo.name, name, sizeof(uinfo.name));
 | |
| 	uinfo.drv_task_id = -1; // drv_task_id -1 to get a new task id and set user info
 | |
| 	uinfo.vos_prio = priority;
 | |
| 	uinfo.user_fp = fp;
 | |
| 	uinfo.user_parm = parm;
 | |
| 	uinfo.user_stksize = stksize;
 | |
| 	if (-1 == ioctl(fd, VOS_TASK_IOCMD_SET_UINFO, &uinfo)) {
 | |
| 		DBG_ERR("ioctl fails, error = %d\r\n", errno);
 | |
| 		return 0;
 | |
| 	}
 | |
| 
 | |
| 	if (uinfo.drv_task_id < 0) {
 | |
| 		DBG_ERR("Invalid drv_task_id %d\r\n", uinfo.drv_task_id);
 | |
| 		return 0;
 | |
| 	}
 | |
| 
 | |
| 	return (VK_TASK_HANDLE)uinfo.drv_task_id;
 | |
| }
 | |
| 
 | |
| int vos_task_resume(VK_TASK_HANDLE task_hdl)
 | |
| {
 | |
| 	VOS_TASK_IOARG_UINFO uinfo = {0};
 | |
| 	VOS_TASK_IOARG ioarg = {0};
 | |
| 	pthread_attr_t attr = {0};
 | |
| 	pthread_t pthread_id;
 | |
| 	int pthread_ret;
 | |
| 	int fd;
 | |
| 
 | |
| 	fd = vos_task_get_fd();
 | |
| 	if (fd < 0) {
 | |
| 		DBG_ERR("get fd failed\r\n");
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| 	uinfo.drv_task_id = (int)task_hdl; // drv_task_id > 0 to get user info
 | |
| 	if (-1 == ioctl(fd, VOS_TASK_IOCMD_GET_UINFO, &uinfo)) {
 | |
| 		DBG_ERR("ioctl fails, error = %d\r\n", errno);
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| 	pthread_ret = pthread_attr_init(&attr);
 | |
| 	if (0 != pthread_ret) {
 | |
| 		DBG_ERR("%s attr_init failed, ret %d\r\n", uinfo.name, pthread_ret);
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| 	pthread_ret = pthread_attr_setstacksize (&attr, uinfo.user_stksize);
 | |
| 	if (0 != pthread_ret) {
 | |
| 		DBG_ERR("%s setstacksize failed, ret %d\r\n", uinfo.name, pthread_ret);
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| 	pthread_ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
 | |
| 	if (0 != pthread_ret) {
 | |
| 		DBG_ERR("%s setdetachstate failed, ret %d\r\n", uinfo.name, pthread_ret);
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| 	pthread_ret = pthread_create(&pthread_id, &attr, vos_task_run_func, (void *)((long)uinfo.drv_task_id));
 | |
| 	if (0 != pthread_ret) {
 | |
| 		DBG_ERR("%s create failed, ret %d\r\n", uinfo.name, pthread_ret);
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| 	pthread_ret = pthread_attr_destroy(&attr);
 | |
| 	if (0 != pthread_ret) {
 | |
| 		DBG_ERR("%s attr_destroy failed, ret %d\r\n", uinfo.name, pthread_ret);
 | |
| 		//do not return NULL, since it is created
 | |
| 	}
 | |
| 
 | |
| 	//Note: We have to register pthread_id right away,
 | |
| 	// because users may call vos_task_set_priority which needs pthread_id to convert handles
 | |
| 	ioarg.pthread_id = (unsigned long)pthread_id;
 | |
| 	ioarg.drv_task_id = (int)task_hdl;
 | |
| 	if (-1 == ioctl(fd, VOS_TASK_IOCMD_RESUME, &ioarg)) {
 | |
| 		DBG_ERR("ioctl fails, error = %d\r\n", errno);
 | |
| 		//do not return NULL, since it is created
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| void vos_task_destroy(VK_TASK_HANDLE task_hdl)
 | |
| {
 | |
| 	VOS_TASK_IOARG ioarg = {0};
 | |
| 	int fd;
 | |
| 
 | |
| 	if (0 == task_hdl) {
 | |
| 		DBG_ERR("Invalid task_hdl 0x%lX\r\n", (ULONG)task_hdl);
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	fd = vos_task_get_fd();
 | |
| 	if (fd < 0) {
 | |
| 		DBG_ERR("get fd failed\r\n");
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	ioarg.drv_task_id = (int)task_hdl;
 | |
| 	if (-1 == ioctl(fd, VOS_TASK_IOCMD_DESTROY, &ioarg)) {
 | |
| 		DBG_ERR("ioctl fails, error = %d\r\n", errno);
 | |
| 	}
 | |
| 
 | |
| 	if (ioarg.pthread_id) {
 | |
| 		pthread_cancel((pthread_t)ioarg.pthread_id);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| VK_TASK_HANDLE vos_task_get_handle(void)
 | |
| {
 | |
| 	VOS_TASK_IOARG ioarg = {0};
 | |
| 	int fd;
 | |
| 
 | |
| 	fd = vos_task_get_fd();
 | |
| 	if (fd < 0) {
 | |
| 		DBG_ERR("get fd failed\r\n");
 | |
| 		return 0;
 | |
| 	}
 | |
| 
 | |
| 	ioarg.pthread_id = (unsigned long)pthread_self();
 | |
| 	if (-1 == ioctl(fd, VOS_TASK_IOCMD_CONVERT_HDL, &ioarg)) {
 | |
| 		DBG_ERR("ioctl fails, error = %d\r\n", errno);
 | |
| 		return 0;
 | |
| 	}
 | |
| 
 | |
| 	return (VK_TASK_HANDLE)ioarg.drv_task_id;
 | |
| }
 | |
| 
 | |
| int vos_task_get_name(VK_TASK_HANDLE task_hdl, char *name, unsigned int len)
 | |
| {
 | |
| 	VOS_TASK_IOARG ioarg = {0};
 | |
| 	int fd;
 | |
| 	int pthread_ret;
 | |
| 
 | |
| 	if (0 == task_hdl) {
 | |
| 		DBG_ERR("Invalid task_hdl 0x%lX\r\n", (ULONG)task_hdl);
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| 	if (NULL == name) {
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| 	fd = vos_task_get_fd();
 | |
| 	if (fd < 0) {
 | |
| 		DBG_ERR("get fd failed\r\n");
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| 	ioarg.drv_task_id = (int)task_hdl;
 | |
| 	if (-1 == ioctl(fd, VOS_TASK_IOCMD_CONVERT_HDL, &ioarg)) {
 | |
| 		DBG_ERR("ioctl fails, error = %d\r\n", errno);
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| 	pthread_ret = pthread_getname_np(ioarg.pthread_id, name, len);
 | |
| 	if (0 != pthread_ret) {
 | |
| 		DBG_ERR("0x%lX get_name failed, ret %d\r\n", (ULONG)task_hdl, pthread_ret);
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| void vos_task_enter(void)
 | |
| {
 | |
| }
 | |
| 
 | |
| int vos_task_return(int rtn_val)
 | |
| {
 | |
| 	VOS_TASK_IOARG ioarg = {0};
 | |
| 	int fd;
 | |
| 
 | |
| 	fd = vos_task_get_fd();
 | |
| 	if (fd < 0) {
 | |
| 		DBG_ERR("get fd failed\r\n");
 | |
| 		return 0;
 | |
| 	}
 | |
| 
 | |
| 	ioarg.pthread_id = (unsigned long)pthread_self();
 | |
| 	if (-1 == ioctl(fd, VOS_TASK_IOCMD_RETURN, &ioarg)) {
 | |
| 		DBG_ERR("ioctl fails, error = %d\r\n", errno);
 | |
| 	}
 | |
| 
 | |
| 	pthread_exit(NULL);
 | |
| 	return 0;
 | |
| }
 | 
