| /**************************************************************************** |
| * sched/pthread/pthread_completejoin.c |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. The |
| * ASF licenses this file to you 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. |
| * |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Included Files |
| ****************************************************************************/ |
| |
| #include <nuttx/config.h> |
| |
| #include <nuttx/nuttx.h> |
| #include <sys/types.h> |
| #include <stdbool.h> |
| #include <pthread.h> |
| #include <assert.h> |
| #include <errno.h> |
| #include <debug.h> |
| |
| #include "sched/sched.h" |
| #include "group/group.h" |
| #include "pthread/pthread.h" |
| |
| /**************************************************************************** |
| * Public Functions |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Name: pthread_completejoin |
| * |
| * Description: |
| * A thread has been terminated -- either by returning, calling |
| * pthread_exit(), or through pthread_cancel(). In any event, we must |
| * complete any pending join events. |
| * |
| * Input Parameters: |
| * exit_value |
| * |
| * Returned Value: |
| * OK unless there is no join information associated with the pid. |
| * This could happen, for example, if a task started with task_create() |
| * calls pthread_exit(). |
| * |
| * Assumptions: |
| * |
| ****************************************************************************/ |
| |
| int pthread_completejoin(pid_t pid, FAR void *exit_value) |
| { |
| FAR struct tcb_s *tcb = nxsched_get_tcb(pid); |
| FAR struct task_group_s *group = tcb->group; |
| FAR struct task_join_s *join; |
| FAR struct tcb_s *wtcb; |
| FAR sq_entry_t *curr; |
| FAR sq_entry_t *next; |
| int ret = OK; |
| |
| sinfo("pid=%d exit_value=%p\n", pid, exit_value); |
| |
| nxrmutex_lock(&group->tg_joinlock); |
| |
| if (!sq_empty(&tcb->join_queue)) |
| { |
| sq_for_every_safe(&tcb->join_queue, curr, next) |
| { |
| /* Remove join entry from queue */ |
| |
| sq_rem(curr, &tcb->join_queue); |
| |
| /* Get tcb entry which waiting for the join */ |
| |
| wtcb = container_of(curr, struct tcb_s, join_entry); |
| |
| /* Save the return exit value in the thread structure. */ |
| |
| wtcb->join_val = exit_value; |
| |
| /* Notify waiters of the availability of the exit value */ |
| |
| nxsem_post(&wtcb->join_sem); |
| } |
| } |
| else if (!sq_is_singular(&tcb->group->tg_members) && |
| (tcb->flags & TCB_FLAG_DETACHED) == 0) |
| { |
| ret = pthread_findjoininfo(tcb->group, pid, &join, true); |
| if (ret == OK) |
| { |
| join->exit_value = exit_value; |
| } |
| } |
| |
| tcb->flags |= TCB_FLAG_JOIN_COMPLETED; |
| |
| nxrmutex_unlock(&group->tg_joinlock); |
| |
| return ret; |
| } |
| |
| /**************************************************************************** |
| * Name: pthread_destroyjoin |
| * |
| * Description: |
| * This is called from pthread_completejoin if the join info was |
| * detached or from pthread_join when the last waiting thread has |
| * received the thread exit info. |
| * |
| * Or it may never be called if the join info was never detached or if |
| * no thread ever calls pthread_join. In case, there is a memory leak! |
| * |
| * Assumptions: |
| * The caller holds tg_joinlock |
| * |
| ****************************************************************************/ |
| |
| void pthread_destroyjoin(FAR struct task_group_s *group, |
| FAR struct task_join_s *pjoin) |
| { |
| sinfo("pjoin=%p\n", pjoin); |
| |
| /* Remove the join info from the set of joins */ |
| |
| nxrmutex_lock(&group->tg_joinlock); |
| sq_rem(&pjoin->entry, &group->tg_joinqueue); |
| nxrmutex_unlock(&group->tg_joinlock); |
| |
| /* And deallocate the pjoin structure */ |
| |
| kmm_free(pjoin); |
| } |