Quellcode durchsuchen

!103 添加对用户态errno支持
Merge pull request !103 from jesven/errno_support

bernard vor 5 Jahren
Ursprung
Commit
a4fe10cf89
3 geänderte Dateien mit 251 neuen und 51 gelöschten Zeilen
  1. 44 0
      components/lwp/lwp.h
  2. 188 51
      components/lwp/lwp_syscall.c
  3. 19 0
      src/kservice.c

+ 44 - 0
components/lwp/lwp.h

@@ -120,6 +120,50 @@ void rt_cpu_set_thread_idr(void *p);
 void lwp_mmu_switch(struct rt_thread *thread);
 #endif
 
+#ifdef RT_USING_USERSPACE
+struct __pthread {
+    /* Part 1 -- these fields may be external or
+     *      * internal (accessed via asm) ABI. Do not change. */
+    struct pthread *self;
+    uintptr_t *dtv;
+    struct pthread *prev, *next; /* non-ABI */
+    uintptr_t sysinfo;
+    uintptr_t canary, canary2;
+
+    /* Part 2 -- implementation details, non-ABI. */
+    int tid;
+    int errno_val;
+    volatile int detach_state;
+    volatile int cancel;
+    volatile unsigned char canceldisable, cancelasync;
+    unsigned char tsd_used:1;
+    unsigned char dlerror_flag:1;
+    unsigned char *map_base;
+    size_t map_size;
+    void *stack;
+    size_t stack_size;
+    size_t guard_size;
+    void *result;
+    struct __ptcb *cancelbuf;
+    void **tsd;
+    struct {
+        volatile void *volatile head;
+        long off;
+        volatile void *volatile pending;
+    } robust_list;
+    volatile int timer_id;
+    locale_t locale;
+    volatile int killlock[1];
+    char *dlerror_buf;
+    void *stdio_locks;
+
+    /* Part 3 -- the positions of these fields relative to
+     *      * the end of the structure is external and internal ABI. */
+    uintptr_t canary_at_end;
+    uintptr_t *dtv_copy;
+};
+#endif
+
 #ifdef __cplusplus
 }
 #endif

+ 188 - 51
components/lwp/lwp_syscall.c

@@ -384,22 +384,33 @@ void sys_exit_group(int status)
 ssize_t sys_read(int fd, void *buf, size_t nbyte)
 {
 #ifdef RT_USING_USERSPACE
-    void *kmem;
-    ssize_t ret;
+    void *kmem = RT_NULL;
+    ssize_t ret = -1;
 
     if (!nbyte)
-        return 0;
+    {
+        rt_set_errno(EINVAL);
+        return -1;
+    }
 
     if (!lwp_user_accessable((void*)buf, nbyte))
-        return 0;
+    {
+        rt_set_errno(EINVAL);
+        return -1;
+    }
 
     kmem = kmem_get(nbyte);
     if (!kmem)
-        return 0;
+    {
+        rt_set_errno(ENOMEM);
+        return -1;
+    }
 
     ret = read(fd, kmem, nbyte);
     if (ret)
+    {
         lwp_put_to_user(buf, kmem, ret);
+    }
 
     kmem_put(kmem);
     return ret;
@@ -412,18 +423,27 @@ ssize_t sys_read(int fd, void *buf, size_t nbyte)
 ssize_t sys_write(int fd, const void *buf, size_t nbyte)
 {
 #ifdef RT_USING_USERSPACE
-    void *kmem;
-    ssize_t ret;
+    void *kmem = RT_NULL;
+    ssize_t ret = -1;
 
     if (!nbyte)
-        return 0;
+    {
+        rt_set_errno(EINVAL);
+        return -1;
+    }
 
     if (!lwp_user_accessable((void*)buf, nbyte))
-        return 0;
+    {
+        rt_set_errno(EINVAL);
+        return -1;
+    }
 
     kmem = kmem_get(nbyte);
     if (!kmem)
-        return 0;
+    {
+        rt_set_errno(ENOMEM);
+        return -1;
+    }
 
     lwp_get_from_user(kmem, (void *)buf, nbyte);
     ret = write(fd, kmem, nbyte);
@@ -445,20 +465,29 @@ off_t sys_lseek(int fd, off_t offset, int whence)
 int sys_open(const char *name, int flag, ...)
 {
 #ifdef RT_USING_USERSPACE
-    int ret;
-    rt_size_t len;
-    char *kname;
+    int ret = -1;
+    rt_size_t len = 0;
+    char *kname = RT_NULL;
 
     if (!lwp_user_accessable((void*)name, 1))
+    {
+        rt_set_errno(EINVAL);
         return -1;
+    }
 
     len = rt_strlen(name);
     if (!len)
+    {
+        rt_set_errno(EINVAL);
         return -1;
+    }
 
     kname = (char *)kmem_get(len + 1);
     if (!kname)
+    {
+        rt_set_errno(ENOMEM);
         return -1;
+    }
 
     lwp_get_from_user(kname, (void *)name, len + 1);
     ret = open(kname, flag, 0);
@@ -489,7 +518,7 @@ int sys_ioctl(int fd, unsigned long cmd, void* data)
 int sys_fstat(int file, struct stat *buf)
 {
 #ifdef RT_USING_USERSPACE
-    int ret;
+    int ret = -1;
     struct stat statbuff;
 
     ret = fstat(file, &statbuff);
@@ -503,15 +532,21 @@ int sys_fstat(int file, struct stat *buf)
 int sys_poll(struct pollfd *fds, nfds_t nfds, int timeout)
 {
 #ifdef RT_USING_USERSPACE
-    int ret;
-    struct pollfd *kfds;
+    int ret = -1;
+    struct pollfd *kfds = RT_NULL;
 
     if (!lwp_user_accessable((void*)fds, nfds * sizeof *fds))
+    {
+        rt_set_errno(EINVAL);
         return -1;
+    }
 
     kfds = (struct pollfd *)kmem_get(nfds * sizeof *kfds);
     if (!kfds)
+    {
+        rt_set_errno(ENOMEM);
         return -1;
+    }
 
     lwp_get_from_user(kfds, fds, nfds * sizeof *kfds);
     ret = poll(kfds, nfds, timeout);
@@ -534,11 +569,13 @@ int sys_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, s
     {
         if (!lwp_user_accessable((void*)readfds, sizeof *readfds))
         {
-            return -1;
+            rt_set_errno(EINVAL);
+            goto quit;
         }
         kreadfds = (fd_set *)kmem_get(sizeof *kreadfds);
         if (!kreadfds)
         {
+            rt_set_errno(ENOMEM);
             goto quit;
         }
         lwp_get_from_user(kreadfds, readfds, sizeof *kreadfds);
@@ -547,11 +584,13 @@ int sys_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, s
     {
         if (!lwp_user_accessable((void*)writefds, sizeof *writefds))
         {
-            return -1;
+            rt_set_errno(EINVAL);
+            goto quit;
         }
         kwritefds = (fd_set *)kmem_get(sizeof *kwritefds);
         if (!kwritefds)
         {
+            rt_set_errno(ENOMEM);
             goto quit;
         }
         lwp_get_from_user(kwritefds, writefds, sizeof *kwritefds);
@@ -560,11 +599,13 @@ int sys_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, s
     {
         if (!lwp_user_accessable((void*)exceptfds, sizeof *exceptfds))
         {
-            return -1;
+            rt_set_errno(EINVAL);
+            goto quit;
         }
         kexceptfds = (fd_set *)kmem_get(sizeof *kexceptfds);
         if (!kexceptfds)
         {
+            rt_set_errno(EINVAL);
             goto quit;
         }
         lwp_get_from_user(kexceptfds, exceptfds, sizeof *kexceptfds);
@@ -605,20 +646,29 @@ quit:
 int sys_unlink(const char *pathname)
 {
 #ifdef RT_USING_USERSPACE
-    int ret;
-    rt_size_t len;
-    char *kname;
+    int ret = -1;
+    rt_size_t len = 0;
+    char *kname = RT_NULL;
 
     if (!lwp_user_accessable((void*)pathname, 1))
+    {
+        rt_set_errno(EINVAL);
         return -1;
+    }
 
     len = rt_strlen(pathname);
     if (!len)
+    {
+        rt_set_errno(EINVAL);
         return -1;
+    }
 
     kname = (char *)kmem_get(len + 1);
     if (!kname)
+    {
+        rt_set_errno(ENOMEM);
         return -1;
+    }
 
     lwp_get_from_user(kname, (void *)pathname, len + 1);
     ret = unlink(kname);
@@ -641,37 +691,43 @@ int sys_nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
     dbg_log(DBG_LOG, "sys_nanosleep\n");
 
     if (!lwp_user_accessable((void*)rqtp, sizeof *rqtp))
+    {
+        rt_set_errno(EINVAL);
         return -1;
+    }
 
     lwp_get_from_user(&rqtp_k, (void *)rqtp, sizeof rqtp_k);
 
-    tick = rqtp_k.tv_sec * RT_TICK_PER_SECOND + ((uint64_t)rqtp_k.tv_nsec * RT_TICK_PER_SECOND)/ 1000000000;
+    tick = rqtp_k.tv_sec * RT_TICK_PER_SECOND + ((uint64_t)rqtp_k.tv_nsec * RT_TICK_PER_SECOND) / 1000000000;
     rt_thread_delay(tick);
 
     if (rmtp)
     {
         if (!lwp_user_accessable((void*)rmtp, sizeof *rmtp))
+        {
+            rt_set_errno(EINVAL);
             return -1;
+        }
 
         tick = rt_tick_get() - tick;
         /* get the passed time */
-        rmtp_k.tv_sec = tick/RT_TICK_PER_SECOND;
-        rmtp_k.tv_nsec = (tick%RT_TICK_PER_SECOND) * (1000000000/RT_TICK_PER_SECOND);
+        rmtp_k.tv_sec = tick / RT_TICK_PER_SECOND;
+        rmtp_k.tv_nsec = (tick % RT_TICK_PER_SECOND) * (1000000000 / RT_TICK_PER_SECOND);
 
         lwp_put_to_user(rmtp, (void *)&rmtp_k, sizeof rmtp_k);
     }
 #else
     dbg_log(DBG_LOG, "sys_nanosleep\n");
 
-    tick = rqtp->tv_sec * RT_TICK_PER_SECOND + ((uint64_t)rqtp->tv_nsec * RT_TICK_PER_SECOND)/ 1000000000;
+    tick = rqtp->tv_sec * RT_TICK_PER_SECOND + ((uint64_t)rqtp->tv_nsec * RT_TICK_PER_SECOND) / 1000000000;
     rt_thread_delay(tick);
 
     if (rmtp)
     {
         tick = rt_tick_get() - tick;
         /* get the passed time */
-        rmtp->tv_sec = tick/RT_TICK_PER_SECOND;
-        rmtp->tv_nsec = (tick%RT_TICK_PER_SECOND) * (1000000000/RT_TICK_PER_SECOND);
+        rmtp->tv_sec = tick / RT_TICK_PER_SECOND;
+        rmtp->tv_nsec = (tick % RT_TICK_PER_SECOND) * (1000000000 / RT_TICK_PER_SECOND);
     }
 #endif
 
@@ -687,7 +743,10 @@ int sys_gettimeofday(struct timeval *tp, struct timezone *tzp)
     if (tp)
     {
         if (!lwp_user_accessable((void*)tp, sizeof *tp))
+        {
+            rt_set_errno(EINVAL);
             return -1;
+        }
 
         t_k.tv_sec = rt_tick_get() / RT_TICK_PER_SECOND;
         t_k.tv_usec = (rt_tick_get() % RT_TICK_PER_SECOND) * (1000000 / RT_TICK_PER_SECOND);
@@ -969,9 +1028,15 @@ rt_thread_t sys_thread_create(void *arg[])
 #endif
     if (!user_stack)
     {
+        rt_set_errno(EINVAL);
         return RT_NULL;
     }
-    tid = rt_thread_create((const char*)arg[0], lwp_user_thread, (void*)arg[2], ALLOC_KERNEL_STACK_SIZE, (rt_uint8_t)(size_t)arg[4], (rt_uint32_t)arg[5]);
+    tid = rt_thread_create((const char*)arg[0],
+            lwp_user_thread,
+            (void*)arg[2],
+            ALLOC_KERNEL_STACK_SIZE,
+            (rt_uint8_t)(size_t)arg[4],
+            (rt_uint32_t)arg[5]);
     if (!tid)
     {
         goto fail;
@@ -1105,6 +1170,7 @@ int sys_stat(const char *file, struct stat *buf)
 
 int sys_notimpl(void)
 {
+    rt_set_errno(ENOSYS);
     return -ENOSYS;
 }
 
@@ -1184,7 +1250,7 @@ rt_size_t sys_device_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt
 /* network interfaces */
 int sys_accept(int socket, struct musl_sockaddr *addr, socklen_t *addrlen)
 {
-    int ret;
+    int ret = -1;
     struct sockaddr ksa;
     struct musl_sockaddr kmusladdr;
     socklen_t uaddrlen;
@@ -1194,16 +1260,19 @@ int sys_accept(int socket, struct musl_sockaddr *addr, socklen_t *addrlen)
     {
         if (!lwp_user_accessable(addrlen, sizeof (socklen_t *)))
         {
+            rt_set_errno(EINVAL);
             return -1;
         }
         lwp_get_from_user(&uaddrlen, addrlen, sizeof (socklen_t *));
         if (!uaddrlen)
         {
+            rt_set_errno(EINVAL);
             return -1;
         }
 
         if (!lwp_user_accessable(addr, uaddrlen))
         {
+            rt_set_errno(EINVAL);
             return -1;
         }
     }
@@ -1233,6 +1302,7 @@ int sys_bind(int socket, const struct musl_sockaddr *name, socklen_t namelen)
 
     if (!lwp_user_accessable((void*)name, namelen))
     {
+        rt_set_errno(EINVAL);
         return -1;
     }
     lwp_get_from_user(&kname, (void*)name, namelen);
@@ -1249,7 +1319,7 @@ int sys_shutdown(int socket, int how)
 
 int sys_getpeername (int socket, struct musl_sockaddr *name, socklen_t *namelen)
 {
-    int ret;
+    int ret = -1;
     struct sockaddr sa;
     struct musl_sockaddr kname;
     socklen_t unamelen;
@@ -1257,16 +1327,19 @@ int sys_getpeername (int socket, struct musl_sockaddr *name, socklen_t *namelen)
 
     if (!lwp_user_accessable(namelen, sizeof (socklen_t *)))
     {
+        rt_set_errno(EINVAL);
         return -1;
     }
     lwp_get_from_user(&unamelen, namelen, sizeof (socklen_t *));
     if (!unamelen)
     {
+        rt_set_errno(EINVAL);
         return -1;
     }
 
     if (!lwp_user_accessable(name, unamelen))
     {
+        rt_set_errno(EINVAL);
         return -1;
     }
 
@@ -1289,7 +1362,7 @@ int sys_getpeername (int socket, struct musl_sockaddr *name, socklen_t *namelen)
 
 int sys_getsockname (int socket, struct musl_sockaddr *name, socklen_t *namelen)
 {
-    int ret;
+    int ret = -1;
     struct sockaddr sa;
     struct musl_sockaddr kname;
     socklen_t unamelen;
@@ -1297,16 +1370,19 @@ int sys_getsockname (int socket, struct musl_sockaddr *name, socklen_t *namelen)
 
     if (!lwp_user_accessable(namelen, sizeof (socklen_t *)))
     {
+        rt_set_errno(EINVAL);
         return -1;
     }
     lwp_get_from_user(&unamelen, namelen, sizeof (socklen_t *));
     if (!unamelen)
     {
+        rt_set_errno(EINVAL);
         return -1;
     }
 
     if (!lwp_user_accessable(name, unamelen))
     {
+        rt_set_errno(EINVAL);
         return -1;
     }
 
@@ -1348,6 +1424,7 @@ int sys_connect(int socket, const struct musl_sockaddr *name, socklen_t namelen)
 
     if (!lwp_user_accessable((void*)name, namelen))
     {
+        rt_set_errno(EINVAL);
         return -1;
     }
     lwp_get_from_user(&kname, (void*)name, namelen);
@@ -1397,14 +1474,23 @@ int sys_recvfrom(int socket, void *mem, size_t len, int flags,
     flgs = netflags_muslc_2_lwip(flags);
 #ifdef RT_USING_USERSPACE
     if (!len)
+    {
+        rt_set_errno(EINVAL);
         return -1;
+    }
 
     if (!lwp_user_accessable((void*)mem, len))
+    {
+        rt_set_errno(EINVAL);
         return -1;
+    }
 
     kmem = kmem_get(len);
     if (!kmem)
+    {
+        rt_set_errno(ENOMEM);
         return -1;
+    }
 
     if (flags == 0x2) {
         flags = 0x1;
@@ -1459,14 +1545,23 @@ int sys_sendto(int socket, const void *dataptr, size_t size, int flags,
     flgs = netflags_muslc_2_lwip(flags);
 #ifdef RT_USING_USERSPACE
     if (!size)
+    {
+        rt_set_errno(EINVAL);
         return -1;
+    }
 
     if (!lwp_user_accessable((void*)dataptr, size))
+    {
+        rt_set_errno(EINVAL);
         return -1;
+    }
 
     kmem = kmem_get(size);
     if (!kmem)
+    {
+        rt_set_errno(ENOMEM);
         return -1;
+    }
 
     lwp_get_from_user(kmem, (void *)dataptr, size);
 
@@ -1557,21 +1652,23 @@ int sys_sigaction(int sig, const struct sigaction *act,
 
     if (!sigsetsize)
     {
+        rt_set_errno(EINVAL);
         goto out;
     }
     if (sigsetsize > sizeof(lwp_sigset_t))
     {
         sigsetsize = sizeof(lwp_sigset_t);
-        goto out;
     }
     if (!act && !oact)
     {
+        rt_set_errno(EINVAL);
         goto out;
     }
     if (oact)
     {
         if (!lwp_user_accessable((void*)oact, sigsetsize))
         {
+            rt_set_errno(EINVAL);
             goto out;
         }
         pkoact = &koact;
@@ -1580,6 +1677,7 @@ int sys_sigaction(int sig, const struct sigaction *act,
     {
         if (!lwp_user_accessable((void*)act, sigsetsize))
         {
+            rt_set_errno(EINVAL);
             goto out;
         }
         kact.__sa_handler._sa_handler = act->sa_handler;
@@ -1607,29 +1705,32 @@ int sys_sigprocmask(int how, const sigset_t *sigset, sigset_t *oset, size_t size
 
     if (!size)
     {
+        rt_set_errno(EINVAL);
         return ret;
     }
     if (!oset && !sigset)
     {
+        rt_set_errno(EINVAL);
         return ret;
     }
     if (size > sizeof(lwp_sigset_t))
     {
         size = sizeof(lwp_sigset_t);
-        return ret;
     }
     if (oset)
     {
         if (!lwp_user_accessable((void*)oset, size))
         {
+            rt_set_errno(EINVAL);
             return ret;
         }
         poldset = &oldset;
     }
     if (sigset)
     {
-        if (!lwp_user_accessable((void*)oset, size))
+        if (!lwp_user_accessable((void*)sigset, size))
         {
+            rt_set_errno(EINVAL);
             return ret;
         }
         lwp_get_from_user(&newset, (void*)sigset, size);
@@ -1665,28 +1766,33 @@ int sys_thread_sigprocmask(int how, const lwp_sigset_t *sigset, lwp_sigset_t *os
 
     if (!size)
     {
+        rt_set_errno(EINVAL);
         return ret;
     }
     if (!oset && !sigset)
     {
+        rt_set_errno(EINVAL);
         return ret;
     }
     if (size != sizeof(lwp_sigset_t))
     {
+        rt_set_errno(EINVAL);
         return ret;
     }
     if (oset)
     {
         if (!lwp_user_accessable((void*)oset, size))
         {
+            rt_set_errno(EINVAL);
             return ret;
         }
         poldset = &oldset;
     }
     if (sigset)
     {
-        if (!lwp_user_accessable((void*)oset, size))
+        if (!lwp_user_accessable((void*)sigset, size))
         {
+            rt_set_errno(EINVAL);
             return ret;
         }
         lwp_get_from_user(&newset, (void*)sigset, sizeof(lwp_sigset_t));
@@ -1737,13 +1843,18 @@ int sys_getaddrinfo(const char *nodename, const char *servname, const struct mus
     if (nodename)
     {
         k_nodename = rt_strdup(nodename);
-        if (!k_nodename) goto exit;
+        if (!k_nodename)
+        {
+            rt_set_errno(ENOMEM);
+            goto exit;
+        }
     }
     if (servname)
     {
         k_servname = rt_strdup(servname);
         if (!k_servname)
         {
+            rt_set_errno(ENOMEM);
             goto exit;
         }
     }
@@ -1753,6 +1864,7 @@ int sys_getaddrinfo(const char *nodename, const char *servname, const struct mus
         k_hints = (struct addrinfo*) rt_malloc(sizeof *hints);
         if (!k_hints)
         {
+            rt_set_errno(ENOMEM);
             goto exit;
         }
 
@@ -1809,7 +1921,8 @@ int sys_gethostbyname2_r(const char *name, int af, struct hostent *ret,
         char *buf, size_t buflen,
         struct hostent **result, int *err)
 {
-    int sal_ret, sal_err;
+    int ret_val = -1;
+    int sal_ret = -1 , sal_err = -1;
     struct hostent sal_he;
     struct hostent *sal_result = NULL;
     char *sal_buf = NULL;
@@ -1819,25 +1932,29 @@ int sys_gethostbyname2_r(const char *name, int af, struct hostent *ret,
     {
         /* not all arguments given */
         *err = EINVAL;
-        return -1;
+        rt_set_errno(EINVAL);
+        goto __exit;
     }
     if ((name == NULL) || (ret == NULL) || (buf == NULL))
     {
         /* not all arguments given */
         *err = EINVAL;
-        return -1;
+        rt_set_errno(EINVAL);
+        goto __exit;
     }
 
     *result = ret;
     sal_buf = (char *)malloc (HOSTENT_BUFSZ);
     if (sal_buf == NULL)
     {
+        rt_set_errno(ENOMEM);
         goto __exit;
     }
 
     k_name = rt_strdup(name);
     if (k_name == NULL)
     {
+        rt_set_errno(ENOMEM);
         goto __exit;
     }
 
@@ -1845,12 +1962,15 @@ int sys_gethostbyname2_r(const char *name, int af, struct hostent *ret,
     sal_ret = sal_gethostbyname_r(k_name, &sal_he, sal_buf, HOSTENT_BUFSZ, &sal_result, &sal_err);
     if (sal_ret == 0)
     {
-        int index, cnt;
+        int index = 0, cnt = 0;
         char *ptr = buf;
 
         /* get counter */
         index = 0;
-        while (sal_he.h_addr_list[index] != NULL) index ++;
+        while (sal_he.h_addr_list[index] != NULL)
+        {
+            index ++;
+        }
         cnt = index + 1;
 
         /* update user space hostent */
@@ -1876,12 +1996,14 @@ int sys_gethostbyname2_r(const char *name, int af, struct hostent *ret,
         ret->h_addr_list[index] = NULL;
     }
 
+    ret_val = 0;
+
 __exit:
     /* release buffer */
     if (sal_buf) free(sal_buf);
     if (k_name) free(k_name);
 
-    return 0;
+    return ret_val;
 }
 #endif
 
@@ -1915,28 +2037,30 @@ struct libc_dirent {
 };
 int sys_getdents(int fd, struct libc_dirent *dirp, size_t nbytes)
 {
-    int ret;
+    int ret = -1;
     struct dfs_fd *dfs_fd;
     size_t cnt = (nbytes / sizeof(struct libc_dirent));
-    size_t rtt_nbytes;
+    size_t rtt_nbytes = 0;
     struct dirent *rtt_dirp;
 
     if (cnt == 0)
     {
-        return 0;
+        rt_set_errno(EINVAL);
+        return -1;
     }
     rtt_nbytes = cnt * sizeof(struct dirent);
     rtt_dirp = (struct dirent*)rt_malloc(rtt_nbytes);
     if (!rtt_dirp)
     {
-        return 0;
+        rt_set_errno(ENOMEM);
+        return -1;
     }
     dfs_fd = fd_get(fd);
     ret = dfs_file_getdents(dfs_fd, rtt_dirp, nbytes);
     fd_put(dfs_fd);
     if (ret)
     {
-        size_t i;
+        size_t i = 0;
         cnt = ret / sizeof(struct dirent);
         for (i = 0; i < cnt; i++)
         {
@@ -1959,6 +2083,10 @@ rt_err_t sys_get_errno(void)
 
 void sys_set_thread_area(void *p)
 {
+    rt_thread_t thread;
+
+    thread = rt_thread_self();
+    thread->thread_idr = p;
     lwp_set_thread_area(p);
 }
 
@@ -1969,21 +2097,30 @@ long sys_set_tid_address(int *tidptr)
 
 int sys_access(const char *filename, int mode)
 {
-    int ret;
+    int ret = -1;
 #ifdef RT_USING_USERSPACE
-    rt_size_t len;
-    char *kname;
+    rt_size_t len = 0;
+    char *kname = RT_NULL;
 
     if (!lwp_user_accessable((void*)filename, 1))
+    {
+        rt_set_errno(EINVAL);
         return -1;
+    }
 
     len = rt_strlen(filename);
     if (!len)
+    {
+        rt_set_errno(EINVAL);
         return -1;
+    }
 
     kname = (char *)kmem_get(len + 1);
     if (!kname)
+    {
+        rt_set_errno(ENOMEM);
         return -1;
+    }
 
     lwp_get_from_user(kname, (void *)filename, len + 1);
     ret = open(kname, mode, 0);

+ 19 - 0
src/kservice.c

@@ -27,6 +27,8 @@
 #endif
 
 #ifdef RT_USING_LWP
+#include <lwp.h>
+#include <lwp_user_mm.h>
 #include <lwp_console.h>
 #endif
 
@@ -95,6 +97,23 @@ void rt_set_errno(rt_err_t error)
     }
 
     tid->error = error;
+#ifdef RT_USING_LWP
+    /* is a process's thread */
+    if (tid->lwp && tid->thread_idr)
+    {
+        pthread_t ptid;
+
+        if (error < 0)
+        {
+            error = -error;
+        }
+        ptid = (pthread_t)((size_t)tid->thread_idr - sizeof(struct __pthread));
+        if (lwp_user_accessable(ptid, sizeof(struct __pthread)))
+        {
+            lwp_put_to_user(&ptid->errno_val, &error, sizeof(ptid->errno_val));
+        }
+    }
+#endif
 }
 RTM_EXPORT(rt_set_errno);