pthread.c 15.6 KB
Newer Older
Y
yiyue.fang 已提交
1
/*
2
 * Copyright (c) 2006-2018, RT-Thread Development Team
Y
yiyue.fang 已提交
3
 *
4
 * SPDX-License-Identifier: Apache-2.0
Y
yiyue.fang 已提交
5 6 7
 *
 * Change Logs:
 * Date           Author       Notes
8 9
 * 2018-01-26     Bernard      Fix pthread_detach issue for a none-joinable
 *                             thread.
10
 * 2019-02-07     Bernard      Add _pthread_destroy to release pthread resource.
Y
yiyue.fang 已提交
11 12
 */

13
#include <rthw.h>
M
Ming, Bai 已提交
14 15 16 17
#include <pthread.h>
#include <sched.h>
#include "pthread_internal.h"

18 19 20 21 22
RT_DEFINE_SPINLOCK(pth_lock);
_pthread_data_t *pth_table[PTHREAD_NUM_MAX] = {NULL};

_pthread_data_t *_pthread_get_data(pthread_t thread)
{
23
    RT_DECLARE_SPINLOCK(pth_lock);
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
    _pthread_data_t *ptd;

    if (thread >= PTHREAD_NUM_MAX) return NULL;

    rt_hw_spin_lock(&pth_lock);
    ptd = pth_table[thread];
    rt_hw_spin_unlock(&pth_lock);

    if (ptd && ptd->magic == PTHREAD_MAGIC) return ptd;

    return NULL;
}

pthread_t _pthread_data_get_pth(_pthread_data_t *ptd)
{
    int index;
40
    RT_DECLARE_SPINLOCK(pth_lock);
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55

    rt_hw_spin_lock(&pth_lock);
    for (index = 0; index < PTHREAD_NUM_MAX; index ++)
    {
        if (pth_table[index] == ptd) break;
    }
    rt_hw_spin_unlock(&pth_lock);

    return index;
}

pthread_t _pthread_data_create(void)
{
    int index;
    _pthread_data_t *ptd = NULL;
56
    RT_DECLARE_SPINLOCK(pth_lock);
57 58 59 60

    ptd = (_pthread_data_t*)rt_malloc(sizeof(_pthread_data_t));
    if (!ptd) return PTHREAD_NUM_MAX;

61
    memset(ptd, 0x0, sizeof(_pthread_data_t));
62 63 64 65 66 67 68 69 70 71 72
    ptd->canceled = 0;
    ptd->cancelstate = PTHREAD_CANCEL_DISABLE;
    ptd->canceltype = PTHREAD_CANCEL_DEFERRED;
    ptd->magic = PTHREAD_MAGIC;

    rt_hw_spin_lock(&pth_lock);
    for (index = 0; index < PTHREAD_NUM_MAX; index ++)
    {
        if (pth_table[index] == NULL)
        {
            pth_table[index] = ptd;
73
            break;
74 75 76 77
        }
    }
    rt_hw_spin_unlock(&pth_lock);

78 79 80 81 82 83 84
    /* full of pthreads, clean magic and release ptd */
    if (index == PTHREAD_NUM_MAX)
    {
        ptd->magic = 0x0;
        rt_free(ptd);
    }

85 86 87 88 89
    return index;
}

void _pthread_data_destroy(pthread_t pth)
{
90 91
    RT_DECLARE_SPINLOCK(pth_lock);

92 93 94 95 96 97 98 99 100 101 102 103 104
    _pthread_data_t *ptd = _pthread_get_data(pth);
    if (ptd)
    {
        /* remove from pthread table */
        rt_hw_spin_lock(&pth_lock);
        pth_table[pth] = NULL;
        rt_hw_spin_unlock(&pth_lock);

        /* delete joinable semaphore */
        if (ptd->joinable_sem != RT_NULL)
            rt_sem_delete(ptd->joinable_sem);

        /* release thread resource */
覃攀's avatar
覃攀 已提交
105
        if (ptd->attr.stackaddr == RT_NULL && ptd->tid->stack_addr != RT_NULL)
106 107 108 109 110 111
        {
            /* release thread allocated stack */
            rt_free(ptd->tid->stack_addr);
        }
        /* clean stack addr pointer */
        ptd->tid->stack_addr = RT_NULL;
112

113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
        /*
        * if this thread create the local thread data,
        * delete it
        */
        if (ptd->tls != RT_NULL) rt_free(ptd->tls);
        rt_free(ptd->tid);

        /* clean magic */
        ptd->magic = 0x0;

        /* free ptd */
        rt_free(ptd);
    }
}

M
Ming, Bai 已提交
128 129
int pthread_system_init(void)
{
Y
yiyue.fang 已提交
130 131 132 133 134 135
    /* initialize key area */
    pthread_key_system_init();
    /* initialize posix mqueue */
    posix_mq_system_init();
    /* initialize posix semaphore */
    posix_sem_system_init();
M
Ming, Bai 已提交
136

Y
yiyue.fang 已提交
137
    return 0;
M
Ming, Bai 已提交
138
}
139
INIT_COMPONENT_EXPORT(pthread_system_init);
M
Ming, Bai 已提交
140

141 142
static void _pthread_destroy(_pthread_data_t *ptd)
{
143 144
    pthread_t pth = _pthread_data_get_pth(ptd);
    if (pth != PTHREAD_NUM_MAX)
145
    {
146
        _pthread_data_destroy(pth);
147 148 149 150 151
    }

    return;
}

M
Ming, Bai 已提交
152 153
static void _pthread_cleanup(rt_thread_t tid)
{
Y
yiyue.fang 已提交
154
    _pthread_data_t *ptd;
155 156 157 158

    /* get pthread data from user data of thread */
    ptd = (_pthread_data_t *)tid->user_data;
    RT_ASSERT(ptd != RT_NULL);
Y
yiyue.fang 已提交
159 160 161 162 163 164 165 166 167 168

    /* clear cleanup function */
    tid->cleanup = RT_NULL;
    if (ptd->attr.detachstate == PTHREAD_CREATE_JOINABLE)
    {
        rt_sem_release(ptd->joinable_sem);
    }
    else
    {
        /* release pthread resource */
169
        _pthread_destroy(ptd);
Y
yiyue.fang 已提交
170
    }
M
Ming, Bai 已提交
171 172
}

Y
yiyue.fang 已提交
173
static void pthread_entry_stub(void *parameter)
M
Ming, Bai 已提交
174
{
Y
yiyue.fang 已提交
175
    void *value;
176
    _pthread_data_t *ptd;
M
Ming, Bai 已提交
177

178
    ptd = (_pthread_data_t *)parameter;
M
Ming, Bai 已提交
179

Y
yiyue.fang 已提交
180 181 182 183
    /* execute pthread entry */
    value = ptd->thread_entry(ptd->thread_parameter);
    /* set value */
    ptd->return_value = value;
M
Ming, Bai 已提交
184 185
}

186
int pthread_create(pthread_t            *pid,
187 188
                   const pthread_attr_t *attr,
                   void *(*start)(void *), void *parameter)
M
Ming, Bai 已提交
189
{
190
    int ret = 0;
Y
yiyue.fang 已提交
191 192 193
    void *stack;
    char name[RT_NAME_MAX];
    static rt_uint16_t pthread_number = 0;
194 195

    pthread_t pth_id;
Y
yiyue.fang 已提交
196 197
    _pthread_data_t *ptd;

198
    /* pid shall be provided */
199
    RT_ASSERT(pid != RT_NULL);
Y
yiyue.fang 已提交
200 201

    /* allocate posix thread data */
202 203 204 205 206 207 208 209
    pth_id = _pthread_data_create();
    if (pth_id == PTHREAD_NUM_MAX) 
    {
        ret = ENOMEM;
        goto __exit;
    }
    /* get pthread data */
    ptd = _pthread_get_data(pth_id);
Y
yiyue.fang 已提交
210 211

    if (attr != RT_NULL)
212
    {
Y
yiyue.fang 已提交
213
        ptd->attr = *attr;
214 215
    }
    else
Y
yiyue.fang 已提交
216 217 218 219 220 221 222 223 224 225 226
    {
        /* use default attribute */
        pthread_attr_init(&ptd->attr);
    }

    rt_snprintf(name, sizeof(name), "pth%02d", pthread_number ++);

    /* pthread is a static thread object */
    ptd->tid = (rt_thread_t) rt_malloc(sizeof(struct rt_thread));
    if (ptd->tid == RT_NULL)
    {
227 228
        ret = ENOMEM;
        goto __exit;
Y
yiyue.fang 已提交
229
    }
覃攀's avatar
覃攀 已提交
230
    memset(ptd->tid, 0, sizeof(struct rt_thread));
Y
yiyue.fang 已提交
231 232 233 234 235 236

    if (ptd->attr.detachstate == PTHREAD_CREATE_JOINABLE)
    {
        ptd->joinable_sem = rt_sem_create(name, 0, RT_IPC_FLAG_FIFO);
        if (ptd->joinable_sem == RT_NULL)
        {
237 238
            ret = ENOMEM;
            goto __exit;
Y
yiyue.fang 已提交
239 240 241
        }
    }
    else
242
    {
Y
yiyue.fang 已提交
243
        ptd->joinable_sem = RT_NULL;
244
    }
Y
yiyue.fang 已提交
245 246 247 248 249

    /* set parameter */
    ptd->thread_entry = start;
    ptd->thread_parameter = parameter;

覃攀's avatar
覃攀 已提交
250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265
    /* stack */
    if (ptd->attr.stackaddr == 0)
    {
        stack = (void *)rt_malloc(ptd->attr.stacksize);
    }
    else
    {
        stack = (void *)(ptd->attr.stackaddr);
    }

    if (stack == RT_NULL)
    {
        ret = ENOMEM;
        goto __exit;
    }

Y
yiyue.fang 已提交
266
    /* initial this pthread to system */
267
    if (rt_thread_init(ptd->tid, name, pthread_entry_stub, ptd,
268 269
                       stack, ptd->attr.stacksize,
                       ptd->attr.schedparam.sched_priority, 5) != RT_EOK)
Y
yiyue.fang 已提交
270
    {
271 272
        ret = EINVAL;
        goto __exit;
Y
yiyue.fang 已提交
273 274 275
    }

    /* set pthread id */
276
    *pid = pth_id;
Y
yiyue.fang 已提交
277 278

    /* set pthread cleanup function and ptd data */
279 280
    ptd->tid->cleanup = _pthread_cleanup;
    ptd->tid->user_data = (rt_uint32_t)ptd;
Y
yiyue.fang 已提交
281 282

    /* start thread */
283
    if (rt_thread_startup(ptd->tid) == RT_EOK)
Y
yiyue.fang 已提交
284 285 286 287
        return 0;

    /* start thread failed */
    rt_thread_detach(ptd->tid);
288
    ret = EINVAL;
Y
yiyue.fang 已提交
289

290 291 292 293
__exit:
    if (pth_id != PTHREAD_NUM_MAX)
        _pthread_data_destroy(pth_id);
    return ret;
M
Ming, Bai 已提交
294 295 296 297 298
}
RTM_EXPORT(pthread_create);

int pthread_detach(pthread_t thread)
{
299 300
    int ret = 0;
    _pthread_data_t *ptd = _pthread_get_data(thread);
Y
yiyue.fang 已提交
301

302
    rt_enter_critical();
303 304 305 306 307
    if (ptd->attr.detachstate == PTHREAD_CREATE_DETACHED)
    {
        /* The implementation has detected that the value specified by thread does not refer
         * to a joinable thread.
         */
308 309
        ret = EINVAL;
        goto __exit;
310 311
    }

312
    if ((ptd->tid->stat & RT_THREAD_STAT_MASK) == RT_THREAD_CLOSE)
Y
yiyue.fang 已提交
313
    {
314 315
        /* this defunct pthread is not handled by idle */
        if (rt_sem_trytake(ptd->joinable_sem) != RT_EOK)
Y
yiyue.fang 已提交
316
        {
317 318 319 320 321 322 323 324 325 326 327
            rt_sem_release(ptd->joinable_sem);

            /* change to detach state */
            ptd->attr.detachstate = PTHREAD_CREATE_DETACHED;

            /* detach joinable semaphore */
            if (ptd->joinable_sem)
            {
                rt_sem_delete(ptd->joinable_sem);
                ptd->joinable_sem = RT_NULL;
            }
Y
yiyue.fang 已提交
328
        }
329 330
        else
        {
331 332
            /* destroy this pthread */
            _pthread_destroy(ptd);
333
        }
Y
yiyue.fang 已提交
334

335
        goto __exit;
Y
yiyue.fang 已提交
336 337 338 339 340 341 342
    }
    else
    {
        /* change to detach state */
        ptd->attr.detachstate = PTHREAD_CREATE_DETACHED;

        /* detach joinable semaphore */
343 344 345 346 347
        if (ptd->joinable_sem)
        {
            rt_sem_delete(ptd->joinable_sem);
            ptd->joinable_sem = RT_NULL;
        }
Y
yiyue.fang 已提交
348 349
    }

350 351 352
__exit:
    rt_exit_critical();
    return ret;
M
Ming, Bai 已提交
353 354 355
}
RTM_EXPORT(pthread_detach);

356
int pthread_join(pthread_t thread, void **value_ptr)
M
Ming, Bai 已提交
357
{
358
    _pthread_data_t *ptd;
Y
yiyue.fang 已提交
359 360
    rt_err_t result;

361 362
    ptd = _pthread_get_data(thread);
    if (ptd && ptd->tid == rt_thread_self())
Y
yiyue.fang 已提交
363 364 365 366 367 368 369 370 371 372 373 374 375 376 377
    {
        /* join self */
        return EDEADLK;
    }

    if (ptd->attr.detachstate == PTHREAD_CREATE_DETACHED)
        return EINVAL; /* join on a detached pthread */

    result = rt_sem_take(ptd->joinable_sem, RT_WAITING_FOREVER);
    if (result == RT_EOK)
    {
        /* get return value */
        if (value_ptr != RT_NULL)
            *value_ptr = ptd->return_value;

378 379
        /* destroy this pthread */
        _pthread_destroy(ptd);
Y
yiyue.fang 已提交
380 381
    }
    else
382
    {
Y
yiyue.fang 已提交
383
        return ESRCH;
384 385
    }

Y
yiyue.fang 已提交
386
    return 0;
M
Ming, Bai 已提交
387 388 389
}
RTM_EXPORT(pthread_join);

390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405
pthread_t pthread_self (void)
{
    rt_thread_t tid;
    _pthread_data_t *ptd;

    tid = rt_thread_self();
    if (tid == NULL) return PTHREAD_NUM_MAX;

    /* get pthread data from user data of thread */
    ptd = (_pthread_data_t *)rt_thread_self()->user_data;
    RT_ASSERT(ptd != RT_NULL);

    return _pthread_data_get_pth(ptd);
}
RTM_EXPORT(pthread_self);

406
void pthread_exit(void *value)
M
Ming, Bai 已提交
407
{
Y
yiyue.fang 已提交
408 409 410 411
    _pthread_data_t *ptd;
    _pthread_cleanup_t *cleanup;
    extern _pthread_key_data_t _thread_keys[PTHREAD_KEY_MAX];

412 413 414 415
    if (rt_thread_self() == NULL) return;

    /* get pthread data from user data of thread */
    ptd = (_pthread_data_t *)rt_thread_self()->user_data;
Y
yiyue.fang 已提交
416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439

    rt_enter_critical();
    /* disable cancel */
    ptd->cancelstate = PTHREAD_CANCEL_DISABLE;
    /* set return value */
    ptd->return_value = value;
    rt_exit_critical();

    /* invoke pushed cleanup */
    while (ptd->cleanup != RT_NULL)
    {
        cleanup = ptd->cleanup;
        ptd->cleanup = cleanup->next;

        cleanup->cleanup_func(cleanup->parameter);
        /* release this cleanup function */
        rt_free(cleanup);
    }

    /* destruct thread local key */
    if (ptd->tls != RT_NULL)
    {
        void *data;
        rt_uint32_t index;
440

Y
yiyue.fang 已提交
441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459
        for (index = 0; index < PTHREAD_KEY_MAX; index ++)
        {
            if (_thread_keys[index].is_used)
            {
                data = ptd->tls[index];
                if (data)
                    _thread_keys[index].destructor(data);
            }
        }

        /* release tls area */
        rt_free(ptd->tls);
        ptd->tls = RT_NULL;
    }

    /* detach thread */
    rt_thread_detach(ptd->tid);
    /* reschedule thread */
    rt_schedule();
M
Ming, Bai 已提交
460 461 462
}
RTM_EXPORT(pthread_exit);

463
int pthread_once(pthread_once_t *once_control, void (*init_routine)(void))
M
Ming, Bai 已提交
464
{
Y
yiyue.fang 已提交
465 466
    RT_ASSERT(once_control != RT_NULL);
    RT_ASSERT(init_routine != RT_NULL);
M
Ming, Bai 已提交
467

Y
yiyue.fang 已提交
468 469 470 471 472 473
    rt_enter_critical();
    if (!(*once_control))
    {
        /* call routine once */
        *once_control = 1;
        rt_exit_critical();
M
Ming, Bai 已提交
474

Y
yiyue.fang 已提交
475 476 477
        init_routine();
    }
    rt_exit_critical();
M
Ming, Bai 已提交
478

Y
yiyue.fang 已提交
479
    return 0;
M
Ming, Bai 已提交
480 481 482 483 484
}
RTM_EXPORT(pthread_once);

int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void))
{
B
bernard 已提交
485
    return EOPNOTSUPP;
M
Ming, Bai 已提交
486 487 488 489 490
}
RTM_EXPORT(pthread_atfork);

int pthread_kill(pthread_t thread, int sig)
{
B
bernard 已提交
491
#ifdef RT_USING_SIGNALS
492 493 494 495 496 497 498 499 500
    _pthread_data_t *ptd;

    ptd = _pthread_get_data(thread);
    if (ptd)
    {
        return rt_thread_kill(ptd->tid, sig);
    }

    return EINVAL;
B
bernard 已提交
501
#else
502
    return ENOSYS;
B
bernard 已提交
503
#endif
M
Ming, Bai 已提交
504 505 506
}
RTM_EXPORT(pthread_kill);

B
bernard 已提交
507 508 509
#ifdef RT_USING_SIGNALS
int pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
{
510
    return sigprocmask(how, set, oset);
B
bernard 已提交
511 512 513
}
#endif

M
Ming, Bai 已提交
514 515
void pthread_cleanup_pop(int execute)
{
Y
yiyue.fang 已提交
516 517 518
    _pthread_data_t *ptd;
    _pthread_cleanup_t *cleanup;

519 520 521 522
    if (rt_thread_self() == NULL) return;

    /* get pthread data from user data of thread */
    ptd = (_pthread_data_t *)rt_thread_self()->user_data;
Y
yiyue.fang 已提交
523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539
    RT_ASSERT(ptd != RT_NULL);

    if (execute)
    {
        rt_enter_critical();
        cleanup = ptd->cleanup;
        if (cleanup)
            ptd->cleanup = cleanup->next;
        rt_exit_critical();

        if (cleanup)
        {
            cleanup->cleanup_func(cleanup->parameter);

            rt_free(cleanup);
        }
    }
M
Ming, Bai 已提交
540 541 542
}
RTM_EXPORT(pthread_cleanup_pop);

543
void pthread_cleanup_push(void (*routine)(void *), void *arg)
M
Ming, Bai 已提交
544
{
Y
yiyue.fang 已提交
545 546 547
    _pthread_data_t *ptd;
    _pthread_cleanup_t *cleanup;

548 549 550 551
    if (rt_thread_self() == NULL) return;

    /* get pthread data from user data of thread */
    ptd = (_pthread_data_t *)rt_thread_self()->user_data;
Y
yiyue.fang 已提交
552 553 554 555 556 557 558 559 560 561 562 563 564
    RT_ASSERT(ptd != RT_NULL);

    cleanup = (_pthread_cleanup_t *)rt_malloc(sizeof(_pthread_cleanup_t));
    if (cleanup != RT_NULL)
    {
        cleanup->cleanup_func = routine;
        cleanup->parameter = arg;

        rt_enter_critical();
        cleanup->next = ptd->cleanup;
        ptd->cleanup = cleanup;
        rt_exit_critical();
    }
M
Ming, Bai 已提交
565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597
}
RTM_EXPORT(pthread_cleanup_push);

/*
 * According to IEEE Std 1003.1, 2004 Edition , following pthreads
 * interface support cancellation point:
 * mq_receive()
 * mq_send()
 * mq_timedreceive()
 * mq_timedsend()
 * msgrcv()
 * msgsnd()
 * msync()
 * pthread_cond_timedwait()
 * pthread_cond_wait()
 * pthread_join()
 * pthread_testcancel()
 * sem_timedwait()
 * sem_wait()
 *
 * A cancellation point may also occur when a thread is
 * executing the following functions:
 * pthread_rwlock_rdlock()
 * pthread_rwlock_timedrdlock()
 * pthread_rwlock_timedwrlock()
 * pthread_rwlock_wrlock()
 *
 * The pthread_cancel(), pthread_setcancelstate(), and pthread_setcanceltype()
 * functions are defined to be async-cancel safe.
 */

int pthread_setcancelstate(int state, int *oldstate)
{
Y
yiyue.fang 已提交
598
    _pthread_data_t *ptd;
M
Ming, Bai 已提交
599

600 601 602 603
    if (rt_thread_self() == NULL) return EINVAL;

    /* get pthread data from user data of thread */
    ptd = (_pthread_data_t *)rt_thread_self()->user_data;
Y
yiyue.fang 已提交
604
    RT_ASSERT(ptd != RT_NULL);
M
Ming, Bai 已提交
605

Y
yiyue.fang 已提交
606 607 608 609 610
    if ((state == PTHREAD_CANCEL_ENABLE) || (state == PTHREAD_CANCEL_DISABLE))
    {
        if (oldstate)
            *oldstate = ptd->cancelstate;
        ptd->cancelstate = state;
M
Ming, Bai 已提交
611

Y
yiyue.fang 已提交
612 613
        return 0;
    }
M
Ming, Bai 已提交
614

Y
yiyue.fang 已提交
615
    return EINVAL;
M
Ming, Bai 已提交
616 617 618 619 620
}
RTM_EXPORT(pthread_setcancelstate);

int pthread_setcanceltype(int type, int *oldtype)
{
Y
yiyue.fang 已提交
621
    _pthread_data_t *ptd;
M
Ming, Bai 已提交
622

623 624 625 626
    if (rt_thread_self() == NULL) return EINVAL;

    /* get pthread data from user data of thread */
    ptd = (_pthread_data_t *)rt_thread_self()->user_data;
Y
yiyue.fang 已提交
627
    RT_ASSERT(ptd != RT_NULL);
M
Ming, Bai 已提交
628

629
    if ((type != PTHREAD_CANCEL_DEFERRED) && (type != PTHREAD_CANCEL_ASYNCHRONOUS))
Y
yiyue.fang 已提交
630
        return EINVAL;
M
Ming, Bai 已提交
631

Y
yiyue.fang 已提交
632 633 634
    if (oldtype)
        *oldtype = ptd->canceltype;
    ptd->canceltype = type;
M
Ming, Bai 已提交
635

Y
yiyue.fang 已提交
636
    return 0;
M
Ming, Bai 已提交
637 638 639 640 641
}
RTM_EXPORT(pthread_setcanceltype);

void pthread_testcancel(void)
{
642 643
    int cancel = 0;
    _pthread_data_t *ptd;
M
Ming, Bai 已提交
644

645 646 647 648
    if (rt_thread_self() == NULL) return;

    /* get pthread data from user data of thread */
    ptd = (_pthread_data_t *)rt_thread_self()->user_data;
Y
yiyue.fang 已提交
649
    RT_ASSERT(ptd != RT_NULL);
M
Ming, Bai 已提交
650

Y
yiyue.fang 已提交
651 652 653
    if (ptd->cancelstate == PTHREAD_CANCEL_ENABLE)
        cancel = ptd->canceled;
    if (cancel)
654
        pthread_exit((void *)PTHREAD_CANCELED);
M
Ming, Bai 已提交
655 656 657 658 659
}
RTM_EXPORT(pthread_testcancel);

int pthread_cancel(pthread_t thread)
{
Y
yiyue.fang 已提交
660 661 662 663 664 665
    _pthread_data_t *ptd;

    /* get posix thread data */
    ptd = _pthread_get_data(thread);
    RT_ASSERT(ptd != RT_NULL);

666 667 668 669
    /* cancel self */
    if (ptd->tid == rt_thread_self())
        return 0;

Y
yiyue.fang 已提交
670 671 672 673 674 675 676 677 678 679 680 681 682
    /* set canceled */
    if (ptd->cancelstate == PTHREAD_CANCEL_ENABLE)
    {
        ptd->canceled = 1;
        if (ptd->canceltype == PTHREAD_CANCEL_ASYNCHRONOUS)
        {
            /*
             * to detach thread.
             * this thread will be removed from scheduler list
             * and because there is a cleanup function in the
             * thread (pthread_cleanup), it will move to defunct
             * thread list and wait for handling in idle thread.
             */
683
            rt_thread_detach(ptd->tid);
Y
yiyue.fang 已提交
684 685 686 687
        }
    }

    return 0;
M
Ming, Bai 已提交
688 689
}
RTM_EXPORT(pthread_cancel);
690