Fork us on GitHub Follow us on Facebook Follow us on Twitter

Changeset ef4218f in mainline


Ignore:
Timestamp:
2018-11-09T17:54:05Z (3 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master
Children:
1a5fe4f
Parents:
d19b3fc
Message:

Do not leak futexes

File:
1 edited

Legend:

Unmodified
Added
Removed
  • kernel/generic/src/synch/futex.c

    rd19b3fc ref4218f  
    4545 * encountered before). Futex object's lifetime is governed by
    4646 * a reference count that represents the number of all the different
    47  * user space virtual addresses from all tasks that map to the
    48  * physical address of the futex variable. A futex object is freed
     47 * tasks that reference the futex variable. A futex object is freed
    4948 * when the last task having accessed the futex exits.
    5049 *
     
    7574/** Task specific pointer to a global kernel futex object. */
    7675typedef struct futex_ptr {
    77         /** List of all futex pointers used by the task. */
    78         link_t all_link;
     76        /** Link for the list of all futex pointers used by a task. */
     77        link_t task_link;
    7978        /** Kernel futex object. */
    8079        futex_t *futex;
    81         /** User space virtual address of the futex variable in the task. */
    82         uintptr_t uaddr;
    8380} futex_ptr_t;
    8481
     
    136133
    137134        list_foreach_safe(TASK->futex_list, cur_link, next_link) {
    138                 futex_ptr_t *fut_ptr = member_to_inst(cur_link, futex_ptr_t, all_link);
    139 
    140                 /*
    141                  * The function is free to free the futex.  Moreover
    142                  * release_ref() only frees the futex if this is the last task
    143                  * referencing the futex. Therefore, only threads of this task
    144                  * may have referenced the futex if it is to be freed.
    145                  */
    146                 futex_release_ref_locked(fut_ptr->futex);
     135                futex_ptr_t *futex_ptr = member_to_inst(cur_link, futex_ptr_t,
     136                    task_link);
     137
     138                futex_release_ref_locked(futex_ptr->futex);
     139                free(futex_ptr);
    147140        }
    148141
     
    166159{
    167160        assert(spinlock_locked(&futex_ht_lock));
    168         assert(0 < futex->refcount);
     161        assert(futex->refcount > 0);
    169162        ++futex->refcount;
    170163}
     
    174167{
    175168        assert(spinlock_locked(&futex_ht_lock));
    176         assert(0 < futex->refcount);
     169        assert(futex->refcount > 0);
    177170
    178171        --futex->refcount;
    179172
    180         if (0 == futex->refcount) {
     173        if (futex->refcount == 0)
    181174                hash_table_remove(&futex_ht, &futex->paddr);
    182         }
    183175}
    184176
     
    202194        if (!futex)
    203195                return NULL;
     196
     197        futex_ptr_t *futex_ptr = malloc(sizeof(futex_ptr_t));
     198        if (!futex_ptr) {
     199                free(futex);
     200                return NULL;
     201        }
    204202
    205203        /*
     
    207205         * if it is not present).
    208206         */
     207        spinlock_lock(&TASK->futex_list_lock);
    209208        spinlock_lock(&futex_ht_lock);
    210209
     
    214213                free(futex);
    215214                futex = member_to_inst(fut_link, futex_t, ht_link);
    216                 futex_add_ref(futex);
     215
     216                /*
     217                 * See if the futex is already known to the TASK
     218                 */
     219                bool found = false;
     220                list_foreach(TASK->futex_list, task_link, futex_ptr_t, fp) {
     221                        if (fp->futex->paddr == paddr) {
     222                                found = true;
     223                                break;
     224                        }
     225                }
     226                /*
     227                 * If not, put it on the TASK->futex_list and bump its reference
     228                 * count
     229                 */
     230                if (!found) {
     231                        list_append(&futex_ptr->task_link, &TASK->futex_list);
     232                        futex_add_ref(futex);
     233                } else
     234                        free(futex_ptr);
    217235        } else {
    218236                futex_initialize(futex, paddr);
    219237                hash_table_insert(&futex_ht, &futex->ht_link);
     238
     239                /*
     240                 * This is a new futex, so it is not on the TASK->futex_list yet
     241                 */
     242                futex_ptr->futex = futex;
     243                list_append(&futex_ptr->task_link, &TASK->futex_list);
    220244        }
    221245
    222246        spinlock_unlock(&futex_ht_lock);
     247        spinlock_unlock(&TASK->futex_list_lock);
    223248
    224249        return futex;
     
    250275
    251276/** Sleep in futex wait queue with a timeout.
     277 *
    252278 *  If the sleep times out or is interrupted, the next wakeup is ignored.
    253279 *  The userspace portion of the call must handle this condition.
Note: See TracChangeset for help on using the changeset viewer.