object.c 16.9 KB
Newer Older
1
/*
mysterywolf's avatar
mysterywolf 已提交
2
 * Copyright (c) 2006-2021, 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
#ifdef RT_USING_MODULE
#include <dlmodule.h>
23
#endif /* RT_USING_MODULE */
24

25
/*
mysterywolf's avatar
mysterywolf 已提交
26
 * define object_info for the number of _object_container items.
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
 */
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. */
58 59 60
#endif
#ifdef RT_USING_HEAP
    RT_Object_Info_Memory,                            /**< The object is a memory. */
61 62 63 64
#endif
    RT_Object_Info_Unknown,                            /**< The object is unknown. */
};

65
#define _OBJ_CONTAINER_LIST_INIT(c)     \
mysterywolf's avatar
mysterywolf 已提交
66 67 68
    {&(_object_container[c].object_list), &(_object_container[c].object_list)}

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

#ifdef RT_USING_HOOK
D
dzzxzz 已提交
117 118 119 120 121
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);
122 123 124 125

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

D
dogandog 已提交
127
/**@{*/
128 129

/**
130 131
 * @brief This function will set a hook function, which will be invoked when object
 *        attaches to kernel object system.
B
bernard.xiong 已提交
132
 *
Nameless-Y's avatar
Nameless-Y 已提交
133
 * @param hook is the hook function.
134
 */
D
dzzxzz 已提交
135
void rt_object_attach_sethook(void (*hook)(struct rt_object *object))
136
{
137
    rt_object_attach_hook = hook;
138 139 140
}

/**
141 142
 * @brief This function will set a hook function, which will be invoked when object
 *        detaches from kernel object system.
B
bernard.xiong 已提交
143
 *
Nameless-Y's avatar
Nameless-Y 已提交
144
 * @param hook is the hook function
145
 */
D
dzzxzz 已提交
146
void rt_object_detach_sethook(void (*hook)(struct rt_object *object))
147
{
148
    rt_object_detach_hook = hook;
149 150 151
}

/**
152 153
 * @brief This function will set a hook function, which will be invoked when object
 *        is taken from kernel object system.
B
bernard.xiong 已提交
154
 *
155 156 157 158 159 160
 *        The object is taken means:
 *            semaphore - semaphore is taken by thread
 *            mutex - mutex is taken by thread
 *            event - event is received by thread
 *            mailbox - mail is received by thread
 *            message queue - message is received by thread
B
bernard.xiong 已提交
161
 *
Nameless-Y's avatar
Nameless-Y 已提交
162
 * @param hook is the hook function.
163
 */
D
dzzxzz 已提交
164
void rt_object_trytake_sethook(void (*hook)(struct rt_object *object))
165
{
166
    rt_object_trytake_hook = hook;
167 168 169
}

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

/**
189 190
 * @brief This function will set a hook function, which will be invoked when object
 *        is put to kernel object system.
B
bernard.xiong 已提交
191
 *
Nameless-Y's avatar
Nameless-Y 已提交
192
 * @param hook is the hook function
193
 */
D
dzzxzz 已提交
194
void rt_object_put_sethook(void (*hook)(struct rt_object *object))
195
{
196
    rt_object_put_hook = hook;
197 198
}

D
dogandog 已提交
199
/**@}*/
200
#endif /* RT_USING_HOOK */
201 202 203 204

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

D
dogandog 已提交
206
/**@{*/
207

208
/**
209
 * @brief This function will return the specified type of object information.
B
Bernard Xiong 已提交
210
 *
Nameless-Y's avatar
Nameless-Y 已提交
211
 * @param type is the type of object, which can be
212 213
 *             RT_Object_Class_Thread/Semaphore/Mutex... etc
 *
214 215
 * @return the object type information or RT_NULL
 */
216 217
struct rt_object_information *
rt_object_get_information(enum rt_object_class_type type)
218
{
219
    int index;
220

221
    for (index = 0; index < RT_Object_Info_Unknown; index ++)
mysterywolf's avatar
mysterywolf 已提交
222
        if (_object_container[index].type == type) return &_object_container[index];
223

224
    return RT_NULL;
225
}
226
RTM_EXPORT(rt_object_get_information);
227

228
/**
229
 * @brief This function will return the length of object list in object container.
230
 *
Nameless-Y's avatar
Nameless-Y 已提交
231
 * @param type is the type of object, which can be
232
 *             RT_Object_Class_Thread/Semaphore/Mutex... etc
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
 * @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);

/**
259 260
 * @brief This function will copy the object pointer of the specified type,
 *        with the maximum size specified by maxlen.
261
 *
Nameless-Y's avatar
Nameless-Y 已提交
262
 * @param type is the type of object, which can be
263
 *             RT_Object_Class_Thread/Semaphore/Mutex... etc
264
 *
Nameless-Y's avatar
Nameless-Y 已提交
265
 * @param pointers is the pointer will be saved to.
266
 *
Nameless-Y's avatar
Nameless-Y 已提交
267
 * @param maxlen is the maximum number of pointers can be saved.
268
 *
Nameless-Y's avatar
Nameless-Y 已提交
269
 * @return the copied number of object pointers.
270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292
 */
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 ++;
293 294

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

    return index;
}
RTM_EXPORT(rt_object_get_pointers);

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

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

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

329 330 331 332 333 334 335 336 337 338
    /* 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);
339 340 341 342
        if (obj) /* skip warning when disable debug */
        {
            RT_ASSERT(obj != object);
        }
343 344 345 346 347
    }
    /* leave critical */
    rt_exit_critical();

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

353
    RT_OBJECT_HOOK_CALL(rt_object_attach_hook, (object));
354

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

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

371 372
    /* unlock interrupt */
    rt_hw_interrupt_enable(temp);
373 374 375
}

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

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

388
    RT_OBJECT_HOOK_CALL(rt_object_detach_hook, (object));
389

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

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

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

399 400
    /* unlock interrupt */
    rt_hw_interrupt_enable(temp);
401 402 403 404
}

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

422
    RT_DEBUG_NOT_IN_INTERRUPT;
423

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

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

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

438
    /* initialize object's parameters */
439

440 441
    /* set object type */
    object->type = type;
442

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

446 447
    /* copy name */
    rt_strncpy(object->name, name, RT_NAME_MAX);
448

449
    RT_OBJECT_HOOK_CALL(rt_object_attach_hook, (object));
450

451 452
    /* lock interrupt */
    temp = rt_hw_interrupt_disable();
453

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

467 468
    /* unlock interrupt */
    rt_hw_interrupt_enable(temp);
469

470 471
    /* return object */
    return object;
472 473 474
}

/**
475
 * @brief This function will delete an object and release object memory.
476
 *
Nameless-Y's avatar
Nameless-Y 已提交
477
 * @param object is the specified object to be deleted.
478 479 480
 */
void rt_object_delete(rt_object_t object)
{
481
    register rt_base_t temp;
482

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

487
    RT_OBJECT_HOOK_CALL(rt_object_detach_hook, (object));
488

489
    /* reset object type */
490
    object->type = RT_Object_Class_Null;
491

492 493
    /* lock interrupt */
    temp = rt_hw_interrupt_disable();
494

495 496
    /* remove from old list */
    rt_list_remove(&(object->list));
497

498 499
    /* unlock interrupt */
    rt_hw_interrupt_enable(temp);
500

501 502
    /* free the memory of object */
    RT_KERNEL_FREE(object);
503
}
504
#endif /* RT_USING_HEAP */
505 506

/**
507 508 509 510
 * @brief This function will judge the object is system object or not.
 *
 * @note  Normally, the system object is a static object and the type
 *        of object set to RT_Object_Class_Static.
511
 *
Nameless-Y's avatar
Nameless-Y 已提交
512
 * @param object is the specified object to be judged.
513
 *
514
 * @return RT_TRUE if a system object, RT_FALSE for others.
515
 */
516
rt_bool_t rt_object_is_systemobject(rt_object_t object)
517
{
518 519
    /* object check */
    RT_ASSERT(object != RT_NULL);
520

521 522
    if (object->type & RT_Object_Class_Static)
        return RT_TRUE;
523

524
    return RT_FALSE;
525 526
}

527
/**
528 529
 * @brief This function will return the type of object without
 *        RT_Object_Class_Static flag.
530
 *
Nameless-Y's avatar
Nameless-Y 已提交
531
 * @param object is the specified object to be get type.
532 533 534 535 536 537 538 539 540 541 542
 *
 * @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;
}

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

562 563
    information = rt_object_get_information((enum rt_object_class_type)type);

564
    /* parameter check */
565
    if ((name == RT_NULL) || (information == RT_NULL)) return RT_NULL;
566 567

    /* which is invoke in interrupt status */
568 569
    RT_DEBUG_NOT_IN_INTERRUPT;

570 571 572 573
    /* enter critical */
    rt_enter_critical();

    /* try to find object */
574
    rt_list_for_each(node, &(information->object_list))
575 576 577 578 579 580 581 582 583 584 585 586 587 588 589
    {
        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;
590
}
D
dzzxzz 已提交
591

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