object.c 16.3 KB
Newer Older
1
/*
2
 * Copyright (c) 2006-2018, RT-Thread Development Team
B
Bernard Xiong 已提交
3
 *
4
 * SPDX-License-Identifier: Apache-2.0
5 6 7 8 9 10 11 12
 *
 * Change Logs:
 * Date           Author       Notes
 * 2006-03-14     Bernard      the first version
 * 2006-04-21     Bernard      change the scheduler lock to interrupt lock
 * 2006-05-18     Bernard      fix the object init bug
 * 2006-08-03     Bernard      add hook support
 * 2007-01-28     Bernard      rename RT_OBJECT_Class_Static to RT_Object_Class_Static
qiuyiuestc's avatar
qiuyiuestc 已提交
13
 * 2010-10-26     yi.qiu       add module support in rt_object_allocate and rt_object_free
14
 * 2017-12-10     Bernard      Add object_info enum.
15
 * 2018-01-25     Bernard      Fix the object find issue when enable MODULE.
16 17 18 19 20
 */

#include <rtthread.h>
#include <rthw.h>

21 22 23 24
#ifdef RT_USING_MODULE
#include <dlmodule.h>
#endif

25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
/*
 * define object_info for the number of rt_object_container items.
 */
enum rt_object_info_type
{
    RT_Object_Info_Thread = 0,                         /**< The object is a thread. */
#ifdef RT_USING_SEMAPHORE
    RT_Object_Info_Semaphore,                          /**< The object is a semaphore. */
#endif
#ifdef RT_USING_MUTEX
    RT_Object_Info_Mutex,                              /**< The object is a mutex. */
#endif
#ifdef RT_USING_EVENT
    RT_Object_Info_Event,                              /**< The object is a event. */
#endif
#ifdef RT_USING_MAILBOX
    RT_Object_Info_MailBox,                            /**< The object is a mail box. */
#endif
#ifdef RT_USING_MESSAGEQUEUE
    RT_Object_Info_MessageQueue,                       /**< The object is a message queue. */
#endif
#ifdef RT_USING_MEMHEAP
    RT_Object_Info_MemHeap,                            /**< The object is a memory heap */
#endif
#ifdef RT_USING_MEMPOOL
    RT_Object_Info_MemPool,                            /**< The object is a memory pool. */
#endif
#ifdef RT_USING_DEVICE
    RT_Object_Info_Device,                             /**< The object is a device */
#endif
    RT_Object_Info_Timer,                              /**< The object is a timer. */
#ifdef RT_USING_MODULE
    RT_Object_Info_Module,                             /**< The object is a module. */
#endif
    RT_Object_Info_Unknown,                            /**< The object is unknown. */
};

62 63
#define _OBJ_CONTAINER_LIST_INIT(c)     \
    {&(rt_object_container[c].object_list), &(rt_object_container[c].object_list)}
64
static struct rt_object_information rt_object_container[RT_Object_Info_Unknown] =
65
{
66
    /* initialize object container - thread */
67
    {RT_Object_Class_Thread, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Thread), sizeof(struct rt_thread)},
68
#ifdef RT_USING_SEMAPHORE
69
    /* initialize object container - semaphore */
70
    {RT_Object_Class_Semaphore, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Semaphore), sizeof(struct rt_semaphore)},
71 72
#endif
#ifdef RT_USING_MUTEX
73
    /* initialize object container - mutex */
74
    {RT_Object_Class_Mutex, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Mutex), sizeof(struct rt_mutex)},
75 76
#endif
#ifdef RT_USING_EVENT
77
    /* initialize object container - event */
78
    {RT_Object_Class_Event, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Event), sizeof(struct rt_event)},
79 80
#endif
#ifdef RT_USING_MAILBOX
81
    /* initialize object container - mailbox */
82
    {RT_Object_Class_MailBox, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_MailBox), sizeof(struct rt_mailbox)},
83 84
#endif
#ifdef RT_USING_MESSAGEQUEUE
85
    /* initialize object container - message queue */
86
    {RT_Object_Class_MessageQueue, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_MessageQueue), sizeof(struct rt_messagequeue)},
87
#endif
88
#ifdef RT_USING_MEMHEAP
89
    /* initialize object container - memory heap */
90
    {RT_Object_Class_MemHeap, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_MemHeap), sizeof(struct rt_memheap)},
91
#endif
92
#ifdef RT_USING_MEMPOOL
93
    /* initialize object container - memory pool */
94
    {RT_Object_Class_MemPool, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_MemPool), sizeof(struct rt_mempool)},
95 96
#endif
#ifdef RT_USING_DEVICE
97
    /* initialize object container - device */
98
    {RT_Object_Class_Device, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Device), sizeof(struct rt_device)},
99
#endif
100
    /* initialize object container - timer */
101
    {RT_Object_Class_Timer, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Timer), sizeof(struct rt_timer)},
102
#ifdef RT_USING_MODULE
103
    /* initialize object container - module */
104
    {RT_Object_Class_Module, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Module), sizeof(struct rt_dlmodule)},
105 106
#endif
};
107 108

#ifdef RT_USING_HOOK
D
dzzxzz 已提交
109 110 111 112 113
static void (*rt_object_attach_hook)(struct rt_object *object);
static void (*rt_object_detach_hook)(struct rt_object *object);
void (*rt_object_trytake_hook)(struct rt_object *object);
void (*rt_object_take_hook)(struct rt_object *object);
void (*rt_object_put_hook)(struct rt_object *object);
114 115 116 117

/**
 * @addtogroup Hook
 */
D
dzzxzz 已提交
118

D
dogandog 已提交
119
/**@{*/
120 121 122 123

/**
 * This function will set a hook function, which will be invoked when object
 * attaches to kernel object system.
B
bernard.xiong 已提交
124
 *
125 126
 * @param hook the hook function
 */
D
dzzxzz 已提交
127
void rt_object_attach_sethook(void (*hook)(struct rt_object *object))
128
{
129
    rt_object_attach_hook = hook;
130 131 132 133 134
}

/**
 * This function will set a hook function, which will be invoked when object
 * detaches from kernel object system.
B
bernard.xiong 已提交
135
 *
136 137
 * @param hook the hook function
 */
D
dzzxzz 已提交
138
void rt_object_detach_sethook(void (*hook)(struct rt_object *object))
139
{
140
    rt_object_detach_hook = hook;
141 142 143 144 145
}

/**
 * This function will set a hook function, which will be invoked when object
 * is taken from kernel object system.
B
bernard.xiong 已提交
146
 *
B
bernard.xiong@gmail.com 已提交
147
 * The object is taken means:
148 149
 * semaphore - semaphore is taken by thread
 * mutex - mutex is taken by thread
B
bernard.xiong 已提交
150
 * event - event is received by thread
151 152
 * mailbox - mail is received by thread
 * message queue - message is received by thread
B
bernard.xiong 已提交
153
 *
154 155
 * @param hook the hook function
 */
D
dzzxzz 已提交
156
void rt_object_trytake_sethook(void (*hook)(struct rt_object *object))
157
{
158
    rt_object_trytake_hook = hook;
159 160 161 162 163
}

/**
 * This function will set a hook function, which will be invoked when object
 * have been taken from kernel object system.
B
bernard.xiong 已提交
164
 *
B
bernard.xiong@gmail.com 已提交
165
 * The object have been taken means:
166 167
 * semaphore - semaphore have been taken by thread
 * mutex - mutex have been taken by thread
B
bernard.xiong 已提交
168
 * event - event have been received by thread
169 170 171
 * mailbox - mail have been received by thread
 * message queue - message have been received by thread
 * timer - timer is started
B
bernard.xiong 已提交
172
 *
173 174
 * @param hook the hook function
 */
D
dzzxzz 已提交
175
void rt_object_take_sethook(void (*hook)(struct rt_object *object))
176
{
177
    rt_object_take_hook = hook;
178 179 180 181 182
}

/**
 * This function will set a hook function, which will be invoked when object
 * is put to kernel object system.
B
bernard.xiong 已提交
183
 *
184 185
 * @param hook the hook function
 */
D
dzzxzz 已提交
186
void rt_object_put_sethook(void (*hook)(struct rt_object *object))
187
{
188
    rt_object_put_hook = hook;
189 190
}

D
dogandog 已提交
191
/**@}*/
192 193 194 195 196
#endif

/**
 * @ingroup SystemInit
 *
B
bernard.xiong@gmail.com 已提交
197
 * This function will initialize system object management.
198
 *
B
bernard.xiong@gmail.com 已提交
199 200
 * @deprecated since 0.3.0, this function does not need to be invoked
 * in the system initialization.
201 202 203 204 205 206 207 208
 */
void rt_system_object_init(void)
{
}

/**
 * @addtogroup KernelObject
 */
D
dzzxzz 已提交
209

D
dogandog 已提交
210
/**@{*/
211

212 213
/**
 * This function will return the specified type of object information.
B
Bernard Xiong 已提交
214
 *
215 216 217
 * @param type the type of object, which can be 
 *             RT_Object_Class_Thread/Semaphore/Mutex... etc
 *
218 219
 * @return the object type information or RT_NULL
 */
220 221
struct rt_object_information *
rt_object_get_information(enum rt_object_class_type type)
222
{
223
    int index;
224

225 226
    for (index = 0; index < RT_Object_Info_Unknown; index ++)
        if (rt_object_container[index].type == type) return &rt_object_container[index];
227

228
    return RT_NULL;
229
}
230
RTM_EXPORT(rt_object_get_information);
231

232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293
/**
 * This function will return the length of object list in object container.
 *
 * @param type the type of object, which can be 
 *             RT_Object_Class_Thread/Semaphore/Mutex... etc
 * @return the length of object list
 */
int rt_object_get_length(enum rt_object_class_type type)
{
    int count = 0;
    rt_ubase_t level;
    struct rt_list_node *node = RT_NULL;
    struct rt_object_information *information = RT_NULL;

    information = rt_object_get_information((enum rt_object_class_type)type);
    if (information == RT_NULL) return 0;

    level = rt_hw_interrupt_disable();
    /* get the count of objects */
    rt_list_for_each(node, &(information->object_list))
    {
        count ++;
    }
    rt_hw_interrupt_enable(level);

    return count;
}
RTM_EXPORT(rt_object_get_length);

/**
 * This function will copy the object pointer of the specified type, 
 * with the maximum size specified by maxlen.
 *
 * @param type the type of object, which can be 
 *             RT_Object_Class_Thread/Semaphore/Mutex... etc
 * @param pointers the pointers will be saved to
 * @param maxlen the maximum number of pointers can be saved
 *
 * @return the copied number of object pointers
 */
int rt_object_get_pointers(enum rt_object_class_type type, rt_object_t *pointers, int maxlen)
{
    int index = 0;
    rt_ubase_t level;

    struct rt_object *object;
    struct rt_list_node *node = RT_NULL;
    struct rt_object_information *information = RT_NULL;

    if (maxlen <= 0) return 0;

    information = rt_object_get_information((enum rt_object_class_type)type);
    if (information == RT_NULL) return 0;

    level = rt_hw_interrupt_disable();
    /* retrieve pointer of object */
    rt_list_for_each(node, &(information->object_list))
    {
        object = rt_list_entry(node, struct rt_object, list);

        pointers[index] = object;
        index ++;
294 295

        if (index >= maxlen) break;
296 297 298 299 300 301 302
    }
    rt_hw_interrupt_enable(level);

    return index;
}
RTM_EXPORT(rt_object_get_pointers);

303
/**
304 305
 * This function will initialize an object and add it to object system
 * management.
306 307 308
 *
 * @param object the specified object to be initialized.
 * @param type the object type.
B
bernard.xiong@gmail.com 已提交
309
 * @param name the object name. In system, the object's name must be unique.
310
 */
311 312 313
void rt_object_init(struct rt_object         *object,
                    enum rt_object_class_type type,
                    const char               *name)
314
{
315
    register rt_base_t temp;
316
    struct rt_list_node *node = RT_NULL;
317
    struct rt_object_information *information;
318 319 320
#ifdef RT_USING_MODULE
    struct rt_dlmodule *module = dlmodule_self();
#endif
321

322
    /* get object information */
323 324
    information = rt_object_get_information(type);
    RT_ASSERT(information != RT_NULL);
325

326 327
    /* check object type to avoid re-initialization */

328 329 330 331 332 333 334 335 336 337
    /* enter critical */
    rt_enter_critical();
    /* try to find object */
    for (node  = information->object_list.next;
            node != &(information->object_list);
            node  = node->next)
    {
        struct rt_object *obj;

        obj = rt_list_entry(node, struct rt_object, list);
338 339 340 341
        if (obj) /* skip warning when disable debug */
        {
            RT_ASSERT(obj != object);
        }
342 343 344 345 346
    }
    /* leave critical */
    rt_exit_critical();

    /* initialize object's parameters */
347 348 349 350
    /* set object type to static */
    object->type = type | RT_Object_Class_Static;
    /* copy name */
    rt_strncpy(object->name, name, RT_NAME_MAX);
351

352
    RT_OBJECT_HOOK_CALL(rt_object_attach_hook, (object));
353

354 355
    /* lock interrupt */
    temp = rt_hw_interrupt_disable();
356

357 358 359 360 361 362 363 364 365 366 367 368
#ifdef RT_USING_MODULE
    if (module)
    {
        rt_list_insert_after(&(module->object_list), &(object->list));
        object->module_id = (void *)module;
    }
    else
#endif
    {
        /* insert object into information object list */
        rt_list_insert_after(&(information->object_list), &(object->list));
    }
369

370 371
    /* unlock interrupt */
    rt_hw_interrupt_enable(temp);
372 373 374 375 376 377 378 379 380 381
}

/**
 * This function will detach a static object from object system,
 * and the memory of static object is not freed.
 *
 * @param object the specified object to be detached.
 */
void rt_object_detach(rt_object_t object)
{
382
    register rt_base_t temp;
383

384 385
    /* object check */
    RT_ASSERT(object != RT_NULL);
386

387
    RT_OBJECT_HOOK_CALL(rt_object_detach_hook, (object));
388

389 390 391
    /* reset object type */
    object->type = 0;

392 393
    /* lock interrupt */
    temp = rt_hw_interrupt_disable();
394

395 396
    /* remove from old list */
    rt_list_remove(&(object->list));
397

398 399
    /* unlock interrupt */
    rt_hw_interrupt_enable(temp);
400 401 402 403 404 405 406 407 408 409 410
}

#ifdef RT_USING_HEAP
/**
 * This function will allocate an object from object system
 *
 * @param type the type of object
 * @param name the object name. In system, the object's name must be unique.
 *
 * @return object
 */
D
dzzxzz 已提交
411
rt_object_t rt_object_allocate(enum rt_object_class_type type, const char *name)
412
{
413 414 415
    struct rt_object *object;
    register rt_base_t temp;
    struct rt_object_information *information;
416 417 418
#ifdef RT_USING_MODULE
    struct rt_dlmodule *module = dlmodule_self();
#endif
419

420
    RT_DEBUG_NOT_IN_INTERRUPT;
421

422
    /* get object information */
423 424
    information = rt_object_get_information(type);
    RT_ASSERT(information != RT_NULL);
425

B
Bernard Xiong 已提交
426
    object = (struct rt_object *)RT_KERNEL_MALLOC(information->object_size);
427 428 429 430 431
    if (object == RT_NULL)
    {
        /* no memory can be allocated */
        return RT_NULL;
    }
B
Bernard Xiong 已提交
432

433 434 435
    /* clean memory data of object */
    rt_memset(object, 0x0, information->object_size);

436
    /* initialize object's parameters */
437

438 439
    /* set object type */
    object->type = type;
440

441 442
    /* set object flag */
    object->flag = 0;
qiuyiuestc's avatar
qiuyiuestc 已提交
443

444 445
    /* copy name */
    rt_strncpy(object->name, name, RT_NAME_MAX);
446

447
    RT_OBJECT_HOOK_CALL(rt_object_attach_hook, (object));
448

449 450
    /* lock interrupt */
    temp = rt_hw_interrupt_disable();
451

452 453 454 455 456 457 458 459 460 461 462 463
#ifdef RT_USING_MODULE
    if (module)
    {
        rt_list_insert_after(&(module->object_list), &(object->list));
        object->module_id = (void *)module;
    }
    else
#endif
    {
        /* insert object into information object list */
        rt_list_insert_after(&(information->object_list), &(object->list));
    }
464

465 466
    /* unlock interrupt */
    rt_hw_interrupt_enable(temp);
467

468 469
    /* return object */
    return object;
470 471 472 473 474 475 476 477 478
}

/**
 * This function will delete an object and release object memory.
 *
 * @param object the specified object to be deleted.
 */
void rt_object_delete(rt_object_t object)
{
479
    register rt_base_t temp;
480

481 482 483
    /* object check */
    RT_ASSERT(object != RT_NULL);
    RT_ASSERT(!(object->type & RT_Object_Class_Static));
484

485
    RT_OBJECT_HOOK_CALL(rt_object_detach_hook, (object));
486

487 488 489
    /* reset object type */
    object->type = 0;

490 491
    /* lock interrupt */
    temp = rt_hw_interrupt_disable();
492

493 494
    /* remove from old list */
    rt_list_remove(&(object->list));
495

496 497
    /* unlock interrupt */
    rt_hw_interrupt_enable(temp);
498

499 500
    /* free the memory of object */
    RT_KERNEL_FREE(object);
501 502 503 504 505 506 507 508 509 510
}
#endif

/**
 * This function will judge the object is system object or not.
 * Normally, the system object is a static object and the type
 * of object set to RT_Object_Class_Static.
 *
 * @param object the specified object to be judged.
 *
511
 * @return RT_TRUE if a system object, RT_FALSE for others.
512
 */
513
rt_bool_t rt_object_is_systemobject(rt_object_t object)
514
{
515 516
    /* object check */
    RT_ASSERT(object != RT_NULL);
517

518 519
    if (object->type & RT_Object_Class_Static)
        return RT_TRUE;
520

521
    return RT_FALSE;
522 523
}

524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539
/**
 * This function will return the type of object without
 * RT_Object_Class_Static flag.
 *
 * @param object the specified object to be get type.
 *
 * @return the type of object.
 */
rt_uint8_t rt_object_get_type(rt_object_t object)
{
    /* object check */
    RT_ASSERT(object != RT_NULL);

    return object->type & ~RT_Object_Class_Static;
}

540 541 542 543 544 545 546 547 548 549
/**
 * This function will find specified name object from object
 * container.
 *
 * @param name the specified name of object.
 * @param type the type of object
 *
 * @return the found object or RT_NULL if there is no this object
 * in object container.
 *
B
bernard.xiong@gmail.com 已提交
550
 * @note this function shall not be invoked in interrupt status.
551
 */
D
dzzxzz 已提交
552
rt_object_t rt_object_find(const char *name, rt_uint8_t type)
553
{
B
Bernard Xiong 已提交
554 555
    struct rt_object *object = RT_NULL;
    struct rt_list_node *node = RT_NULL;
556
    struct rt_object_information *information = RT_NULL;
557

558 559
    information = rt_object_get_information((enum rt_object_class_type)type);

560
    /* parameter check */
561
    if ((name == RT_NULL) || (information == RT_NULL)) return RT_NULL;
562 563

    /* which is invoke in interrupt status */
564 565
    RT_DEBUG_NOT_IN_INTERRUPT;

566 567 568 569
    /* enter critical */
    rt_enter_critical();

    /* try to find object */
570
    rt_list_for_each(node, &(information->object_list))
571 572 573 574 575 576 577 578 579 580 581 582 583 584 585
    {
        object = rt_list_entry(node, struct rt_object, list);
        if (rt_strncmp(object->name, name, RT_NAME_MAX) == 0)
        {
            /* leave critical */
            rt_exit_critical();

            return object;
        }
    }

    /* leave critical */
    rt_exit_critical();

    return RT_NULL;
586
}
D
dzzxzz 已提交
587

D
dogandog 已提交
588
/**@}*/