Merge Posix Cancellation Point
authorjc_.kim <jc_.kim@samsung.com>
Thu, 9 Mar 2017 06:03:03 +0000 (15:03 +0900)
committerjc_.kim <jc_.kim@samsung.com>
Thu, 9 Mar 2017 06:03:03 +0000 (15:03 +0900)
Merge Posix Cancellation Point referenced by Nuttx 7.18

57 files changed:
lib/libc/pthread/Make.defs
lib/libc/pthread/pthread_setcancelstate.c [new file with mode: 0644]
lib/libc/pthread/pthread_setcanceltype.c [new file with mode: 0644]
lib/libc/pthread/pthread_testcancel.c [new file with mode: 0644]
lib/libc/sched/Make.defs
lib/libc/sched/task_setcanceltype.c [new file with mode: 0644]
lib/libc/sched/task_testcancel.c [new file with mode: 0644]
os/fs/vfs/fs_close.c
os/fs/vfs/fs_fcntl.c
os/fs/vfs/fs_fsync.c
os/fs/vfs/fs_open.c
os/fs/vfs/fs_poll.c
os/fs/vfs/fs_pread.c
os/fs/vfs/fs_pwrite.c
os/fs/vfs/fs_read.c
os/fs/vfs/fs_select.c
os/fs/vfs/fs_write.c
os/include/pthread.h
os/include/sched.h
os/include/tinyara/cancelpt.h [new file with mode: 0644]
os/include/tinyara/sched.h
os/kernel/Kconfig
os/kernel/mqueue/mq_rcvinternal.c
os/kernel/mqueue/mq_receive.c
os/kernel/mqueue/mq_send.c
os/kernel/mqueue/mq_sndinternal.c
os/kernel/mqueue/mq_timedreceive.c
os/kernel/mqueue/mq_timedsend.c
os/kernel/pthread/Make.defs
os/kernel/pthread/pthread.h
os/kernel/pthread/pthread_cancel.c
os/kernel/pthread/pthread_cleanup.c [new file with mode: 0644]
os/kernel/pthread/pthread_condtimedwait.c
os/kernel/pthread/pthread_condwait.c
os/kernel/pthread/pthread_create.c
os/kernel/pthread/pthread_exit.c
os/kernel/pthread/pthread_join.c
os/kernel/sched/sched_wait.c
os/kernel/sched/sched_waitid.c
os/kernel/sched/sched_waitpid.c
os/kernel/semaphore/sem_timedwait.c
os/kernel/semaphore/sem_wait.c
os/kernel/signal/sig_nanosleep.c
os/kernel/signal/sig_pause.c
os/kernel/signal/sig_suspend.c
os/kernel/signal/sig_timedwait.c
os/kernel/signal/sig_waitinfo.c
os/kernel/task/Make.defs
os/kernel/task/task.h
os/kernel/task/task_cancelpt.c [new file with mode: 0644]
os/kernel/task/task_delete.c
os/kernel/task/task_exithook.c
os/kernel/task/task_restart.c
os/kernel/task/task_setcancelstate.c [new file with mode: 0644]
os/kernel/task/task_setcanceltype.c [new file with mode: 0644]
os/kernel/task/task_setup.c
os/kernel/task/task_testcancel.c [new file with mode: 0644]

index 6dd6ef3..8bfe2a3 100644 (file)
@@ -61,9 +61,11 @@ CSRCS += pthread_attrinit.c pthread_attrdestroy.c \
                  pthread_barrierattrgetpshared.c pthread_barrierattrsetpshared.c \
                  pthread_condattrinit.c pthread_condattrdestroy.c \
                  pthread_mutexattrinit.c pthread_mutexattrdestroy.c \
-                 pthread_mutexattrgetpshared.c pthread_mutexattrsetpshared.c
+                 pthread_mutexattrgetpshared.c pthread_mutexattrsetpshared.c \
+                 pthread_setcancelstate.c pthread_setcanceltype.c  \
+                 pthread_testcancel.c
 
-ifeq ($(CONFIG_IOTIVITY_SCONS_BUILD),y)
+ifeq ($(CONFIG_ENABLE_IOTIVITY),y)
 CSRCS += pthread_condattrsetclock.c
 endif
 
diff --git a/lib/libc/pthread/pthread_setcancelstate.c b/lib/libc/pthread/pthread_setcancelstate.c
new file mode 100644 (file)
index 0000000..f77e7b3
--- /dev/null
@@ -0,0 +1,107 @@
+/****************************************************************************
+ *
+ * Copyright 2016 Samsung Electronics All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ ****************************************************************************/
+/****************************************************************************
+ * libc/pthread/pthread_setcancelstate.c
+ *
+ *   Copyright (C) 2007, 2008, 2016 Gregory Nutt. All rights reserved.
+ *   Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <tinyara/config.h>
+#include <pthread.h>
+#include <sched.h>
+#include <errno.h>
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+/* These are defined in different header files but must have the same values. */
+
+#if PTHREAD_CANCEL_ENABLE != TASK_CANCEL_ENABLE
+#  error We must have  PTHREAD_CANCEL_ENABLE == TASK_CANCEL_ENABLE
+#endif
+
+#if PTHREAD_CANCEL_DISABLE != TASK_CANCEL_DISABLE
+#  error We must have  PTHREAD_CANCEL_DISABLE == TASK_CANCEL_DISABLE
+#endif
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: pthread_setcancelstate
+ *
+ * Description:
+ *   The pthread_setcancelstate() function atomically both sets the calling
+ *   thread's cancelability state to the indicated state and returns the
+ *   previous cancelability state at the location referenced by oldstate.
+ *   Legal values for state are PTHREAD_CANCEL_ENABLE and
+ *   PTHREAD_CANCEL_DISABLE.
+ *
+ *   The cancelability state and type of any newly created threads,
+ *   including the thread in which main() was first invoked, are
+ *   PTHREAD_CANCEL_ENABLE and PTHREAD_CANCEL_DEFERRED respectively.
+ *
+ ****************************************************************************/
+
+int pthread_setcancelstate(int state, FAR int *oldstate)
+{
+       int ret;
+
+       /* task_setcancelstate() can do this */
+
+       ret = task_setcancelstate(state, oldstate);
+       if (ret < 0) {
+               ret = errno;
+       }
+
+       return ret;
+}
diff --git a/lib/libc/pthread/pthread_setcanceltype.c b/lib/libc/pthread/pthread_setcanceltype.c
new file mode 100644 (file)
index 0000000..87514d3
--- /dev/null
@@ -0,0 +1,108 @@
+/****************************************************************************
+ *
+ * Copyright 2016 Samsung Electronics All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ ****************************************************************************/
+/****************************************************************************
+ * libc/pthread/pthread_setcanceltype.c
+ *
+ *   Copyright (C) 2016 Gregory Nutt. All rights reserved.
+ *   Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <pthread.h>
+#include <sched.h>
+#include <errno.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+/* The following are defined in different header files but must have the
+ * same values.
+ */
+
+#if PTHREAD_CANCEL_DEFERRED != TASK_CANCEL_DEFERRED
+#  error We must have  PTHREAD_CANCEL_DEFERRED == TASK_CANCEL_DEFERRED
+#endif
+
+#if PTHREAD_CANCEL_ASYNCHRONOUS != TASK_CANCEL_ASYNCHRONOUS
+#  error We must have  PTHREAD_CANCEL_ASYNCHRONOUS == TASK_CANCEL_ASYNCHRONOUS
+#endif
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: pthread_setcancelstate
+ *
+ * Description:
+ *   The pthread_setcanceltype() function atomically both sets the calling
+ *   thread's cancelability type to the indicated type and returns the
+ *   previous cancelability type at the location referenced by oldtype
+ *   Legal values for type are PTHREAD_CANCEL_DEFERRED and
+ *   PTHREAD_CANCEL_ASYNCHRONOUS.
+ *
+ *   The cancelability state and type of any newly created threads,
+ *   including the thread in which main() was first invoked, are
+ *   PTHREAD_CANCEL_ENABLE and PTHREAD_CANCEL_DEFERRED respectively.
+ *
+ ****************************************************************************/
+
+int pthread_setcanceltype(int type, FAR int *oldtype)
+{
+       int ret;
+
+       /* task_setcanceltype() can do this */
+
+       ret = task_setcanceltype(type, oldtype);
+       if (ret < 0) {
+               ret = errno;
+       }
+
+       return ret;
+}
diff --git a/lib/libc/pthread/pthread_testcancel.c b/lib/libc/pthread/pthread_testcancel.c
new file mode 100644 (file)
index 0000000..bff3543
--- /dev/null
@@ -0,0 +1,79 @@
+/****************************************************************************
+ *
+ * Copyright 2016 Samsung Electronics All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ ****************************************************************************/
+/****************************************************************************
+ * libc/pthread/pthread_testcancel.c
+ *
+ *   Copyright (C) 2016 Gregory Nutt. All rights reserved.
+ *   Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <pthread.h>
+#include <sched.h>
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: pthread_testcancel
+ *
+ * Description:
+ *   The pthread_testcancel() function creates a cancellation point in the
+ *   calling thread. The pthread_testcancel() function has no effect if
+ *   cancelability is disabled
+ *
+ ****************************************************************************/
+
+void pthread_testcancel(void)
+{
+       /* task_testcancel() does the real work */
+
+       task_testcancel();
+}
index 0ab5f53..5310aca 100644 (file)
@@ -58,6 +58,10 @@ ifeq ($(CONFIG_BUILD_PROTECTED),y)
 CSRCS += task_startup.c
 endif
 
+ifeq ($(CONFIG_CANCELLATION_POINTS),y)
+CSRCS += task_setcanceltype.c task_testcancel.c
+endif
+
 # Add the sched directory to the build
 
 DEPPATH += --dep-path sched
diff --git a/lib/libc/sched/task_setcanceltype.c b/lib/libc/sched/task_setcanceltype.c
new file mode 100644 (file)
index 0000000..aeee9d4
--- /dev/null
@@ -0,0 +1,90 @@
+/****************************************************************************
+ *
+ * Copyright 2016 Samsung Electronics All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ ****************************************************************************/
+/****************************************************************************
+ * libc/sched/task_setcanceltype.c
+ *
+ *   Copyright (C) 2016 Gregory Nutt. All rights reserved.
+ *   Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <sched.h>
+#include <errno.h>
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: task_setcancelstate
+ *
+ * Description:
+ *   The task_setcanceltype() function atomically both sets the calling
+ *   task's cancelability type to the indicated type and returns the
+ *   previous cancelability type at the location referenced by oldtype
+ *   Legal values for type are TASK_CANCEL_DEFERRED and
+ *   TASK_CANCEL_ASYNCHRONOUS.
+ *
+ *   The cancelability state and type of any newly created tasks are
+ *   TASK_CANCEL_ENABLE and TASK_CANCEL_DEFERRED respectively.
+ *
+ ****************************************************************************/
+
+int task_setcanceltype(int type, FAR int *oldtype)
+{
+       /* Return the current type if so requrested */
+
+       if (oldtype != NULL) {
+               *oldtype = TASK_CANCEL_ASYNCHRONOUS;
+       }
+
+       /* Check the requested cancellation type */
+
+       return (type == TASK_CANCEL_ASYNCHRONOUS) ? OK : ENOSYS;
+}
diff --git a/lib/libc/sched/task_testcancel.c b/lib/libc/sched/task_testcancel.c
new file mode 100644 (file)
index 0000000..db80e64
--- /dev/null
@@ -0,0 +1,75 @@
+/****************************************************************************
+ *
+ * Copyright 2016 Samsung Electronics All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ ****************************************************************************/
+/****************************************************************************
+ * libc/sched/task_testcancel.c
+ *
+ *   Copyright (C) 2016 Gregory Nutt. All rights reserved.
+ *   Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <sched.h>
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: task_testcancel
+ *
+ * Description:
+ *   The task_testcancel() function creates a cancellation point in the
+ *   calling thread. The task_testcancel() function has no effect if
+ *   cancelability is disabled
+ *
+ ****************************************************************************/
+
+void task_testcancel(void)
+{
+}
index 9bc38db..8b26a23 100644 (file)
@@ -60,6 +60,7 @@
 #include <sched.h>
 #include <errno.h>
 #include <tinyara/fs/fs.h>
+#include <tinyara/cancelpt.h>
 
 #if defined(CONFIG_NET) && CONFIG_NSOCKET_DESCRIPTORS > 0
 #include <tinyara/net/net.h>
@@ -99,7 +100,11 @@ int close(int fd)
        int err;
 #if CONFIG_NFILE_DESCRIPTORS > 0
        int ret;
+#endif
+       /* close() is a cancellation point */
+       (void)enter_cancellation_point();
 
+#if CONFIG_NFILE_DESCRIPTORS > 0
        /* Did we get a valid file descriptor? */
 
        if ((unsigned int)fd >= CONFIG_NFILE_DESCRIPTORS)
@@ -109,7 +114,9 @@ int close(int fd)
 
 #if defined(CONFIG_NET) && CONFIG_NSOCKET_DESCRIPTORS > 0
                if ((unsigned int)fd < (CONFIG_NFILE_DESCRIPTORS + CONFIG_NSOCKET_DESCRIPTORS)) {
-                       return net_close(fd);
+                       ret = net_close(fd);
+                       leave_cancellation_point();
+                       return ret;
                } else
 #endif
                {
@@ -135,11 +142,13 @@ int close(int fd)
                err = -ret;
                goto errout;
        }
+       leave_cancellation_point();
        return OK;
 
 #endif
 
 errout:
        set_errno(err);
+       leave_cancellation_point();
        return ERROR;
 }
index 891c758..54f04f1 100644 (file)
@@ -64,6 +64,7 @@
 #include <tinyara/fs/fs.h>
 #include <tinyara/net/net.h>
 #include <tinyara/sched.h>
+#include <tinyara/cancelpt.h>
 
 #include "inode/inode.h"
 
@@ -242,6 +243,9 @@ int fcntl(int fd, int cmd, ...)
        va_list ap;
        int ret;
 
+       /* fcntl() is a cancellation point */
+       (void)enter_cancellation_point();
+
        /* Setup to access the variable argument list */
 
        va_start(ap, cmd);
@@ -257,6 +261,7 @@ int fcntl(int fd, int cmd, ...)
                        /* The errno value has already been set */
 
                        va_end(ap);
+                       leave_cancellation_point();
                        return ERROR;
                }
 
@@ -282,5 +287,6 @@ int fcntl(int fd, int cmd, ...)
        }
 
        va_end(ap);
+       leave_cancellation_point();
        return ret;
 }
index bf8b153..806d506 100644 (file)
@@ -61,8 +61,9 @@
 #include <errno.h>
 #include <assert.h>
 
-#include <tinyara/fs/fs.h>
 #include <tinyara/sched.h>
+#include <tinyara/cancelpt.h>
+#include <tinyara/fs/fs.h>
 
 #include "inode/inode.h"
 
@@ -146,6 +147,10 @@ errout:
 int fsync(int fd)
 {
        FAR struct file *filep;
+       int ret;
+
+       /* fsync() is a cancellation point */
+       (void)enter_cancellation_point();
 
        /* Get the file structure corresponding to the file descriptor. */
 
@@ -153,12 +158,15 @@ int fsync(int fd)
        if (!filep) {
                /* The errno value has already been set */
 
+               leave_cancellation_point();
                return ERROR;
        }
 
        /* Perform the fsync operation */
 
-       return file_fsync(filep);
+       ret = file_fsync(filep);
+       leave_cancellation_point();
+       return ret;
 }
 
 #endif                                                 /* !CONFIG_DISABLE_MOUNTPOINT */
index a712177..4d57255 100644 (file)
@@ -65,6 +65,7 @@
 #include <stdarg.h>
 #endif
 
+#include <tinyara/cancelpt.h>
 #include <tinyara/fs/fs.h>
 
 #include "inode/inode.h"
@@ -118,6 +119,9 @@ int open(const char *path, int oflags, ...)
 #warning "File creation not implemented"
 #endif
 
+       /* open() is a cancellation point */
+       (void)enter_cancellation_point();
+
        /* If the file is opened for creation, then get the mode bits */
 
        if ((oflags & (O_WRONLY | O_CREAT)) != 0) {
@@ -177,7 +181,7 @@ int open(const char *path, int oflags, ...)
        filep = fs_getfilep(fd);
        if (!filep) {
                /* The errno value has already been set */
-
+               leave_cancellation_point();
                return ERROR;
        }
 
@@ -203,6 +207,7 @@ int open(const char *path, int oflags, ...)
                goto errout_with_fd;
        }
 
+       leave_cancellation_point();
        return fd;
 
 errout_with_fd:
@@ -211,5 +216,6 @@ errout_with_inode:
        inode_release(inode);
 errout:
        set_errno(ret);
+       leave_cancellation_point();
        return ERROR;
 }
index f7b3c3a..deb9d5f 100644 (file)
@@ -65,6 +65,7 @@
 
 #include <tinyara/sched.h>
 #include <tinyara/clock.h>
+#include <tinyara/cancelpt.h>
 #include <tinyara/fs/fs.h>
 
 #ifdef CONFIG_NET_LWIP
@@ -303,6 +304,9 @@ int poll(FAR struct pollfd *fds, nfds_t nfds, int timeout)
        int count = 0;
        int ret;
 
+       /* poll() is a cancellation point */
+       (void)enter_cancellation_point();
+
        sem_init(&sem, 0, 0);
        ret = poll_setup(fds, nfds, &sem);
        if (ret >= 0) {
@@ -369,6 +373,7 @@ int poll(FAR struct pollfd *fds, nfds_t nfds, int timeout)
        }
 
        sem_destroy(&sem);
+       leave_cancellation_point();
 
        /* Check for errors */
 
index 4b20441..126e9c9 100644 (file)
@@ -60,6 +60,7 @@
 #include <unistd.h>
 #include <errno.h>
 
+#include <tinyara/cancelpt.h>
 #include <tinyara/fs/fs.h>
 
 /****************************************************************************
@@ -157,6 +158,10 @@ ssize_t file_pread(FAR struct file *filep, FAR void *buf, size_t nbytes, off_t o
 ssize_t pread(int fd, FAR void *buf, size_t nbytes, off_t offset)
 {
        FAR struct file *filep;
+       ssize_t ret;
+
+       /* pread() is a cancellation point */
+       (void)enter_cancellation_point();
 
        /* Get the file structure corresponding to the file descriptor. */
 
@@ -164,10 +169,12 @@ ssize_t pread(int fd, FAR void *buf, size_t nbytes, off_t offset)
        if (!filep) {
                /* The errno value has already been set */
 
-               return (ssize_t)ERROR;
+               ret = (ssize_t)ERROR;
+       } else {
+               /* Let file_pread do the real work */
+               ret = file_pread(filep, buf, nbytes, offset);
        }
 
-       /* Let file_pread do the real work */
-
-       return file_pread(filep, buf, nbytes, offset);
+       leave_cancellation_point();
+       return ret;
 }
index d728a8f..2888dbf 100644 (file)
@@ -60,6 +60,7 @@
 #include <unistd.h>
 #include <errno.h>
 
+#include <tinyara/cancelpt.h>
 #include <tinyara/fs/fs.h>
 
 /****************************************************************************
@@ -155,6 +156,10 @@ ssize_t file_pwrite(FAR struct file *filep, FAR const void *buf, size_t nbytes,
 ssize_t pwrite(int fd, FAR const void *buf, size_t nbytes, off_t offset)
 {
        FAR struct file *filep;
+       ssize_t ret;
+
+       /* pwrite() is a cancellation point */
+       (void)enter_cancellation_point();
 
        /* Get the file structure corresponding to the file descriptor. */
 
@@ -162,10 +167,13 @@ ssize_t pwrite(int fd, FAR const void *buf, size_t nbytes, off_t offset)
        if (!filep) {
                /* The errno value has already been set */
 
-               return (ssize_t)ERROR;
-       }
+               ret = (ssize_t)ERROR;
+       } else {
+               /* Let file_pread do the real work */
 
-       /* Let file_pread do the real work */
+               ret = file_pwrite(filep, buf, nbytes, offset);
+       }
 
-       return file_pwrite(filep, buf, nbytes, offset);
+       leave_cancellation_point();
+       return ret;
 }
index b0d6949..88583ab 100644 (file)
@@ -62,6 +62,7 @@
 #include <fcntl.h>
 #include <sched.h>
 #include <errno.h>
+#include <tinyara/cancelpt.h>
 
 #include "inode/inode.h"
 
@@ -150,6 +151,11 @@ ssize_t file_read(FAR struct file *filep, FAR void *buf, size_t nbytes)
 
 ssize_t read(int fd, FAR void *buf, size_t nbytes)
 {
+       ssize_t ret;
+
+       /* read() is a cancellation point */
+       (void)enter_cancellation_point();
+
        /* Did we get a valid file descriptor? */
 
 #if CONFIG_NFILE_DESCRIPTORS > 0
@@ -157,16 +163,17 @@ ssize_t read(int fd, FAR void *buf, size_t nbytes)
 #endif
        {
                /* No.. If networking is enabled, read() is the same as recv() with
-                * the flags parameter set to zero.
+                * the flags parameter set to zero. Note that recv() sets
+                * the errno variables
                 */
 
 #if defined(CONFIG_NET) && CONFIG_NSOCKET_DESCRIPTORS > 0
-               return recv(fd, buf, nbytes, 0);
+               ret = recv(fd, buf, nbytes, 0);
 #else
                /* No networking... it is a bad descriptor in any event */
 
                set_errno(EBADF);
-               return ERROR;
+               ret = ERROR;
 #endif
        }
 #if CONFIG_NFILE_DESCRIPTORS > 0
@@ -174,19 +181,24 @@ ssize_t read(int fd, FAR void *buf, size_t nbytes)
                FAR struct file *filep;
 
                /* The descriptor is in a valid range to file descriptor... do the
-                * read.  First, get the file structure.
+                * read.  First, get the file structure. Note that on failure,
+                * fs_getfilep() will set the errno variable.
                 */
 
                filep = fs_getfilep(fd);
                if (!filep) {
                        /* The errno value has already been set */
 
-                       return ERROR;
-               }
+                       ret = ERROR;
+               } else {
 
-               /* Then let file_read do all of the work */
+                       /* Then let file_read do all of the work */
 
-               return file_read(filep, buf, nbytes);
+                       ret = file_read(filep, buf, nbytes);
+               }
        }
 #endif
+
+       leave_cancellation_point();
+       return ret;
 }
index 3eebb46..5ff728f 100644 (file)
@@ -66,6 +66,7 @@
 #include <debug.h>
 
 #include <tinyara/kmalloc.h>
+#include <tinyara/cancelpt.h>
 #include <tinyara/fs/fs.h>
 
 #include "inode/inode.h"
@@ -126,6 +127,9 @@ int select(int nfds, FAR fd_set *readfds, FAR fd_set *writefds, FAR fd_set *exce
        int ndx;
        int ret;
 
+       /* select() is a cancellation point */
+       (void)enter_cancellation_point();
+
        /* How many pollfd structures do we need to allocate? */
 
        /* Initialize the descriptor list for poll() */
@@ -146,6 +150,7 @@ int select(int nfds, FAR fd_set *readfds, FAR fd_set *writefds, FAR fd_set *exce
                pollset = (struct pollfd *)kmm_zalloc(npfds * sizeof(struct pollfd));
                if (!pollset) {
                        set_errno(ENOMEM);
+                       leave_cancellation_point();
                        return ERROR;
                }
        }
@@ -275,6 +280,7 @@ int select(int nfds, FAR fd_set *readfds, FAR fd_set *writefds, FAR fd_set *exce
                set_errno(errcode);
        }
 
+       leave_cancellation_point();
        return ret;
 }
 
index 71f78cb..366f8b4 100644 (file)
@@ -62,6 +62,7 @@
 #include <errno.h>
 #include <assert.h>
 
+#include <tinyara/cancelpt.h>
 #include <sys/socket.h>
 
 #include "inode/inode.h"
@@ -87,7 +88,7 @@
 ssize_t file_write(FAR struct file *filep, FAR const void *buf, size_t nbytes)
 {
        FAR struct inode *inode;
-       int ret;
+       ssize_t ret;
        int err;
 
        /* Was this file opened for write access? */
@@ -175,6 +176,10 @@ ssize_t write(int fd, FAR const void *buf, size_t nbytes)
 #if CONFIG_NFILE_DESCRIPTORS > 0
        FAR struct file *filep;
 #endif
+       ssize_t ret;
+
+       /* write() is a cancellation point */
+       (void)enter_cancellation_point();
 
        /* Did we get a valid file descriptor? */
 
@@ -185,26 +190,32 @@ ssize_t write(int fd, FAR const void *buf, size_t nbytes)
                /* Write to a socket descriptor is equivalent to send with flags == 0 */
 
 #if (defined(CONFIG_NET_TCP) || defined(CONFIG_NET_LWIP)) && CONFIG_NSOCKET_DESCRIPTORS > 0
-               return send(fd, buf, nbytes, 0);
+               ret = send(fd, buf, nbytes, 0);
 #else
                set_errno(EBADF);
-               return ERROR;
+               ret = ERROR;
 #endif
        }
 #if CONFIG_NFILE_DESCRIPTORS > 0
-       /* The descriptor is in the right range to be a file descriptor... write
-        * to the file.
-        */
-
-       filep = fs_getfilep(fd);
-       if (!filep) {
-               /* The errno value has already been set */
-
-               return ERROR;
+       else {
+               /* The descriptor is in the right range to be a file descriptor... write
+                * to the file. Note that fs_getfilep() will set the errno on failure.
+                */
+
+               filep = fs_getfilep(fd);
+               if (!filep) {
+                       /* The errno value has already been set */
+
+                       ret = ERROR;
+               } else {
+                       /* Perform the write operation using the file descriptor as an index.
+                        * Note that file_write() will set the errno on failure.
+                        */
+
+                       ret = file_write(filep, buf, nbytes);
+               }
        }
-
-       /* Perform the write operation using the file descriptor as an index */
-
-       return file_write(filep, buf, nbytes);
 #endif
+       leave_cancellation_point();
+       return ret;
 }
index dc78f5d..0ec26d0 100644 (file)
 
 #define PTHREAD_DEFAULT_PRIORITY      100
 
-/* Cancellation states returned by pthread_cancelstate() */
+/* Cancellation states used by pthread_setcancelstate() */
 
 #define PTHREAD_CANCEL_ENABLE         (0)
 #define PTHREAD_CANCEL_DISABLE        (1)
 
+/* Cancellation types used by pthread_setcanceltype() */
+#define PTHREAD_CANCEL_DEFERRED       (0)
+#define PTHREAD_CANCEL_ASYNCHRONOUS   (1)
+
 /* Thread return value when a pthread is canceled */
 
 #define PTHREAD_CANCELED              ((FAR void*)ERROR)
@@ -293,6 +297,12 @@ typedef struct pthread_barrier_s pthread_barrier_t;
 
 typedef bool pthread_once_t;
 
+#ifdef CONFIG_PTHREAD_CLEANUP
+/* This type describes the pthread cleanup callback (non-standard) */
+
+typedef CODE void (*pthread_cleanup_t)(FAR void *arg);
+#endif
+
 /* Forware references */
 
 struct sched_param;                    /* Defined in sched.h */
@@ -360,6 +370,8 @@ int pthread_cancel(pthread_t thread);
  */
 int pthread_setcancelstate(int state, FAR int *oldstate);
 
+int  pthread_setcanceltype(int type, FAR int *oldtype);
+
 /**
  * @cond
  * @internal
@@ -368,6 +380,13 @@ void pthread_testcancel(void);
 /**
  * @endcond
  */
+
+/* A thread may set up cleanup functions to execut when the thread exits or is canceled. */
+#ifdef CONFIG_PTHREAD_CLEANUP
+void pthread_cleanup_pop(int execute);
+void pthread_cleanup_push(pthread_cleanup_t routine, FAR void *arg);
+#endif
+
 /* A thread can await termination of another thread and retrieve the return
  * value of the thread.
  */
index 5bfa954..ae723e1 100644 (file)
 #define SCHED_SPORADIC 3               /* Not supported */
 #define SCHED_OTHER    4               /* Not supported */
 
+
+/* Cancellation definitions *****************************************************/
+/* Cancellation states used by task_setcancelstate() */
+#define TASK_CANCEL_ENABLE (0)
+#define TASK_CANCEL_DISABLE (1)
+/* Cancellation types used by task_setcanceltype() */
+#define TASK_CANCEL_DEFERRED (0)
+#define TASK_CANCEL_ASYNCHRONOUS (1)
+
 /* Pthread definitions **********************************************************/
 
 #define PTHREAD_KEYS_MAX CONFIG_NPTHREAD_KEYS
@@ -217,6 +226,10 @@ int task_delete(pid_t pid);
  */
 int task_restart(pid_t pid);
 
+int    task_setcancelstate(int state, FAR int *oldstate);
+int    task_setcanceltype(int type, FAR int *oldtype);
+void   task_testcancel(void);
+
 /* Task Scheduling Interfaces (based on POSIX APIs) */
 /**
  * @ingroup SCHED_KERNEL
diff --git a/os/include/tinyara/cancelpt.h b/os/include/tinyara/cancelpt.h
new file mode 100644 (file)
index 0000000..c27c8b3
--- /dev/null
@@ -0,0 +1,169 @@
+/****************************************************************************
+ *
+ * Copyright 2016 Samsung Electronics All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ ****************************************************************************/
+/****************************************************************************
+ * include/tinyara/cancelpt.h
+ * Definitions related to cancellation points
+ *
+ *   Copyright (C) 2016 Gregory Nutt. All rights reserved.
+ *   Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+#ifndef __INCLUDE_TINYARA_CANCELPT_H
+#define __INCLUDE_TINYARA_CANCELPT_H
+
+/****************************************************************************
+ * Cancellation Points.
+ *
+ * Cancellation points shall occur when a thread is executing the following
+ * functions:
+ *
+ * accept()          mq_timedsend()           putpmsg()       sigtimedwait()
+ * aio_suspend()     msgrcv()                 pwrite()        sigwait()
+ * clock_nanosleep() msgsnd()                 read()          sigwaitinfo()
+ * close()           msync()                  readv()         sleep()
+ * connect()         nanosleep()              recv()          system()
+ * creat()           open()                   recvfrom()      tcdrain()
+ * fcntl()           pause()                  recvmsg()       usleep()
+ * fdatasync()       poll()                   select()        wait()
+ * fsync()           pread()                  sem_timedwait() waitid()
+ * getmsg()          pselect()                sem_wait()      waitpid()
+ * getpmsg()         pthread_cond_timedwait() send()          write()
+ * lockf()           pthread_cond_wait()      sendmsg()       writev()
+ * mq_receive()      pthread_join()           sendto()
+ * mq_send()         pthread_testcancel()     sigpause()
+ * mq_timedreceive() putmsg()                 sigsuspend()
+ *
+ * Each of the above function must call enter_cancellation_point() on entry
+ * in order to establish the cancellation point and leave_cancellation_point()
+ * on exit.  These functions are described below.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <tinyara/config.h>
+
+#include <stdbool.h>
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+#ifdef __cplusplus
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+/****************************************************************************
+ * Name: enter_cancellation_point
+ *
+ * Description:
+ *   Called at the beginning of the cancellation point to establish the
+ *   cancellation point.  This function does the following:
+ *
+ *   1. If deferred cancellation does not apply to this thread, nothing is
+ *      done, otherwise, it
+ *   2. Sets state information in the caller's TCB and increments a nesting
+ *      count.
+ *   3. If this is the outermost nesting level, it checks if there is a
+ *      pending cancellation and, if so, calls either exit() or
+ *      pthread_exit(), depending upon the type of the thread.
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value
+ *   true is returned if a cancellation is pending but cannot be performed
+ *   now due to the nesting level.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_CANCELLATION_POINTS
+bool enter_cancellation_point(void);
+#else
+#  define enter_cancellation_point() false
+#endif
+
+/****************************************************************************
+ * Name: leave_cancellation_point
+ *
+ * Description:
+ *   Called at the end of the cancellation point.  This function does the
+ *   following:
+ *
+ *   1. If deferred cancellation does not apply to this thread, nothing is
+ *      done, otherwise, it
+ *   2. Clears state information in the caller's TCB and decrements a
+ *      nesting count.
+ *   3. If this is the outermost nesting level, it checks if there is a
+ *      pending cancellation and, if so, calls either exit() or
+ *      pthread_exit(), depending upon the type of the thread.
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value
+ *   None
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_CANCELLATION_POINTS
+void leave_cancellation_point(void);
+#else
+#  define leave_cancellation_point()
+#endif
+
+#undef EXTERN
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __INCLUDE_TINYARA_CANCELPT_H */
index 4f4392d..71923e0 100644 (file)
 #define TCB_FLAG_TTYPE_PTHREAD   (1 << TCB_FLAG_TTYPE_SHIFT)   /* User pthread */
 #define TCB_FLAG_TTYPE_KERNEL    (2 << TCB_FLAG_TTYPE_SHIFT)   /* Kernel thread */
 #define TCB_FLAG_NONCANCELABLE     (1 << 2)    /* Bit 2: Pthread is non-cancelable */
-#define TCB_FLAG_CANCEL_PENDING    (1 << 3)    /* Bit 3: Pthread cancel is pending */
-#define TCB_FLAG_ROUND_ROBIN       (1 << 4)    /* Bit 4: Round robin sched enabled */
-#define TCB_FLAG_EXIT_PROCESSING   (1 << 5)    /* Bit 5: Exitting */
+#define TCB_FLAG_CANCEL_DEFERRED   (1 << 3)    /* Bit 3: Deferred (vs asynch) cancellation type */
+#define TCB_FLAG_CANCEL_PENDING    (1 << 4)    /* Bit 4: Pthread cancel is pending */
+#define TCB_FLAG_POLICY_SHIFT      (5) /* Bit 5-6: Scheduling policy */
+ #define TCB_FLAG_POLICY_MASK       (3 << TCB_FLAG_POLICY_SHIFT)
+ #  define TCB_FLAG_SCHED_FIFO      (0 << TCB_FLAG_POLICY_SHIFT) /* FIFO scheding policy */
+ #  define TCB_FLAG_ROUND_ROBIN     (1 << TCB_FLAG_POLICY_SHIFT) /* Round robin scheding policy */
+ #  define TCB_FLAG_SCHED_SPORADIC  (2 << TCB_FLAG_POLICY_SHIFT) /* Sporadic scheding policy */
+ #  define TCB_FLAG_SCHED_OTHER     (3 << TCB_FLAG_POLICY_SHIFT) /* Other scheding policy */
+#define TCB_FLAG_CPU_LOCKED        (1 << 7) /* Bit 7: Locked to this CPU */
+#define TCB_FLAG_EXIT_PROCESSING   (1 << 8) /* Bit 8: Exitting */
+                                                                                       /* Bits 9-15: Available */
 
 /* Values for struct task_group tg_flags */
 
@@ -259,6 +267,16 @@ struct child_status_s {
 };
 #endif
 
+/* struct pthread_cleanup_s ******************************************************/
+/* This structure describes one element of the pthread cleanup stack */
+
+#ifdef CONFIG_PTHREAD_CLEANUP
+struct pthread_cleanup_s {
+       pthread_cleanup_t pc_cleaner;    /* Cleanup callback address */
+       FAR void *pc_arg;                /* Argument that accompanies the callback */
+};
+#endif
+
 /* struct dspace_s ***************************************************************/
 
 /** @brief This structure describes a reference counted D-Space region.  This must be a
@@ -493,6 +511,9 @@ struct tcb_s {
        uint8_t task_state;                     /* Current state of the thread         */
        uint16_t flags;                         /* Misc. general status flags          */
        int16_t lockcount;                      /* 0=preemptable (not-locked)          */
+#ifdef CONFIG_CANCELLATION_POINTS
+       int16_t cpcount;                        /* Nested cancellation point count     */
+#endif
 
 #if CONFIG_RR_INTERVAL > 0
        int timeslice;                          /* RR timeslice interval remaining     */
@@ -509,6 +530,10 @@ struct tcb_s {
        FAR void *adj_stack_ptr;        /* Adjusted stack_alloc_ptr for HW     */
        /* The initial stack pointer value     */
 
+#ifdef CONFIG_MPU_STACKGUARD
+       FAR void *stack_guard;          /* address of the stack guard */
+       size_t guard_size;              /* size of the guard region */
+#endif
        /* External Module Support *************************************************** */
 
 #ifdef CONFIG_PIC
@@ -604,6 +629,15 @@ struct pthread_tcb_s {
        pthread_addr_t arg;                     /* Startup argument                    */
        FAR void *joininfo;                     /* Detach-able info to support join    */
 
+#ifdef CONFIG_PTHREAD_CLEANUP
+       /* tos   - The index to the next avaiable entry at the top of the stack.
+        * stack - The pre-allocated clean-up stack memory.
+        */
+
+       uint8_t tos;
+       struct pthread_cleanup_s stack[CONFIG_PTHREAD_CLEANUP_STACKSIZE];
+#endif
+
        /* POSIX Thread Specific Data ************************************************ */
 
 #if CONFIG_NPTHREAD_KEYS > 0
index 2e02cce..11ce03b 100644 (file)
@@ -430,8 +430,37 @@ config NPTHREAD_KEYS
                The number of items of thread-
                specific data that can be retained
 
+config PTHREAD_CLEANUP
+       bool "pthread cleanup stack"
+       default n
+       ---help---
+               Select to enable support for pthread exit cleanup stacks.  This
+               enables the interfaces pthread_cleanup_push() and
+               pthread_cleanup_pop().
+
+config PTHREAD_CLEANUP_STACKSIZE
+       int "pthread cleanup stack size"
+       default 1
+       range 1 32
+       depends on PTHREAD_CLEANUP
+       ---help---
+               The maximum number of cleanup actions that may be pushed by
+               pthread_clean_push().  This setting will increase the size of EVERY
+               pthread task control block by about n * CONFIG_PTHREAD_CLEANUP_STACKSIZE
+               where n is the size of a pointer, 2* sizeof(uintptr_t), this would be
+               8 for a CPU with 32-bit addressing and 4 for a CPU with 16-bit
+               addressing.
+
 endmenu # Pthread Options
 
+config CANCELLATION_POINTS
+       bool "Cancellation points"
+       default n
+       ---help---
+               Enable POSIX cancellation points for pthread_cancel().  If selected,
+               cancellation points will also used with the () task_delete() API even if
+               pthreads are not enabled.
+
 menu "Performance Monitoring"
 
 config SCHED_CPULOAD
@@ -1013,6 +1042,9 @@ config PREAPP_STACKSIZE
                The size of the stack to allocate for the pre-application thread
                that is started as soon as the OS completes its initialization.
 
+config MPU_STACKGAURD
+       default n
+
 config PTHREAD_STACK_MIN
        int "Minimum pthread stack size"
        default 256
@@ -1025,3 +1057,9 @@ config PTHREAD_STACK_DEFAULT
        ---help---
                Default pthread stack size
 endmenu # Stack size information
+
+comment "Kernel Latency utility"
+source kernel/latency/Kconfig
+
+comment "Kernel Debug and Simulation"
+source kernel/debug/Kconfig
index 19a65e6..8eefef7 100644 (file)
@@ -66,6 +66,7 @@
 #include <debug.h>
 
 #include <tinyara/arch.h>
+#include <tinyara/cancelpt.h>
 
 #include "sched/sched.h"
 #include "mqueue/mqueue.h"
@@ -174,6 +175,19 @@ FAR struct mqueue_msg_s *mq_waitreceive(mqd_t mqdes)
        FAR struct mqueue_inode_s *msgq;
        FAR struct mqueue_msg_s *rcvmsg;
 
+       /* mq_waitreceive() is not a cancellation point, but it is always called
+        * from a cancellation point.
+        */
+
+       if (enter_cancellation_point()) {
+               /* If there is a pending cancellation, then do not perform
+                * the wait. Exit now with ECANCELED.
+                */
+               set_errno(ECANCELED);
+               leave_cancellation_point();
+               return NULL;
+       }
+
        /* Get a pointer to the message queue */
 
        msgq = mqdes->msgq;
@@ -222,6 +236,7 @@ FAR struct mqueue_msg_s *mq_waitreceive(mqd_t mqdes)
                msgq->nmsgs--;
        }
 
+       leave_cancellation_point();
        return rcvmsg;
 }
 
@@ -306,6 +321,5 @@ ssize_t mq_doreceive(mqd_t mqdes, FAR struct mqueue_msg_s *mqmsg, FAR char *ubuf
        }
 
        /* Return the length of the message transferred to the user buffer */
-
        return rcvmsglen;
 }
index b7ef6fa..579151c 100644 (file)
@@ -62,6 +62,7 @@
 #include <mqueue.h>
 #include <debug.h>
 #include <tinyara/arch.h>
+#include <tinyara/cancelpt.h>
 
 #include "mqueue/mqueue.h"
 
@@ -141,7 +142,11 @@ ssize_t mq_receive(mqd_t mqdes, FAR char *msg, size_t msglen, FAR int *prio)
         * errno appropriately.
         */
 
+       /* mq_receive() is a cancellation point */
+       (void)enter_cancellation_point();
+
        if (mq_verifyreceive(mqdes, msg, msglen) != OK) {
+               leave_cancellation_point();
                return ERROR;
        }
 
@@ -177,5 +182,6 @@ ssize_t mq_receive(mqd_t mqdes, FAR char *msg, size_t msglen, FAR int *prio)
        }
 
        sched_unlock();
+       leave_cancellation_point();
        return ret;
 }
index 0f5d982..34cc74f 100644 (file)
@@ -62,6 +62,7 @@
 #include  <debug.h>
 
 #include  <tinyara/arch.h>
+#include  <tinyara/cancelpt.h>
 
 #include  "mqueue/mqueue.h"
 
@@ -143,7 +144,11 @@ int mq_send(mqd_t mqdes, FAR const char *msg, size_t msglen, int prio)
         * on any failures to verify.
         */
 
+       /* mq_send() is a cancellation point */
+       (void)enter_cancellation_point();
+
        if (mq_verifysend(mqdes, msg, msglen, prio) != OK) {
+               leave_cancellation_point();
                return ERROR;
        }
 
@@ -190,5 +195,6 @@ int mq_send(mqd_t mqdes, FAR const char *msg, size_t msglen, int prio)
        }
 
        sched_unlock();
+       leave_cancellation_point();
        return ret;
 }
index e4d0cf0..1ac9b82 100644 (file)
@@ -68,6 +68,7 @@
 #include <tinyara/kmalloc.h>
 #include <tinyara/arch.h>
 #include <tinyara/sched.h>
+#include <tinyara/cancelpt.h>
 #include "sched/sched.h"
 #ifndef CONFIG_DISABLE_SIGNALS
 #include "signal/signal.h"
@@ -252,6 +253,18 @@ int mq_waitsend(mqd_t mqdes)
        FAR struct tcb_s *rtcb;
        FAR struct mqueue_inode_s *msgq;
 
+       /* mq_waitsend() is not a cancellation point, but it is always called from
+        * a cancellation point.
+        */
+       if (enter_cancellation_point()) {
+               /* If there is a pending cancellation, then do not perform
+                * the wait. Exit now with ECANCELED.
+                */
+               set_errno(ECANCELED);
+               leave_cancellation_point();
+               return ERROR;
+       }
+
        /* Get a pointer to the message queue */
 
        msgq = mqdes->msgq;
@@ -267,6 +280,7 @@ int mq_waitsend(mqd_t mqdes)
                        /* No... We will return an error to the caller. */
 
                        set_errno(EAGAIN);
+                       leave_cancellation_point();
                        return ERROR;
                }
 
@@ -298,11 +312,13 @@ int mq_waitsend(mqd_t mqdes)
                                 */
 
                                if (get_errno() != OK) {
+                                       leave_cancellation_point();
                                        return ERROR;
                                }
                        }
                }
        }
+       leave_cancellation_point();
        return OK;
 }
 
index ff8ec3f..9f62b49 100644 (file)
@@ -66,6 +66,7 @@
 
 #include <tinyara/arch.h>
 #include <tinyara/wdog.h>
+#include <tinyara/cancelpt.h>
 
 #include "sched/sched.h"
 #include "clock/clock.h"
@@ -204,16 +205,21 @@ ssize_t mq_timedreceive(mqd_t mqdes, FAR char *msg, size_t msglen, FAR int *prio
 
        DEBUGASSERT(up_interrupt_context() == false && rtcb->waitdog == NULL);
 
+       /* mq_timedreceive() is not a cancellation point */
+       (void)enter_cancellation_point();
+
        /* Verify the input parameters and, in case of an error, set
         * errno appropriately.
         */
 
        if (mq_verifyreceive(mqdes, msg, msglen) != OK) {
+               leave_cancellation_point();
                return ERROR;
        }
 
        if (!abstime || abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) {
                set_errno(EINVAL);
+               leave_cancellation_point();
                return ERROR;
        }
 
@@ -225,6 +231,7 @@ ssize_t mq_timedreceive(mqd_t mqdes, FAR char *msg, size_t msglen, FAR int *prio
        rtcb->waitdog = wd_create();
        if (!rtcb->waitdog) {
                set_errno(EINVAL);
+               leave_cancellation_point();
                return ERROR;
        }
 
@@ -272,6 +279,7 @@ ssize_t mq_timedreceive(mqd_t mqdes, FAR char *msg, size_t msglen, FAR int *prio
                        sched_unlock();
                        wd_delete(rtcb->waitdog);
                        rtcb->waitdog = NULL;
+                       leave_cancellation_point();
                        return ERROR;
                }
 
@@ -309,5 +317,6 @@ ssize_t mq_timedreceive(mqd_t mqdes, FAR char *msg, size_t msglen, FAR int *prio
        sched_unlock();
        wd_delete(rtcb->waitdog);
        rtcb->waitdog = NULL;
+       leave_cancellation_point();
        return ret;
 }
index 4d2e710..49c3c36 100644 (file)
@@ -66,6 +66,7 @@
 
 #include <tinyara/arch.h>
 #include <tinyara/wdog.h>
+#include <tinyara/cancelpt.h>
 
 #include "clock/clock.h"
 #include "sched/sched.h"
@@ -206,16 +207,21 @@ int mq_timedsend(mqd_t mqdes, FAR const char *msg, size_t msglen, int prio, FAR
 
        DEBUGASSERT(up_interrupt_context() == false && rtcb->waitdog == NULL);
 
+       /* mq_timedsend() is a cancellation point */
+       (void)enter_cancellation_point();
+
        /* Verify the input parameters -- setting errno appropriately
         * on any failures to verify.
         */
 
        if (mq_verifysend(mqdes, msg, msglen, prio) != OK) {
+               leave_cancellation_point();
                return ERROR;
        }
 
        if (!abstime || abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) {
                set_errno(EINVAL);
+               leave_cancellation_point();
                return ERROR;
        }
 
@@ -231,6 +237,7 @@ int mq_timedsend(mqd_t mqdes, FAR const char *msg, size_t msglen, int prio, FAR
        rtcb->waitdog = wd_create();
        if (!rtcb->waitdog) {
                set_errno(EINVAL);
+               leave_cancellation_point();
                return ERROR;
        }
 
@@ -320,5 +327,6 @@ int mq_timedsend(mqd_t mqdes, FAR const char *msg, size_t msglen, int prio, FAR
        sched_unlock();
        wd_delete(rtcb->waitdog);
        rtcb->waitdog = NULL;
+       leave_cancellation_point();
        return ret;
 }
index 3729fab..22e787f 100644 (file)
@@ -68,6 +68,10 @@ ifneq ($(CONFIG_DISABLE_SIGNALS),y)
 CSRCS += pthread_condtimedwait.c pthread_kill.c pthread_sigmask.c
 endif
 
+ifeq ($(CONFIG_PTHREAD_CLEANUP),y)
+CSRCS += pthread_cleanup.c
+endif
+
 # Include pthread build support
 
 DEPPATH += --dep-path pthread
index 4d9e766..e17c643 100644 (file)
@@ -114,6 +114,9 @@ struct task_group_s;                        /* Forward reference */
 
 void weak_function pthread_initialize(void);
 int pthread_schedsetup(FAR struct pthread_tcb_s *tcb, int priority, start_t start, pthread_startroutine_t entry);
+#ifdef CONFIG_PTHREAD_CLEANUP
+void pthread_cleanup_popall(FAR struct pthread_tcb_s *tcb);
+#endif
 int pthread_completejoin(pid_t pid, FAR void *exit_value);
 void pthread_destroyjoin(FAR struct task_group_s *group, FAR struct join_s *pjoin);
 FAR struct join_s *pthread_findjoininfo(FAR struct task_group_s *group, pid_t pid);
index 4128349..240f2b4 100644 (file)
@@ -62,6 +62,7 @@
 #include <errno.h>
 
 #include "sched/sched.h"
+#include "task/task.h"
 #include "pthread/pthread.h"
 
 /**************************************************************************
 
 int pthread_cancel(pthread_t thread)
 {
-       struct tcb_s *tcb;
+       struct pthread_tcb_s *tcb;
 
        /* First, make sure that the handle references a valid thread */
 
-       if (!thread) {
+       if (thread == 0) {
                /* pid == 0 is the IDLE task.  Callers cannot cancel the
                 * IDLE task.
                 */
-
                return ESRCH;
        }
 
-       tcb = sched_gettcb((pid_t)thread);
+       tcb = (FAR struct pthread_tcb_s *)sched_gettcb((pid_t)thread);
        if (!tcb) {
                /* The pid does not correspond to any known thread.  The thread
                 * has probably already exited.
                 */
-
                return ESRCH;
        }
 
@@ -121,7 +120,7 @@ int pthread_cancel(pthread_t thread)
         */
 
        sched_lock();
-       if ((tcb->flags & TCB_FLAG_NONCANCELABLE) != 0) {
+       if ((tcb->cmn.flags & TCB_FLAG_NONCANCELABLE) != 0) {
                /* Then we cannot cancel the thread now.  Here is how this is
                 * supposed to work:
                 *
@@ -135,10 +134,31 @@ int pthread_cancel(pthread_t thread)
                 *  processing."
                 */
 
-               tcb->flags |= TCB_FLAG_CANCEL_PENDING;
+               tcb->cmn.flags |= TCB_FLAG_CANCEL_PENDING;
+               sched_unlock();
+               return OK;
+       }
+
+#ifdef CONFIG_CANCELLATION_POINTS
+       /* Check if this thread supports deferred cancellation */
+
+       if ((tcb->cmn.flags & TCB_FLAG_CANCEL_DEFERRED) != 0) {
+               /* If the thread is waiting at a cancellation point, then notify of the
+                * cancellation thereby waking the task up with an ECANCELED error.
+                *
+                * REVISIT: is locking the scheduler sufficent in SMP mode?
+                */
+
+               tcb->cmn.flags |= TCB_FLAG_CANCEL_PENDING;
+
+               if (tcb->cmn.cpcount > 0) {
+                       notify_cancellation(&tcb->cmn);
+               }
+
                sched_unlock();
                return OK;
        }
+#endif
 
        sched_unlock();
 
@@ -146,16 +166,28 @@ int pthread_cancel(pthread_t thread)
         * same as pthread_exit(PTHREAD_CANCELED).
         */
 
-       if (tcb == (struct tcb_s *)g_readytorun.head) {
+       if (tcb == (struct pthread_tcb_s *)g_readytorun.head) {
                pthread_exit(PTHREAD_CANCELED);
        }
 
+#ifdef CONFIG_PTHREAD_CLEANUP
+               /* Perform any stack pthread clean-up callbacks.
+                *
+                * REVISIT: In this case, the clean-up callback will execute on the
+                * thread of the caller of pthread cancel, not on the thread of
+                * the thread-to-be-canceled.  Is that an issue?  Presumably they
+                * are both within the same group and within the same process address
+                * space.
+                */
+
+               pthread_cleanup_popall(tcb);
+#endif
+
        /* Complete pending join operations */
 
        (void)pthread_completejoin((pid_t)thread, PTHREAD_CANCELED);
 
-       /* Then let pthread_delete do the real work */
+       /* Then let task_terminate do the real work */
 
-       task_delete((pid_t)thread);
-       return OK;
+       return task_terminate((pid_t)thread, false);
 }
diff --git a/os/kernel/pthread/pthread_cleanup.c b/os/kernel/pthread/pthread_cleanup.c
new file mode 100644 (file)
index 0000000..95fc4de
--- /dev/null
@@ -0,0 +1,238 @@
+/****************************************************************************
+ *
+ * Copyright 2016 Samsung Electronics All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ ****************************************************************************/
+/****************************************************************************
+ * kernel/pthread/pthread_cleanup.c
+ *
+ *   Copyright (C) 2016 Gregory Nutt. All rights reserved.
+ *   Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <tinyara/config.h>
+
+#include <pthread.h>
+#include <sched.h>
+
+#include <tinyara/sched.h>
+
+#include "sched/sched.h"
+#include "pthread/pthread.h"
+
+#ifdef CONFIG_PTHREAD_CLEANUP
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: pthread_cleanup_pop_tcb
+ *
+ * Description:
+ *   The pthread_cleanup_pop_tcb() function will remove the routine at the top
+ *   of the calling thread's cancellation cleanup stack and optionally
+ *   invoke it (if 'execute' is non-zero).
+ *
+ * Input Parameters:
+ *   tcb - The TCB of the pthread that is exiting or being canceled.
+ *
+ * Return Value:
+ *   None
+ *
+ * Assumptions:
+ *   The scheduler is locked.
+ *
+ ****************************************************************************/
+
+static void pthread_cleanup_pop_tcb(FAR struct pthread_tcb_s *tcb, int execute)
+{
+       if (tcb->tos > 0) {
+               unsigned int ndx;
+
+               /* Get the index to the last cleaner function pushed onto the stack */
+
+               ndx = tcb->tos - 1;
+               DEBUGASSERT(ndx >= 0 && ndx < CONFIG_PTHREAD_CLEANUP_STACKSIZE);
+
+               /* Should we execute the cleanup routine at the top of the stack? */
+
+               if (execute != 0) {
+                       FAR struct pthread_cleanup_s *cb;
+
+                       /* Yes..  Execute the clean-up routine.
+                        *
+                        * REVISIT: This is a security problem In the PROTECTED and KERNEL
+                        * builds:  We must not call the registered function in supervisor
+                        * mode!  See also on_exit() and atexit() callbacks.
+                        */
+
+                       cb  = &tcb->stack[ndx];
+                       cb->pc_cleaner(cb->pc_arg);
+               }
+
+               tcb->tos = ndx;
+       }
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: pthread_cleanup_push
+ *       pthread_cleanup_pop
+ *
+ * Description:
+ *   The pthread_cleanup_pop() function will remove the routine at the top
+ *   of the calling thread's cancellation cleanup stack and optionally
+ *   invoke it (if 'execute' is non-zero).
+ *
+ *   The pthread_cleanup_push() function will push the specified cancellation
+ *   cleanup handler routine onto the calling thread's cancellation cleanup
+ *   stack. The cancellation cleanup handler will be popped from the
+ *   cancellation cleanup stack and invoked with the argument arg when:
+ *
+ *   - The thread exits (that is, calls pthread_exit()).
+ *   - The thread acts upon a cancellation request.
+ *   - The thread calls pthread_cleanup_pop() with a non-zero execute argument.
+ *
+ * Input Parameters:
+ *   routine - The cleanup routine to be pushed on the the cleanup stack.
+ *   arg     - An argument that will accompany the callback.
+ *   execute - Execute the popped cleanup function immediately.
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+void pthread_cleanup_pop(int execute)
+{
+       FAR struct pthread_tcb_s *tcb = (FAR struct pthread_tcb_s *)g_readytorun.head;
+
+       /* We don't assert if called from a non-pthread; we just don't do anything */
+
+       DEBUGASSERT(tcb != NULL);
+
+       /* sched_lock() should provide sufficient protection.  We only need to
+        * have this TCB stationary; the pthread cleanup stack should never be
+        * modified by interrupt level logic.
+        */
+
+       sched_lock();
+       if ((tcb->cmn.flags & TCB_FLAG_TTYPE_MASK) == TCB_FLAG_TTYPE_PTHREAD) {
+               pthread_cleanup_pop_tcb(tcb, execute);
+       }
+
+       sched_unlock();
+}
+
+void pthread_cleanup_push(pthread_cleanup_t routine, FAR void *arg)
+{
+       FAR struct pthread_tcb_s *tcb = (FAR struct pthread_tcb_s *)g_readytorun.head;
+
+       /* We don't assert if called from a non-pthread; we just don't do anything */
+
+       DEBUGASSERT(tcb != NULL);
+       DEBUGASSERT(tcb->tos < CONFIG_PTHREAD_CLEANUP_STACKSIZE);
+
+       /* sched_lock() should provide sufficient protection.  We only need to
+        * have this TCB stationary; the pthread cleanup stack should never be
+        * modified by interrupt level logic.
+        */
+
+       sched_lock();
+       if ((tcb->cmn.flags & TCB_FLAG_TTYPE_MASK) == TCB_FLAG_TTYPE_PTHREAD &&
+       tcb->tos < CONFIG_PTHREAD_CLEANUP_STACKSIZE) {
+               unsigned int ndx = tcb->tos;
+
+               tcb->tos++;
+               tcb->stack[ndx].pc_cleaner = routine;
+               tcb->stack[ndx].pc_arg = arg;
+       }
+
+       sched_unlock();
+}
+
+/****************************************************************************
+ * Name: pthread_cleanup_popall
+ *
+ * Description:
+ *   The pthread_cleanup_popall() is an internal function that will pop and
+ *   execute all clean-up functions.  This function is only called from within
+ *   the pthread_exit() and pthread_cancellation() logic
+ *
+ * Input Parameters:
+ *   tcb - The TCB of the pthread that is exiting or being canceled.
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+void pthread_cleanup_popall(FAR struct pthread_tcb_s *tcb)
+{
+       DEBUGASSERT(tcb != NULL);
+       DEBUGASSERT((tcb->cmn.flags & TCB_FLAG_TTYPE_MASK) == TCB_FLAG_TTYPE_PTHREAD);
+
+       /* Pop and execute each cleanup routine/
+        *
+        * sched_lock() should provide sufficient protection.  We only need to
+        * have this TCB stationary; the pthread cleanup stack should never be
+        * modified by interrupt level logic.
+        */
+
+       sched_lock();
+       while (tcb->tos > 0) {
+               pthread_cleanup_pop_tcb(tcb, 1);
+       }
+
+       sched_unlock();
+}
+
+#endif /* CONFIG_PTHREAD_CLEANUP */
index e4df029..42ffec8 100644 (file)
@@ -65,6 +65,7 @@
 #include <errno.h>
 #include <assert.h>
 #include <debug.h>
+#include <tinyara/cancelpt.h>
 
 #include <tinyara/wdog.h>
 
@@ -206,6 +207,9 @@ int pthread_cond_timedwait(FAR pthread_cond_t *cond, FAR pthread_mutex_t *mutex,
 
        DEBUGASSERT(rtcb->waitdog == NULL);
 
+       /* pthread_cond_timedwait() is a cancellation point */
+       (void)enter_cancellation_point();
+
        /* Make sure that non-NULL references were provided. */
 
        if (!cond || !mutex) {
@@ -343,5 +347,6 @@ int pthread_cond_timedwait(FAR pthread_cond_t *cond, FAR pthread_mutex_t *mutex,
        }
 
        svdbg("Returning %d\n", ret);
+       leave_cancellation_point();
        return ret;
 }
index 45b8579..af0f87e 100644 (file)
@@ -62,6 +62,7 @@
 #include <errno.h>
 #include <debug.h>
 
+#include <tinyara/cancelpt.h>
 #include "pthread/pthread.h"
 
 /****************************************************************************
@@ -110,6 +111,9 @@ int pthread_cond_wait(FAR pthread_cond_t *cond, FAR pthread_mutex_t *mutex)
 
        svdbg("cond=0x%p mutex=0x%p\n", cond, mutex);
 
+       /* pthread_cond_wait() is a cancellation point */
+       (void)enter_cancellation_point();
+
        /* Make sure that non-NULL references were provided. */
 
        if (!cond || !mutex) {
@@ -144,5 +148,6 @@ int pthread_cond_wait(FAR pthread_cond_t *cond, FAR pthread_mutex_t *mutex)
        }
 
        svdbg("Returning %d\n", ret);
+       leave_cancellation_point();
        return ret;
 }
index b000d24..a5a6159 100644 (file)
@@ -382,6 +382,10 @@ int pthread_create(FAR pthread_t *thread, FAR const pthread_attr_t *attr, pthrea
 #endif
        }
 
+#ifdef CONFIG_CANCELLATION_POINTS
+       /* Set the deferred cancellation types */
+       ptcb->cmn.flags |= TCB_FLAG_CANCEL_DEFERRED;
+#endif
        /* Get the assigned pid before we start the task (who knows what
         * could happen to ptcb after this!).  Copy this ID into the join structure
         * as well.
@@ -432,7 +436,6 @@ int pthread_create(FAR pthread_t *thread, FAR const pthread_attr_t *attr, pthrea
                errcode = EIO;
                goto errout_with_join;
        }
-
        return ret;
 
 errout_with_join:
index b9ba654..b2eb058 100644 (file)
@@ -128,6 +128,21 @@ void pthread_exit(FAR void *exit_value)
        }
 #endif
 
+#ifdef CONFIG_CANCELLATION_POINTS
+       /* Mark the pthread as non-cancelable to avoid additional calls to
+        * pthread_exit() due to any cancellation point logic that might get
+        * kicked off by actions taken during pthread_exit processing.
+        */
+       tcb->flags |= TCB_FLAG_NONCANCELABLE;
+       tcb->flags &= ~TCB_FLAG_CANCEL_PENDING;
+       tcb->cpcount = 0;
+#endif
+
+#ifdef CONFIG_PTHREAD_CLEANUP
+       /* Perform any stack pthread clean-up callbacks */
+       pthread_cleanup_popall((FAR struct pthread_tcb_s *)tcb);
+#endif
+
        /* Complete pending join operations */
 
        status = pthread_completejoin(getpid(), exit_value);
index 497348e..9d4253c 100644 (file)
  * Included Files
  ****************************************************************************/
 
+#include <tinyara/config.h>
 #include <sys/types.h>
 #include <unistd.h>
 #include <pthread.h>
+#include <tinyara/cancelpt.h>
 #include <errno.h>
 #include <debug.h>
 
@@ -127,11 +129,15 @@ int pthread_join(pthread_t thread, FAR pthread_addr_t *pexit_value)
        svdbg("thread=%d group=%p\n", thread, group);
        DEBUGASSERT(group);
 
+       /* pthread_join() is a cancellation point */
+       (void)enter_cancellation_point();
+
        /* First make sure that this is not an attempt to join to
         * ourself.
         */
 
        if ((pid_t)thread == getpid()) {
+               leave_cancellation_point();
                return EDEADLK;
        }
 
@@ -256,5 +262,6 @@ int pthread_join(pthread_t thread, FAR pthread_addr_t *pexit_value)
        }
 
        svdbg("Returning %d\n", ret);
+       leave_cancellation_point();
        return ret;
 }
index 21457d3..78c095e 100644 (file)
 
 pid_t wait(FAR int *stat_loc)
 {
+       /* wait() is a cancellation point, but nothings needs to be done for this
+        * trivial case.
+        */
        return waitpid((pid_t)-1, stat_loc, 0);
 }
 
index 275e649..14d05c3 100644 (file)
@@ -61,6 +61,7 @@
 #include <errno.h>
 
 #include <tinyara/sched.h>
+#include <tinyara/cancelpt.h>
 
 #include "sched/sched.h"
 #include "group/group.h"
@@ -179,6 +180,9 @@ int waitid(idtype_t idtype, id_t id, FAR siginfo_t *info, int options)
        int err;
        int ret;
 
+       /* waitid() is a cancellation point */
+       (void)enter_cancellation_point();
+
        /* MISSING LOGIC:   If WNOHANG is provided in the options, then this function
         * should returned immediately.  However, there is no mechanism available now
         * know if the thread has child:  The children remember their parents (if
@@ -387,12 +391,14 @@ int waitid(idtype_t idtype, id_t id, FAR siginfo_t *info, int options)
                }
        }
 
+       leave_cancellation_point();
        sched_unlock();
        return OK;
 
 errout_with_errno:
        set_errno(err);
 errout:
+       leave_cancellation_point();
        sched_unlock();
        return ERROR;
 }
index e1ef3b2..252e250 100644 (file)
@@ -62,6 +62,7 @@
 #include <errno.h>
 
 #include <tinyara/sched.h>
+#include <tinyara/cancelpt.h>
 
 #include "sched/sched.h"
 #include "group/group.h"
@@ -207,11 +208,15 @@ pid_t waitpid(pid_t pid, int *stat_loc, int options)
 
        DEBUGASSERT(stat_loc);
 
+       /* waitpid() is a cancellation point */
+       (void)enter_cancellation_point();
+
        /* None of the options are supported */
 
 #ifdef CONFIG_DEBUG
        if (options != 0) {
                set_errno(ENOSYS);
+               leave_cancellation_point();
                return ERROR;
        }
 #endif
@@ -262,12 +267,14 @@ pid_t waitpid(pid_t pid, int *stat_loc, int options)
 
        /* On success, return the PID */
 
+       leave_cancellation_point();
        sched_unlock();
        return pid;
 
 errout_with_errno:
        set_errno(err);
 errout:
+       leave_cancellation_point();
        sched_unlock();
        return ERROR;
 }
@@ -301,11 +308,15 @@ pid_t waitpid(pid_t pid, int *stat_loc, int options)
 
        DEBUGASSERT(stat_loc);
 
+       /* waitpid() is a cancellation point */
+       (void)enter_cancellation_point();
+
        /* None of the options are supported */
 
 #ifdef CONFIG_DEBUG
        if (options != 0) {
                set_errno(ENOSYS);
+               leave_cancellation_point();
                return ERROR;
        }
 #endif
@@ -491,6 +502,7 @@ pid_t waitpid(pid_t pid, int *stat_loc, int options)
                }
        }
 
+       leave_cancellation_point();
        sched_unlock();
        return (int)pid;
 
@@ -498,6 +510,7 @@ errout_with_errno:
        set_errno(err);
 
 errout_with_lock:
+       leave_cancellation_point();
        sched_unlock();
        return ERROR;
 }
index 0a5b29c..30d6fa0 100644 (file)
@@ -65,6 +65,7 @@
 
 #include <tinyara/arch.h>
 #include <tinyara/wdog.h>
+#include <tinyara/cancelpt.h>
 
 #include "sched/sched.h"
 #include "clock/clock.h"
@@ -188,6 +189,9 @@ int sem_timedwait(FAR sem_t *sem, FAR const struct timespec *abstime)
 
        DEBUGASSERT(up_interrupt_context() == false && rtcb->waitdog == NULL);
 
+       /* sem_timedwait() is a cancellation point */
+       (void)enter_cancellation_point();
+
        /* Verify the input parameters and, in case of an error, set
         * errno appropriately.
         */
@@ -229,6 +233,7 @@ int sem_timedwait(FAR sem_t *sem, FAR const struct timespec *abstime)
                irqrestore(flags);
                wd_delete(rtcb->waitdog);
                rtcb->waitdog = NULL;
+               leave_cancellation_point();
                return OK;
        }
 
@@ -278,6 +283,7 @@ int sem_timedwait(FAR sem_t *sem, FAR const struct timespec *abstime)
        irqrestore(flags);
        wd_delete(rtcb->waitdog);
        rtcb->waitdog = NULL;
+       leave_cancellation_point();
 
        /* We are either returning success or an error detected by sem_wait()
         * or the timeout detected by sem_timeout().  The 'errno' value has
@@ -296,5 +302,6 @@ errout_disabled:
 
 errout:
        set_errno(err);
+       leave_cancellation_point();
        return ERROR;
 }
index 883b868..a42937e 100644 (file)
 #include <errno.h>
 #include <assert.h>
 #include <tinyara/arch.h>
+#include <tinyara/cancelpt.h>
 
 #include "sched/sched.h"
 #include "semaphore/semaphore.h"
 
+#if defined(CONFIG_TINYARA_DEBUG) && defined(CONFIG_SEMAPHORE_HISTORY)
+#include <tinyara/debug/tinyara_debug.h>
+#endif
+
 /****************************************************************************
  * Pre-processor Definitions
  ****************************************************************************/
@@ -119,18 +124,30 @@ int sem_wait(FAR sem_t *sem)
 
        /* This API should not be called from interrupt handlers */
 
-       DEBUGASSERT(up_interrupt_context() == false)
+       DEBUGASSERT(up_interrupt_context() == false);
 
        /* Assume any errors reported are due to invalid arguments. */
        set_errno(EINVAL);
 
-       if (sem) {
-               /* The following operations must be performed with interrupts
-                * disabled because sem_post() may be called from an interrupt
-                * handler.
+       /* The following operations must be performed with interrupts
+        * disabled because sem_post() may be called from an interrupt
+        * handler.
+        */
+       saved_state = irqsave();
+
+       /* sem_wait() is a cancellation point */
+       if (enter_cancellation_point()) {
+               /* If there is a pending cancellation, then do not perform
+                * the wait. Exit now with ECANCELED.
                 */
+               set_errno(ECANCELED);
+               leave_cancellation_point();
+               irqrestore(saved_state);
+               return ERROR;
+       }
 
-               saved_state = irqsave();
+       /* Make sure we were supplied with a valid semaphore */
+       if (sem) {
 
                /* Check if the lock is available */
 
@@ -140,6 +157,9 @@ int sem_wait(FAR sem_t *sem)
                        sem->semcount--;
                        sem_addholder(sem);
                        rtcb->waitsem = NULL;
+#if defined(CONFIG_TINYARA_DEBUG) && defined(CONFIG_SEMAPHORE_HISTORY)
+                       save_semaphore_history(sem, (void *)rtcb, SEM_AQUIRE);
+#endif
                        ret = OK;
                }
 
@@ -162,6 +182,10 @@ int sem_wait(FAR sem_t *sem)
 
                        rtcb->waitsem = sem;
 
+#if defined(CONFIG_TINYARA_DEBUG) && defined(CONFIG_SEMAPHORE_HISTORY)
+                       save_semaphore_history(sem, (void *)rtcb, SEM_WAITING);
+#endif
+
                        /* If priority inheritance is enabled, then check the priority of
                         * the holder of the semaphore.
                         */
@@ -212,12 +236,10 @@ int sem_wait(FAR sem_t *sem)
                        sched_unlock();
 #endif
                }
-
-               /* Interrupts may now be enabled. */
-
-               irqrestore(saved_state);
        }
 
+       leave_cancellation_point();
+       irqrestore(saved_state);
        return ret;
 }
 
@@ -253,18 +275,30 @@ int sem_wait_for_isr(FAR sem_t *sem)
 
        /* This API should not be called from interrupt handlers */
 
-       DEBUGASSERT(up_interrupt_context() == false)
+       DEBUGASSERT(up_interrupt_context() == false);
 
        /* Assume any errors reported are due to invalid arguments. */
        set_errno(EINVAL);
 
-       if (sem) {
-               /* The following operations must be performed with interrupts
-                * disabled because sem_post() may be called from an interrupt
-                * handler.
+
+       /* The following operations must be performed with interrupts
+        * disabled because sem_post() may be called from an interrupt
+        * handler.
+        */
+       saved_state = irqsave();
+
+       /* sem_wait() is a cancellation point */
+       if (enter_cancellation_point()) {
+               /* If there is a pending cancellation, then do not perform
+                * the wait. Exit now with ECANCELED.
                 */
+               set_errno(ECANCELED);
+               leave_cancellation_point();
+               irqrestore(saved_state);
+               return ERROR;
+       }
 
-               saved_state = irqsave();
+       if (sem) {
 
                /* Check if the lock is available */
 
@@ -273,6 +307,9 @@ int sem_wait_for_isr(FAR sem_t *sem)
 
                        sem->semcount--;
                        rtcb->waitsem = NULL;
+#if defined(CONFIG_TINYARA_DEBUG) && defined(CONFIG_SEMAPHORE_HISTORY)
+                       save_semaphore_history(sem, (void *)rtcb, SEM_AQUIRE);
+#endif
                        ret = OK;
                }
 
@@ -295,6 +332,10 @@ int sem_wait_for_isr(FAR sem_t *sem)
 
                        rtcb->waitsem = sem;
 
+#if defined(CONFIG_TINYARA_DEBUG) && defined(CONFIG_SEMAPHORE_HISTORY)
+                       save_semaphore_history(sem, (void *)rtcb, SEM_WAITING);
+#endif
+
                        /* Add the TCB to the prioritized semaphore wait queue */
                        set_errno(0);
 
@@ -326,9 +367,10 @@ int sem_wait_for_isr(FAR sem_t *sem)
                }
 
                /* Interrupts may now be enabled. */
-
-               irqrestore(saved_state);
        }
 
+       leave_cancellation_point();
+       irqrestore(saved_state);
+
        return ret;
 }
index 7636eed..b706044 100644 (file)
@@ -63,6 +63,7 @@
 
 #include <tinyara/clock.h>
 #include <arch/irq.h>
+#include <tinyara/cancelpt.h>
 
 #include "clock/clock.h"
 
@@ -149,6 +150,9 @@ int nanosleep(FAR const struct timespec *rqtp, FAR struct timespec *rmtp)
        int ret;
 #endif
 
+       /* nanosleep() is a cancellation point */
+       (void)enter_cancellation_point();
+
        if (!rqtp || rqtp->tv_nsec < 0 || rqtp->tv_nsec >= 1000000000) {
                errval = EINVAL;
                goto errout;
@@ -189,6 +193,7 @@ int nanosleep(FAR const struct timespec *rqtp, FAR struct timespec *rmtp)
                /* The timeout "error" is the normal, successful result */
 
                irqrestore(flags);
+               leave_cancellation_point();
                return OK;
        }
 
@@ -229,5 +234,6 @@ int nanosleep(FAR const struct timespec *rqtp, FAR struct timespec *rmtp)
 
 errout:
        set_errno(errval);
+       leave_cancellation_point();
        return ERROR;
 }
index f7eb12d..64cb4f0 100644 (file)
@@ -59,6 +59,8 @@
 #include <unistd.h>
 #include <signal.h>
 
+#include <tinyara/cancelpt.h>
+
 /****************************************************************************
  * Preprocessor Definitions
  ****************************************************************************/
@@ -111,6 +113,10 @@ int pause(void)
 {
        sigset_t set;
        struct siginfo value;
+       int ret;
+
+       /* pause() is a cancellation point */
+       (void)enter_cancellation_point();
 
        /* Set up for the sleep.  Using the empty set means that we are not
         * waiting for any particular signal.  However, any unmasked signal
@@ -123,5 +129,7 @@ int pause(void)
         * meaning that some unblocked signal was caught.
         */
 
-       return sigwaitinfo(&set, &value);
+       ret = sigwaitinfo(&set, &value);
+       leave_cancellation_point();
+       return ret;
 }
index 2c857c2..a0b0633 100644 (file)
@@ -62,6 +62,7 @@
 #include <sched.h>
 
 #include <tinyara/arch.h>
+#include <tinyara/cancelpt.h>
 
 #include "sched/sched.h"
 #include "signal/signal.h"
@@ -134,6 +135,9 @@ int sigsuspend(FAR const sigset_t *set)
        irqstate_t saved_state;
        int unblocksigno;
 
+       /* sigsuspend() is a cancellation point */
+       (void)enter_cancellation_point();
+
        /* Several operations must be performed below:  We must determine if any
         * signal is pending and, if not, wait for the signal.  Since signals can
         * be posted from the interrupt level, there is a race condition that
@@ -187,5 +191,6 @@ int sigsuspend(FAR const sigset_t *set)
        }
 
        sched_unlock();
+       leave_cancellation_point();
        return ERROR;
 }
index 0f2b689..fe01e3f 100644 (file)
@@ -68,6 +68,7 @@
 
 #include <tinyara/arch.h>
 #include <tinyara/wdog.h>
+#include <tinyara/cancelpt.h>
 
 #include "sched/sched.h"
 #include "signal/signal.h"
@@ -197,6 +198,9 @@ int sigtimedwait(FAR const sigset_t *set, FAR struct siginfo *info, FAR const st
 
        DEBUGASSERT(rtcb->waitdog == NULL);
 
+       /* sigtimedwait() is a cancellation point */
+       (void)enter_cancellation_point();
+
        sched_lock();                           /* Not necessary */
 
        /* Several operations must be performed below:  We must determine if any
@@ -350,5 +354,6 @@ int sigtimedwait(FAR const sigset_t *set, FAR struct siginfo *info, FAR const st
        }
 
        sched_unlock();
+       leave_cancellation_point();
        return ret;
 }
index 99bbb46..4346274 100644 (file)
@@ -56,6 +56,7 @@
 
 #include <tinyara/config.h>
 #include <signal.h>
+#include <tinyara/cancelpt.h>
 
 /****************************************************************************
  * Definitions
 
 int sigwaitinfo(FAR const sigset_t *set, FAR struct siginfo *info)
 {
-       return sigtimedwait(set, info, NULL);
+       int ret;
+
+       /* sigwaitinfo() is a cancellation point */
+       (void)enter_cancellation_point();
+
+       ret = sigtimedwait(set, info, NULL);
+       leave_cancellation_point();
+       return ret;
 }
index cba28ab..f85ee78 100644 (file)
@@ -54,7 +54,7 @@ CSRCS += task_create.c task_init.c task_setup.c task_activate.c
 CSRCS += task_start.c task_delete.c task_exit.c task_exithook.c
 CSRCS += task_recover.c task_restart.c task_spawnparms.c
 CSRCS += task_terminate.c task_getgroup.c task_prctl.c task_getpid.c
-CSRCS += exit.c
+CSRCS += exit.c task_setcancelstate.c
 
 ifeq ($(CONFIG_ARCH_HAVE_VFORK),y)
 ifeq ($(CONFIG_SCHED_WAITPID),y)
@@ -78,6 +78,10 @@ ifeq ($(CONFIG_SCHED_ONEXIT),y)
 CSRCS += task_onexit.c
 endif
 
+ifeq ($(CONFIG_CANCELLATION_POINTS),y)
+CSRCS += task_setcanceltype.c task_testcancel.c task_cancelpt.c
+endif
+
 # Include task build support
 
 DEPPATH += --dep-path task
index b23dc90..685b63c 100644 (file)
@@ -97,4 +97,8 @@ void task_recover(FAR struct tcb_s *tcb);
 
 bool sched_addreadytorun(FAR struct tcb_s *rtrtcb);
 
+#ifdef CONFIG_CANCELLATION_POINTS
+void notify_cancellation(FAR struct tcb_s *tcb);
+#endif
+
 #endif                                                 /* __SCHED_TASK_TASK_H */
diff --git a/os/kernel/task/task_cancelpt.c b/os/kernel/task/task_cancelpt.c
new file mode 100644 (file)
index 0000000..f6feba0
--- /dev/null
@@ -0,0 +1,326 @@
+/****************************************************************************
+ *
+ * Copyright 2016 Samsung Electronics All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ ****************************************************************************/
+/****************************************************************************
+ * kernel/task/task_cancelpt.c
+ *
+ *   Copyright (C) 2016 Gregory Nutt. All rights reserved.
+ *   Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Cancellation Points.
+ *
+ * Cancellation points shall occur when a thread is executing the following
+ * functions:
+ *
+ * accept()          mq_timedsend()           putpmsg()       sigtimedwait()
+ * aio_suspend()     msgrcv()                 pwrite()        sigwait()
+ * clock_nanosleep() msgsnd()                 read()          sigwaitinfo()
+ * close()           msync()                  readv()         sleep()
+ * connect()         nanosleep()              recv()          system()
+ * creat()           open()                   recvfrom()      tcdrain()
+ * fcntl()           pause()                  recvmsg()       usleep()
+ * fdatasync()       poll()                   select()        wait()
+ * fsync()           pread()                  sem_timedwait() waitid()
+ * getmsg()          pselect()                sem_wait()      waitpid()
+ * getpmsg()         pthread_cond_timedwait() send()          write()
+ * lockf()           pthread_cond_wait()      sendmsg()       writev()
+ * mq_receive()      pthread_join()           sendto()
+ * mq_send()         pthread_testcancel()     sigpause()
+ * mq_timedreceive() putmsg()                 sigsuspend()
+ *
+ * Each of the above function must call enter_cancellation_point() on entry
+ * in order to establish the cancellation point and leave_cancellation_point()
+ * on exit.  These functions are described below.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <tinyara/config.h>
+
+#include <sched.h>
+#include <errno.h>
+
+#include <tinyara/irq.h>
+#include <tinyara/cancelpt.h>
+
+#include "sched/sched.h"
+#include "semaphore/semaphore.h"
+#include "mqueue/mqueue.h"
+#include "task/task.h"
+
+#ifdef CONFIG_CANCELLATION_POINTS
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: enter_cancellation_point
+ *
+ * Description:
+ *   Called at the beginning of the cancellation point to establish the
+ *   cancellation point.  This function does the following:
+ *
+ *   1. If deferred cancellation does not apply to this thread, nothing is
+ *      done, otherwise, it
+ *   2. Sets state information in the caller's TCB and increments a nesting
+ *      count.
+ *   3. If this is the outermost nesting level, it checks if there is a
+ *      pending cancellation and, if so, calls either exit() or
+ *      pthread_exit(), depending upon the type of the thread.
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value
+ *   true is returned if a cancellation is pending but cannot be performed
+ *   now due to the nesting level.
+ *
+ ****************************************************************************/
+
+bool enter_cancellation_point(void)
+{
+       FAR struct tcb_s *tcb = (FAR struct tcb_s *)g_readytorun.head;
+       bool ret = false;
+
+       /* Disabling pre-emption should provide sufficient protection.  We only
+        * need the TCB to be stationary (no interrupt level modification is
+        * anticipated).
+        *
+        * REVISIT: is locking the scheduler sufficent in SMP mode?
+        */
+
+       sched_lock();
+
+       /* If cancellation is disabled on this thread or if this thread is using
+        * asynchronous cancellation, then do nothing.
+        *
+        * Special case: if the cpcount count is greater than zero, then we are
+        * nested and the above condition was certainly true at the outermost
+        * nesting level.
+        */
+
+       if (((tcb->flags & TCB_FLAG_NONCANCELABLE) == 0 &&
+       (tcb->flags & TCB_FLAG_CANCEL_DEFERRED) != 0) ||
+       tcb->cpcount > 0) {
+               /* Check if there is a pending cancellation */
+
+               if ((tcb->flags & TCB_FLAG_CANCEL_PENDING) != 0) {
+                       /* Yes... return true (if we don't exit here) */
+
+                       ret = true;
+
+                       /* If there is a pending cancellation and we are at the outermost
+                        * nesting level of cancellation function calls, then exit
+                        * according to the type of the thread.
+                        */
+
+                       if (tcb->cpcount == 0) {
+#ifndef CONFIG_DISABLE_PTHREAD
+                               if ((tcb->flags & TCB_FLAG_TTYPE_MASK) == TCB_FLAG_TTYPE_PTHREAD) {
+                                       pthread_exit(PTHREAD_CANCELED);
+                               } else
+#endif
+                               {
+                                       exit(EXIT_FAILURE);
+                               }
+                       }
+               }
+
+               /* Otherwise, indicate that we are at a cancellation point by
+                * incrementing the nesting level of the cancellation point
+                * functions.
+                */
+
+               DEBUGASSERT(tcb->cpcount < INT16_MAX);
+               tcb->cpcount++;
+       }
+
+       sched_unlock();
+       return ret;
+}
+
+/****************************************************************************
+ * Name: leave_cancellation_point
+ *
+ * Description:
+ *   Called at the end of the cancellation point.  This function does the
+ *   following:
+ *
+ *   1. If deferred cancellation does not apply to this thread, nothing is
+ *      done, otherwise, it
+ *   2. Clears state information in the caller's TCB and decrements a
+ *      nesting count.
+ *   3. If this is the outermost nesting level, it checks if there is a
+ *      pending cancellation and, if so, calls either exit() or
+ *      pthread_exit(), depending upon the type of the thread.
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value
+ *   None
+ *
+ ****************************************************************************/
+
+void leave_cancellation_point(void)
+{
+       FAR struct tcb_s *tcb = (FAR struct tcb_s *)g_readytorun.head;
+
+       /* Disabling pre-emption should provide sufficient protection.  We only
+        * need the TCB to be stationary (no interrupt level modification is
+        * anticipated).
+        *
+        * REVISIT: is locking the scheduler sufficent in SMP mode?
+        */
+
+       sched_lock();
+
+       /* If cancellation is disabled on this thread or if this thread is using
+        * asynchronous cancellation, then do nothing.  Here we check only the
+        * nesting level: if the cpcount count is greater than zero, then the
+        * required condition was certainly true at the outermost nesting level.
+        */
+
+       if (tcb->cpcount > 0) {
+               /* Decrement the nesting level.  If if would decrement to zero, then
+                * we are at the outermost nesting level and may need to do more.
+                */
+
+               if (tcb->cpcount == 1) {
+                       /* We are no longer at the cancellation point */
+
+                       tcb->cpcount = 0;
+
+                       /* If there is a pending cancellation then just exit according to
+                        * the type of the thread.
+                        */
+
+                       if ((tcb->flags & TCB_FLAG_CANCEL_PENDING) != 0) {
+#ifndef CONFIG_DISABLE_PTHREAD
+                               if ((tcb->flags & TCB_FLAG_TTYPE_MASK) == TCB_FLAG_TTYPE_PTHREAD) {
+                                       pthread_exit(PTHREAD_CANCELED);
+                               } else
+#endif
+                               {
+                                       exit(EXIT_FAILURE);
+                               }
+                       }
+               } else {
+                       /* We are not at the outermost nesting level.  Just decrment the
+                       * nesting level count.
+                       */
+
+                       tcb->cpcount--;
+               }
+       }
+
+       sched_unlock();
+}
+
+/****************************************************************************
+ * Name: notify_cancellation
+ *
+ * Description:
+ *   Called by task_delete() or pthread_cancel() if the cancellation occurs
+ *   while we the thread is within the cancellation point.  This logic
+ *   behaves much like sending a signal:  It will cause waiting threads
+ *   to wake up and terminated with ECANCELED.  A call to
+ *   leave_cancellation_point() whould then follow, causing the thread to
+ *   exit.
+ *
+ ****************************************************************************/
+
+void notify_cancellation(FAR struct tcb_s *tcb)
+{
+       irqstate_t flags;
+
+       /* We need perform the following operations from within a critical section
+        * because it can compete with interrupt level activity.
+        */
+
+       flags = irqsave();
+
+       /* Make sure that the cancellation pending indication is set. */
+
+       tcb->flags |= TCB_FLAG_CANCEL_PENDING;
+
+       /* We only notify the cancellation if (1) the thread has not disabled
+        * cancellation, (2) the thread uses the deffered cancellation mode,
+        * (3) the thread is waiting within a cancellation point.
+        */
+
+       if (((tcb->flags & TCB_FLAG_NONCANCELABLE) == 0 &&
+       (tcb->flags & TCB_FLAG_CANCEL_DEFERRED) != 0) ||
+       tcb->cpcount > 0) {
+               /* If the thread is blocked waiting for a semaphore, then the thread
+                * must be unblocked to handle the cancellation.
+                */
+
+               if (tcb->task_state == TSTATE_WAIT_SEM) {
+                       sem_waitirq(tcb, ECANCELED);
+               }
+
+               /* If the thread is blocked waiting on a message queue, then the
+                * thread must be unblocked to handle the cancellation.
+                */
+
+#ifndef CONFIG_DISABLE_MQUEUE
+               if (tcb->task_state == TSTATE_WAIT_MQNOTEMPTY ||
+               tcb->task_state == TSTATE_WAIT_MQNOTFULL) {
+                       mq_waitirq(tcb, ECANCELED);
+               }
+#endif
+       }
+
+       irqrestore(flags);
+}
+
+#endif /* CONFIG_CANCELLATION_POINTS */
index 8e73b8c..68b9980 100644 (file)
@@ -57,6 +57,7 @@
 #include <tinyara/config.h>
 
 #include <stdlib.h>
+#include <errno.h>
 
 #include <tinyara/sched.h>
 
  *   redirected to exit().  This can only happen if a task calls task_delete()
  *   in order to delete itself.
  *
- *   In fact, this function (and task_terminate) are the final functions
- *   called all task termination sequences.  task_delete may be called
- *   from:
- *
- *   - task_restart(),
- *   - pthread_cancel(),
- *   - and directly from user code.
- *
- *   Other exit paths (exit(), _eixt(), and pthread_exit()) will go through
- *   task_terminate()
+ *   This function obeys the semantics of pthread cancellation: task
+ *  deletion is deferred if cancellation is disabled or if deferred
+ *  cancellation is supported (with cancellation points enabled).
  *
  * Inputs:
  *   pid - The task ID of the task to delete.  A pid of zero
  *         signifies the calling task.
  *
  * Return Value:
- *   OK on success; or ERROR on failure
- *
- *   This function can fail if the provided pid does not correspond to a
- *   task (errno is not set)
+ *  OK on success; or ERROR on failure with the errno variable set
+ *  appropriately.
  *
  ****************************************************************************/
 
 int task_delete(pid_t pid)
 {
+       FAR struct tcb_s *dtcb;
        FAR struct tcb_s *rtcb;
+       int ret;
 
-       /* Check if the task to delete is the calling task */
+       /* Check if the task to delete is the calling task:  PID=0 means to delete
+        * the calling task.  In this case, task_delete() is much like exit()
+        * except that it obeys the cancellation semantics.
+        */
 
        rtcb = (FAR struct tcb_s *)g_readytorun.head;
-       if (pid == 0 || pid == rtcb->pid) {
-               /* If it is, then what we really wanted to do was exit. Note that we
-                * don't bother to unlock the TCB since it will be going away.
+       if (pid == 0) {
+               pid = rtcb->pid;
+       }
+
+       /* Get the TCB of the task to be deleted */
+
+       dtcb = (FAR struct tcb_s *)sched_gettcb(pid);
+       if (dtcb == NULL) {
+       /* The pid does not correspond to any known thread.  The task
+        * has probably already exited.
+        */
+
+       set_errno(ESRCH);
+       return ERROR;
+       }
+
+       /* Only tasks and kernel threads should use this interface */
+
+       DEBUGASSERT((dtcb->flags & TCB_FLAG_TTYPE_MASK) != TCB_FLAG_TTYPE_PTHREAD);
+
+       /* Check to see if this task has the non-cancelable bit set in its
+        * flags. Suppress context changes for a bit so that the flags are stable.
+        * (the flags should not change in interrupt handling).
+        */
+
+       sched_lock();
+       if ((dtcb->flags & TCB_FLAG_NONCANCELABLE) != 0) {
+               /* Then we cannot cancel the thread now.  Here is how this is
+                * supposed to work:
+                *
+                * "When cancelability is disabled, all cancels are held pending
+                *  in the target thread until the thread changes the cancelability.
+                *  When cancelability is deferred, all cancels are held pending in
+                *  the target thread until the thread changes the cancelability, calls
+                *  a function which is a cancellation point or calls pthread_testcancel(),
+                *  thus creating a cancellation point. When cancelability is asynchronous,
+                *  all cancels are acted upon immediately, interrupting the thread with its
+                *  processing."
                 */
 
-               exit(EXIT_SUCCESS);
+               dtcb->flags |= TCB_FLAG_CANCEL_PENDING;
+               sched_unlock();
+               return OK;
        }
 
-       /* Then let task_terminate do the heavy lifting */
+#ifdef CONFIG_CANCELLATION_POINTS
+       /* Check if this task supports deferred cancellation */
+
+       if ((dtcb->flags & TCB_FLAG_CANCEL_DEFERRED) != 0) {
+
+               /* If the task is waiting at a cancellation point, then notify of the
+                * cancellation thereby waking the task up with an ECANCELED error.
+                *
+                * REVISIT: is locking the scheduler sufficent in SMP mode?
+                */
+
+               dtcb->flags |= TCB_FLAG_CANCEL_PENDING;
+
+               if (dtcb->cpcount > 0) {
+                       notify_cancellation(dtcb);
+               }
+
+               sched_unlock();
+               return OK;
+       }
+#endif
+
+       /* Check if the task to delete is the calling task */
+
+       sched_unlock();
+       if (pid == rtcb->pid) {
+       /* If it is, then what we really wanted to do was exit. Note that we
+        * don't bother to unlock the TCB since it will be going away.
+        */
+
+       exit(EXIT_SUCCESS);
+       }
+
+       /* Otherwise, perform the asynchronous cancellation, letting
+        * task_terminate() do all of the heavy lifting.
+        */
+
+       ret = task_terminate(pid, false);
+       if (ret < 0) {
+               set_errno(-ret);
+               return ERROR;
+       }
 
-       return task_terminate(pid, false);
+       return OK;
 }
index 86c56b2..5aeb719 100644 (file)
@@ -607,6 +607,17 @@ void task_exithook(FAR struct tcb_s *tcb, int status, bool nonblocking)
        if ((tcb->flags & TCB_FLAG_EXIT_PROCESSING) != 0) {
                return;
        }
+
+#ifdef CONFIG_CANCELLATION_POINTS
+       /* Mark the task as non-cancelable to avoid additional calls to exit()
+        * due to any cancellation point logic that might get kicked off by
+        * actions taken during exit processing.
+        */
+       tcb->flags |= TCB_FLAG_NONCANCELABLE;
+       tcb->flags &= ~TCB_FLAG_CANCEL_PENDING;
+       tcb->cpcount = 0;
+#endif
+
 #if defined(CONFIG_SCHED_ATEXIT) || defined(CONFIG_SCHED_ONEXIT)
        /* If exit function(s) were registered, call them now before we do any un-
         * initialization.
index ffdc86b..f7086a8 100644 (file)
@@ -211,7 +211,7 @@ int task_restart(pid_t pid)
 
                status = task_activate((FAR struct tcb_s *)tcb);
                if (status != OK) {
-                       (void)task_delete(pid);
+                       (void)task_terminate(pid, true);
                        set_errno(-status);
                        return ERROR;
                }
diff --git a/os/kernel/task/task_setcancelstate.c b/os/kernel/task/task_setcancelstate.c
new file mode 100644 (file)
index 0000000..82bd6f6
--- /dev/null
@@ -0,0 +1,166 @@
+/****************************************************************************
+ *
+ * Copyright 2016 Samsung Electronics All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ ****************************************************************************/
+/****************************************************************************
+ * kernel/task/task_setcancelstate.c
+ *
+ *   Copyright (C) 2007, 2008, 2016 Gregory Nutt. All rights reserved.
+ *   Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <tinyara/config.h>
+
+#include <stdlib.h>
+#include <pthread.h>
+#include <sched.h>
+#include <errno.h>
+
+#include "sched/sched.h"
+#include "task/task.h"
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: task_setcancelstate
+ *
+ * Description:
+ *   The task_setcancelstate() function atomically both sets the calling
+ *   task's cancelability state to the indicated state and returns the
+ *   previous cancelability state at the location referenced by oldstate.
+ *   Legal values for state are TASK_CANCEL_ENABLE and TASK_CANCEL_DISABLE.
+ *
+ *   The cancelability state and type of any newly created tasks are
+ *   TASK_CANCEL_ENABLE and TASK_CANCEL_DEFERRED respectively.
+ *
+ * Input Parameters:
+ *   state    - the new cancellability state, either TASK_CANCEL_ENABLE or
+ *              TASK_CANCEL_DISABLE
+ *   oldstate - The location to return the old cancellability state.
+ *
+ * Returned Value:
+ *   Zero (OK) on success; ERROR is returned on any failure with the
+ *   errno value set appropriately.
+ *
+ ****************************************************************************/
+
+int task_setcancelstate(int state, FAR int *oldstate)
+{
+       FAR struct tcb_s *tcb = (FAR struct tcb_s *)g_readytorun.head;
+       int ret = OK;
+
+       /* Suppress context changes for a bit so that the flags are stable. (the
+        * flags should not change in interrupt handling).
+        */
+
+       sched_lock();
+
+       /* Return the current state if so requrested */
+
+       if (oldstate != NULL) {
+               if ((tcb->flags & TCB_FLAG_NONCANCELABLE) != 0) {
+                       *oldstate = TASK_CANCEL_DISABLE;
+               } else {
+                       *oldstate = TASK_CANCEL_ENABLE;
+               }
+       }
+
+       /* Set the new cancellation state */
+
+       if (state == TASK_CANCEL_ENABLE) {
+               /* Clear the non-cancelable flag */
+
+               tcb->flags &= ~TCB_FLAG_NONCANCELABLE;
+
+               /* Check if a cancellation was pending */
+
+               if ((tcb->flags & TCB_FLAG_CANCEL_PENDING) != 0) {
+#ifdef CONFIG_CANCELLATION_POINTS
+                       /* If we are using deferred cancellation? */
+
+                       if ((tcb->flags & TCB_FLAG_CANCEL_DEFERRED) != 0) {
+                       /* Yes.. If we are within a cancellation point, then
+                        * notify of the cancellation.
+                        */
+
+                               if (tcb->cpcount > 0) {
+                                       notify_cancellation(tcb);
+                               }
+                       } else
+#endif
+                       {
+                       /* No.. We are using asynchronous cancellation.  If the
+                        * cancellation was pending in this case, then just exit.
+                        */
+
+                       tcb->flags &= ~TCB_FLAG_CANCEL_PENDING;
+
+#ifndef CONFIG_DISABLE_PTHREAD
+                               if ((tcb->flags & TCB_FLAG_TTYPE_MASK) == TCB_FLAG_TTYPE_PTHREAD) {
+                                       pthread_exit(PTHREAD_CANCELED);
+                               } else
+#endif
+                               {
+                                       exit(EXIT_FAILURE);
+                               }
+                       }
+               }
+       } else if (state == TASK_CANCEL_DISABLE) {
+       /* Set the non-cancelable state */
+
+               tcb->flags |= TCB_FLAG_NONCANCELABLE;
+       } else {
+               set_errno(EINVAL);
+               ret = ERROR;
+       }
+
+       sched_unlock();
+       return ret;
+}
diff --git a/os/kernel/task/task_setcanceltype.c b/os/kernel/task/task_setcanceltype.c
new file mode 100644 (file)
index 0000000..6f7a1cc
--- /dev/null
@@ -0,0 +1,150 @@
+/****************************************************************************
+ *
+ * Copyright 2016 Samsung Electronics All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ ****************************************************************************/
+/****************************************************************************
+ * kernel/task/task_setcanceltype.c
+ *
+ *   Copyright (C) 2016 Gregory Nutt. All rights reserved.
+ *   Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <tinyara/config.h>
+
+#include <stdlib.h>
+#include <pthread.h>
+#include <sched.h>
+#include <errno.h>
+
+#include "sched/sched.h"
+#include "task/task.h"
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: task_setcancelstate
+ *
+ * Description:
+ *   The task_setcanceltype() function atomically both sets the calling
+ *   thread's cancelability type to the indicated type and returns the
+ *   previous cancelability type at the location referenced by oldtype
+ *   Legal values for type are TASK_CANCEL_DEFERRED and
+ *   TASK_CANCEL_ASYNCHRONOUS.
+ *
+ *   The cancelability state and type of any newly created threads,
+ *   including the thread in which main() was first invoked, are
+ *   TASK_CANCEL_ENABLE and TASK_CANCEL_DEFERRED respectively.
+ *
+ ****************************************************************************/
+
+int task_setcanceltype(int type, FAR int *oldtype)
+{
+       FAR struct tcb_s *tcb = (FAR struct tcb_s *)g_readytorun.head;
+       int ret = OK;
+
+       /* Suppress context changes for a bit so that the flags are stable. (the
+        * flags should not change in interrupt handling).
+        */
+
+       sched_lock();
+
+       /* Return the current type if so requrested */
+
+       if (oldtype != NULL) {
+               if ((tcb->flags & TCB_FLAG_CANCEL_DEFERRED) != 0) {
+                       *oldtype = TASK_CANCEL_DEFERRED;
+               } else {
+                       *oldtype = TASK_CANCEL_ASYNCHRONOUS;
+               }
+       }
+
+       /* Set the new cancellation type */
+
+       if (type == TASK_CANCEL_ASYNCHRONOUS) {
+               /* Clear the deferred cancellation bit */
+
+               tcb->flags &= ~TCB_FLAG_CANCEL_DEFERRED;
+
+#ifdef CONFIG_CANCELLATION_POINTS
+               /* If we just switched from deferred to asynchronous type and if a
+                * cancellation is pending, then exit now.
+                */
+
+               if ((tcb->flags & TCB_FLAG_CANCEL_PENDING) != 0 &&
+               (tcb->flags & TCB_FLAG_NONCANCELABLE) == 0) {
+                       tcb->flags &= ~TCB_FLAG_CANCEL_PENDING;
+
+                       /* Exit according to the type of the thread */
+
+#ifndef CONFIG_DISABLE_PTHREAD
+                       if ((tcb->flags & TCB_FLAG_TTYPE_MASK) == TCB_FLAG_TTYPE_PTHREAD) {
+                               pthread_exit(PTHREAD_CANCELED);
+                       } else
+#endif
+                       {
+                               exit(EXIT_FAILURE);
+                       }
+               }
+#endif
+       }
+#ifdef CONFIG_CANCELLATION_POINTS
+       else if (type == TASK_CANCEL_DEFERRED) {
+               /* Set the deferred cancellation type */
+
+               tcb->flags |= TCB_FLAG_CANCEL_DEFERRED;
+       }
+#endif
+       else {
+               ret = EINVAL;
+       }
+
+       sched_unlock();
+       return ret;
+}
index 39c5fbb..ee21fa5 100644 (file)
@@ -374,6 +374,11 @@ static int thread_schedsetup(FAR struct tcb_s *tcb, int priority, start_t start,
                tcb->flags &= ~TCB_FLAG_TTYPE_MASK;
                tcb->flags |= ttype;
 
+#ifdef CONFIG_CANCELLATION_POINTS
+               /* Set the deferred cancellation type */
+               tcb->flags |= TCB_FLAG_CANCEL_DEFERRED;
+#endif
+
                /* Save initial thread scheduling policy int the TCB */
 
 #if CONFIG_RR_INTERVAL > 0
@@ -421,7 +426,6 @@ static int thread_schedsetup(FAR struct tcb_s *tcb, int priority, start_t start,
                tcb->task_state = TSTATE_TASK_INACTIVE;
                sched_unlock();
        }
-
        return ret;
 }
 
diff --git a/os/kernel/task/task_testcancel.c b/os/kernel/task/task_testcancel.c
new file mode 100644 (file)
index 0000000..0363071
--- /dev/null
@@ -0,0 +1,84 @@
+/****************************************************************************
+ *
+ * Copyright 2016 Samsung Electronics All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ ****************************************************************************/
+/****************************************************************************
+ * kernel/task/task_testcancel.c
+ *
+ *   Copyright (C) 2016 Gregory Nutt. All rights reserved.
+ *   Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <tinyara/config.h>
+
+#include <sched.h>
+#include <errno.h>
+
+#include <tinyara/cancelpt.h>
+
+#include "task/task.h"
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: task_testcancel
+ *
+ * Description:
+ *   The task_testcancel() function creates a cancellation point in the
+ *   calling thread. The task_testcancel() function has no effect if
+ *   cancelability is disabled
+ *
+ ****************************************************************************/
+
+void task_testcancel(void)
+{
+       (void)enter_cancellation_point();
+       leave_cancellation_point();
+}