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
--- /dev/null
+/****************************************************************************
+ *
+ * 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;
+}
--- /dev/null
+/****************************************************************************
+ *
+ * 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;
+}
--- /dev/null
+/****************************************************************************
+ *
+ * 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();
+}
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
--- /dev/null
+/****************************************************************************
+ *
+ * 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;
+}
--- /dev/null
+/****************************************************************************
+ *
+ * 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)
+{
+}
#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>
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)
#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
{
err = -ret;
goto errout;
}
+ leave_cancellation_point();
return OK;
#endif
errout:
set_errno(err);
+ leave_cancellation_point();
return ERROR;
}
#include <tinyara/fs/fs.h>
#include <tinyara/net/net.h>
#include <tinyara/sched.h>
+#include <tinyara/cancelpt.h>
#include "inode/inode.h"
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);
/* The errno value has already been set */
va_end(ap);
+ leave_cancellation_point();
return ERROR;
}
}
va_end(ap);
+ leave_cancellation_point();
return ret;
}
#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"
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. */
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 */
#include <stdarg.h>
#endif
+#include <tinyara/cancelpt.h>
#include <tinyara/fs/fs.h>
#include "inode/inode.h"
#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) {
filep = fs_getfilep(fd);
if (!filep) {
/* The errno value has already been set */
-
+ leave_cancellation_point();
return ERROR;
}
goto errout_with_fd;
}
+ leave_cancellation_point();
return fd;
errout_with_fd:
inode_release(inode);
errout:
set_errno(ret);
+ leave_cancellation_point();
return ERROR;
}
#include <tinyara/sched.h>
#include <tinyara/clock.h>
+#include <tinyara/cancelpt.h>
#include <tinyara/fs/fs.h>
#ifdef CONFIG_NET_LWIP
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) {
}
sem_destroy(&sem);
+ leave_cancellation_point();
/* Check for errors */
#include <unistd.h>
#include <errno.h>
+#include <tinyara/cancelpt.h>
#include <tinyara/fs/fs.h>
/****************************************************************************
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. */
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;
}
#include <unistd.h>
#include <errno.h>
+#include <tinyara/cancelpt.h>
#include <tinyara/fs/fs.h>
/****************************************************************************
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. */
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;
}
#include <fcntl.h>
#include <sched.h>
#include <errno.h>
+#include <tinyara/cancelpt.h>
#include "inode/inode.h"
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
#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
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;
}
#include <debug.h>
#include <tinyara/kmalloc.h>
+#include <tinyara/cancelpt.h>
#include <tinyara/fs/fs.h>
#include "inode/inode.h"
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() */
pollset = (struct pollfd *)kmm_zalloc(npfds * sizeof(struct pollfd));
if (!pollset) {
set_errno(ENOMEM);
+ leave_cancellation_point();
return ERROR;
}
}
set_errno(errcode);
}
+ leave_cancellation_point();
return ret;
}
#include <errno.h>
#include <assert.h>
+#include <tinyara/cancelpt.h>
#include <sys/socket.h>
#include "inode/inode.h"
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? */
#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? */
/* 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;
}
#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)
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 */
*/
int pthread_setcancelstate(int state, FAR int *oldstate);
+int pthread_setcanceltype(int type, FAR int *oldtype);
+
/**
* @cond
* @internal
/**
* @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.
*/
#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
*/
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
--- /dev/null
+/****************************************************************************
+ *
+ * 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 */
#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 */
};
#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
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 */
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
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
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
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
---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
#include <debug.h>
#include <tinyara/arch.h>
+#include <tinyara/cancelpt.h>
#include "sched/sched.h"
#include "mqueue/mqueue.h"
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;
msgq->nmsgs--;
}
+ leave_cancellation_point();
return rcvmsg;
}
}
/* Return the length of the message transferred to the user buffer */
-
return rcvmsglen;
}
#include <mqueue.h>
#include <debug.h>
#include <tinyara/arch.h>
+#include <tinyara/cancelpt.h>
#include "mqueue/mqueue.h"
* errno appropriately.
*/
+ /* mq_receive() is a cancellation point */
+ (void)enter_cancellation_point();
+
if (mq_verifyreceive(mqdes, msg, msglen) != OK) {
+ leave_cancellation_point();
return ERROR;
}
}
sched_unlock();
+ leave_cancellation_point();
return ret;
}
#include <debug.h>
#include <tinyara/arch.h>
+#include <tinyara/cancelpt.h>
#include "mqueue/mqueue.h"
* 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;
}
}
sched_unlock();
+ leave_cancellation_point();
return ret;
}
#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"
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;
/* No... We will return an error to the caller. */
set_errno(EAGAIN);
+ leave_cancellation_point();
return ERROR;
}
*/
if (get_errno() != OK) {
+ leave_cancellation_point();
return ERROR;
}
}
}
}
+ leave_cancellation_point();
return OK;
}
#include <tinyara/arch.h>
#include <tinyara/wdog.h>
+#include <tinyara/cancelpt.h>
#include "sched/sched.h"
#include "clock/clock.h"
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;
}
rtcb->waitdog = wd_create();
if (!rtcb->waitdog) {
set_errno(EINVAL);
+ leave_cancellation_point();
return ERROR;
}
sched_unlock();
wd_delete(rtcb->waitdog);
rtcb->waitdog = NULL;
+ leave_cancellation_point();
return ERROR;
}
sched_unlock();
wd_delete(rtcb->waitdog);
rtcb->waitdog = NULL;
+ leave_cancellation_point();
return ret;
}
#include <tinyara/arch.h>
#include <tinyara/wdog.h>
+#include <tinyara/cancelpt.h>
#include "clock/clock.h"
#include "sched/sched.h"
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;
}
rtcb->waitdog = wd_create();
if (!rtcb->waitdog) {
set_errno(EINVAL);
+ leave_cancellation_point();
return ERROR;
}
sched_unlock();
wd_delete(rtcb->waitdog);
rtcb->waitdog = NULL;
+ leave_cancellation_point();
return ret;
}
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
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);
#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;
}
*/
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:
*
* 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();
* 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);
}
--- /dev/null
+/****************************************************************************
+ *
+ * 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 */
#include <errno.h>
#include <assert.h>
#include <debug.h>
+#include <tinyara/cancelpt.h>
#include <tinyara/wdog.h>
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) {
}
svdbg("Returning %d\n", ret);
+ leave_cancellation_point();
return ret;
}
#include <errno.h>
#include <debug.h>
+#include <tinyara/cancelpt.h>
#include "pthread/pthread.h"
/****************************************************************************
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) {
}
svdbg("Returning %d\n", ret);
+ leave_cancellation_point();
return ret;
}
#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.
errcode = EIO;
goto errout_with_join;
}
-
return ret;
errout_with_join:
}
#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);
* 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>
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;
}
}
svdbg("Returning %d\n", ret);
+ leave_cancellation_point();
return ret;
}
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);
}
#include <errno.h>
#include <tinyara/sched.h>
+#include <tinyara/cancelpt.h>
#include "sched/sched.h"
#include "group/group.h"
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
}
}
+ leave_cancellation_point();
sched_unlock();
return OK;
errout_with_errno:
set_errno(err);
errout:
+ leave_cancellation_point();
sched_unlock();
return ERROR;
}
#include <errno.h>
#include <tinyara/sched.h>
+#include <tinyara/cancelpt.h>
#include "sched/sched.h"
#include "group/group.h"
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
/* 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;
}
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
}
}
+ leave_cancellation_point();
sched_unlock();
return (int)pid;
set_errno(err);
errout_with_lock:
+ leave_cancellation_point();
sched_unlock();
return ERROR;
}
#include <tinyara/arch.h>
#include <tinyara/wdog.h>
+#include <tinyara/cancelpt.h>
#include "sched/sched.h"
#include "clock/clock.h"
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.
*/
irqrestore(flags);
wd_delete(rtcb->waitdog);
rtcb->waitdog = NULL;
+ leave_cancellation_point();
return OK;
}
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
errout:
set_errno(err);
+ leave_cancellation_point();
return ERROR;
}
#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
****************************************************************************/
/* 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 */
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;
}
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.
*/
sched_unlock();
#endif
}
-
- /* Interrupts may now be enabled. */
-
- irqrestore(saved_state);
}
+ leave_cancellation_point();
+ irqrestore(saved_state);
return ret;
}
/* 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 */
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;
}
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);
}
/* Interrupts may now be enabled. */
-
- irqrestore(saved_state);
}
+ leave_cancellation_point();
+ irqrestore(saved_state);
+
return ret;
}
#include <tinyara/clock.h>
#include <arch/irq.h>
+#include <tinyara/cancelpt.h>
#include "clock/clock.h"
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;
/* The timeout "error" is the normal, successful result */
irqrestore(flags);
+ leave_cancellation_point();
return OK;
}
errout:
set_errno(errval);
+ leave_cancellation_point();
return ERROR;
}
#include <unistd.h>
#include <signal.h>
+#include <tinyara/cancelpt.h>
+
/****************************************************************************
* Preprocessor Definitions
****************************************************************************/
{
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
* meaning that some unblocked signal was caught.
*/
- return sigwaitinfo(&set, &value);
+ ret = sigwaitinfo(&set, &value);
+ leave_cancellation_point();
+ return ret;
}
#include <sched.h>
#include <tinyara/arch.h>
+#include <tinyara/cancelpt.h>
#include "sched/sched.h"
#include "signal/signal.h"
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
}
sched_unlock();
+ leave_cancellation_point();
return ERROR;
}
#include <tinyara/arch.h>
#include <tinyara/wdog.h>
+#include <tinyara/cancelpt.h>
#include "sched/sched.h"
#include "signal/signal.h"
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
}
sched_unlock();
+ leave_cancellation_point();
return ret;
}
#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;
}
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)
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
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 */
--- /dev/null
+/****************************************************************************
+ *
+ * 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 */
#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;
}
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.
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;
}
--- /dev/null
+/****************************************************************************
+ *
+ * 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;
+}
--- /dev/null
+/****************************************************************************
+ *
+ * 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;
+}
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
tcb->task_state = TSTATE_TASK_INACTIVE;
sched_unlock();
}
-
return ret;
}
--- /dev/null
+/****************************************************************************
+ *
+ * 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();
+}