| Index: emcore/trunk/execimage.c | 
| — | — | @@ -25,6 +25,7 @@ | 
| 26 | 26 | #include "console.h" | 
| 27 | 27 | #include "execimage.h" | 
| 28 | 28 | #include "mmu.h" | 
|  | 29 | +#include "malloc.h" | 
| 29 | 30 |  | 
| 30 | 31 |  | 
| 31 | 32 | struct scheduler_thread* execimage(void* image, bool copy) | 
| — | — | @@ -37,11 +38,13 @@ | 
| 38 | 39 | header->signature[0], header->signature[1], header->signature[2], | 
| 39 | 40 | header->signature[3], header->signature[4], header->signature[5], | 
| 40 | 41 | header->signature[6], header->signature[7]); | 
|  | 42 | +        if (!copy) free(image); | 
| 41 | 43 | return NULL; | 
| 42 | 44 | } | 
| 43 | 45 | if (header->version != EMCOREAPP_HEADER_VERSION) | 
| 44 | 46 | { | 
| 45 | 47 | cprintf(CONSOLE_BOOT, "execimage: Unsupported version! (%08X)\n", header->version); | 
|  | 48 | +        if (!copy) free(image); | 
| 46 | 49 | return NULL; | 
| 47 | 50 | } | 
| 48 | 51 | off_t offset = header->textstart; | 
| — | — | @@ -52,7 +55,10 @@ | 
| 53 | 56 | off_t relocstart = header->relocstart - offset; | 
| 54 | 57 | uint32_t reloccount = header->reloccount; | 
| 55 | 58 | bool compressed = header->flags & EMCOREAPP_FLAG_COMPRESSED; | 
| 56 |  | -    size_t finalsize = textsize + bsssize + stacksize;
 | 
|  | 59 | +	bool lib = header->flags & EMCOREAPP_FLAG_LIBRARY; | 
|  | 60 | +    size_t finalsize; | 
|  | 61 | +    if (lib) finalsize = textsize + bsssize; | 
|  | 62 | +    else finalsize = textsize + bsssize + stacksize; | 
| 57 | 63 | size_t datasize = relocstart + reloccount * 4; | 
| 58 | 64 | size_t tempsize = MAX(finalsize, datasize); | 
| 59 | 65 | if (compressed) | 
| — | — | @@ -61,6 +67,7 @@ | 
| 62 | 68 | if (!alloc) | 
| 63 | 69 | { | 
| 64 | 70 | cprintf(CONSOLE_BOOT, "execimage: Out of memory!\n"); | 
|  | 71 | +            if (!copy) free(image); | 
| 65 | 72 | return NULL; | 
| 66 | 73 | } | 
| 67 | 74 | uint32_t decompsize; | 
| — | — | @@ -67,9 +74,11 @@ | 
| 68 | 75 | if (ucl_decompress(image + offset, datasize, alloc, &decompsize)) | 
| 69 | 76 | { | 
| 70 | 77 | cprintf(CONSOLE_BOOT, "execimage: Decompression failed!\n"); | 
|  | 78 | +            if (!copy) free(image); | 
| 71 | 79 | free(alloc); | 
| 72 | 80 | return NULL; | 
| 73 | 81 | } | 
|  | 82 | +        if (!copy) free(image); | 
| 74 | 83 | if (datasize != decompsize) | 
| 75 | 84 | { | 
| 76 | 85 | cprintf(CONSOLE_BOOT, "execimage: Decompressed size mismatch!\n"); | 
| — | — | @@ -76,7 +85,6 @@ | 
| 77 | 86 | free(alloc); | 
| 78 | 87 | return NULL; | 
| 79 | 88 | } | 
| 80 |  | -        if (!copy) free(image);
 | 
| 81 | 89 | image = alloc; | 
| 82 | 90 | } | 
| 83 | 91 | else if (copy) | 
| — | — | @@ -93,12 +101,14 @@ | 
| 94 | 102 | else | 
| 95 | 103 | { | 
| 96 | 104 | memcpy(image, image + offset, datasize); | 
| 97 |  | -        image = realloc(image, tempsize);
 | 
| 98 |  | -        if (!image)
 | 
|  | 105 | +        void* newimage = realloc(image, tempsize); | 
|  | 106 | +        if (!newimage) | 
| 99 | 107 | { | 
|  | 108 | +            free(image); | 
| 100 | 109 | cprintf(CONSOLE_BOOT, "execimage: Out of memory!\n"); | 
| 101 | 110 | return NULL; | 
| 102 | 111 | } | 
|  | 112 | +        else image = newimage; | 
| 103 | 113 | } | 
| 104 | 114 | for (; reloccount; reloccount--, relocstart += 4) | 
| 105 | 115 | { | 
| — | — | @@ -109,10 +119,18 @@ | 
| 110 | 120 | if (tempsize != finalsize) realloc(image, finalsize); /* Can only shrink => safe */ | 
| 111 | 121 | clean_dcache(); | 
| 112 | 122 | invalidate_icache(); | 
| 113 |  | -    struct scheduler_thread* thread = thread_create(NULL, NULL, image + entrypoint,
 | 
| 114 |  | -                                                    image + textsize + bsssize, stacksize,
 | 
| 115 |  | -                                                    USER_THREAD, 127, false);
 | 
| 116 |  | -    reownalloc(image, thread);
 | 
| 117 |  | -    thread_resume(thread);
 | 
|  | 123 | +    struct scheduler_thread* thread; | 
|  | 124 | +    if (lib) thread = (struct scheduler_thread*)library_register(image, image + entrypoint); | 
|  | 125 | +    else | 
|  | 126 | +    { | 
|  | 127 | +        thread = thread_create(NULL, NULL, image + entrypoint, image + textsize + bsssize, | 
|  | 128 | +                               stacksize, USER_THREAD, 127, false); | 
|  | 129 | +        if (thread) | 
|  | 130 | +        { | 
|  | 131 | +            reownalloc(image, thread); | 
|  | 132 | +            thread_resume(thread); | 
|  | 133 | +        } | 
|  | 134 | +        else free(image); | 
|  | 135 | +    } | 
| 118 | 136 | return thread; | 
| 119 | 137 | } | 
| Index: emcore/trunk/execimage.h | 
| — | — | @@ -50,6 +50,7 @@ | 
| 51 | 51 | }; | 
| 52 | 52 |  | 
| 53 | 53 | #define EMCOREAPP_FLAG_COMPRESSED 0x00000001 | 
|  | 54 | +#define EMCOREAPP_FLAG_LIBRARY    0x00000002 | 
| 54 | 55 |  | 
| 55 | 56 |  | 
| 56 | 57 | #ifndef _TOOL | 
| Index: emcore/trunk/export/emcorelib.h | 
| — | — | @@ -0,0 +1,23 @@ | 
|  | 2 | +#include "syscallwrappers.h" | 
|  | 3 | + | 
|  | 4 | + | 
|  | 5 | +#define EMCORE_LIB_HEADER(libidentifier, libversion, initfunc, shutdownfunc, apipointer)          \ | 
|  | 6 | +    struct emcore_syscall_table* __emcore_syscall;                                                \ | 
|  | 7 | +    int __emcore_lib_init()                                                                       \ | 
|  | 8 | +    {                                                                                             \ | 
|  | 9 | +        asm volatile("swi\t2\n\tldr\tr1, =__emcore_syscall\n\tstr\tr0, [r1]\n\t"                  \ | 
|  | 10 | +                 ::: "r0", "r1", "r2", "r3", "r12", "lr", "cc", "memory");                        \ | 
|  | 11 | +        if (__embios_syscall->table_version < EMCORE_API_VERSION                                  \ | 
|  | 12 | +         || __embios_syscall->table_minversion > EMCORE_API_VERSION)                              \ | 
|  | 13 | +             return 0x80000000;                                                                   \ | 
|  | 14 | +        if (initfunc) return initfunc();                                                          \ | 
|  | 15 | +    }                                                                                             \ | 
|  | 16 | +    struct emcorelib_header __attribute__((section(".emcoreentrypoint"))) __emcore_entrypoint()   \ | 
|  | 17 | +    {                                                                                             \ | 
|  | 18 | +        .headerversion = EMCORELIB_HEADER_VERSION,                                                \ | 
|  | 19 | +        .identifier = libidentifier,                                                              \ | 
|  | 20 | +        .version = libversion,                                                                    \ | 
|  | 21 | +        .initfunc = __emcore_lib_init,                                                            \ | 
|  | 22 | +        .shutdownfunc = shutdownfunc,                                                             \ | 
|  | 23 | +        .api = apipointer                                                                         \ | 
|  | 24 | +    }; | 
| Index: emcore/trunk/SOURCES | 
| — | — | @@ -69,6 +69,7 @@ | 
| 70 | 70 | init.c | 
| 71 | 71 | util.c | 
| 72 | 72 | malloc.c | 
|  | 73 | +library.c | 
| 73 | 74 | #ifdef HAVE_LCD | 
| 74 | 75 | drawing.S | 
| 75 | 76 | lcdconsole.c | 
| Index: emcore/trunk/library.c | 
| — | — | @@ -0,0 +1,243 @@ | 
|  | 2 | +// | 
|  | 3 | +// | 
|  | 4 | +//    Copyright 2010 TheSeven | 
|  | 5 | +// | 
|  | 6 | +// | 
|  | 7 | +//    This file is part of emCORE. | 
|  | 8 | +// | 
|  | 9 | +//    emCORE is free software: you can redistribute it and/or | 
|  | 10 | +//    modify it under the terms of the GNU General Public License as | 
|  | 11 | +//    published by the Free Software Foundation, either version 2 of the | 
|  | 12 | +//    License, or (at your option) any later version. | 
|  | 13 | +// | 
|  | 14 | +//    emCORE is distributed in the hope that it will be useful, | 
|  | 15 | +//    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | 16 | +//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | 
|  | 17 | +//    See the GNU General Public License for more details. | 
|  | 18 | +// | 
|  | 19 | +//    You should have received a copy of the GNU General Public License along | 
|  | 20 | +//    with emCORE.  If not, see <http://www.gnu.org/licenses/>. | 
|  | 21 | +// | 
|  | 22 | +// | 
|  | 23 | + | 
|  | 24 | + | 
|  | 25 | +#include "global.h" | 
|  | 26 | +#include "library.h" | 
|  | 27 | +#include "malloc.h" | 
|  | 28 | +#include "execimage.h" | 
|  | 29 | +#include "thread.h" | 
|  | 30 | +#ifdef HAVE_STORAGE | 
|  | 31 | +#include "file.h" | 
|  | 32 | +#include "dir.h" | 
|  | 33 | +#endif | 
|  | 34 | +#ifdef HAVE_BOOTFLASH | 
|  | 35 | +#include "bootflash.h" | 
|  | 36 | +#endif | 
|  | 37 | +#ifdef HAVE_BUTTON | 
|  | 38 | +#include "button.h" | 
|  | 39 | +#endif | 
|  | 40 | + | 
|  | 41 | + | 
|  | 42 | +struct library_handle* library_list_head; | 
|  | 43 | +struct mutex library_mutex; | 
|  | 44 | + | 
|  | 45 | + | 
|  | 46 | +struct library_handle* library_register(void* image, struct emcorelib_header* header) | 
|  | 47 | +{ | 
|  | 48 | +    mutex_lock(&library_mutex, TIMEOUT_BLOCK); | 
|  | 49 | +    struct library_handle* h; | 
|  | 50 | +    for (h = library_list_head; h; h = h->next) | 
|  | 51 | +        if (h->lib->identifier == header->identifier && h->lib->version == header->version) | 
|  | 52 | +        { | 
|  | 53 | +            mutex_unlock(&library_mutex); | 
|  | 54 | +            return NULL; | 
|  | 55 | +        } | 
|  | 56 | +    if (header->initfunc && header->initfunc() < 0) | 
|  | 57 | +    { | 
|  | 58 | +        mutex_unlock(&library_mutex); | 
|  | 59 | +        return NULL; | 
|  | 60 | +    } | 
|  | 61 | +    struct library_handle* handle = (struct library_handle*)malloc(sizeof(struct library_handle)); | 
|  | 62 | +    memset(handle, 0, sizeof(struct library_handle)); | 
|  | 63 | +    reownalloc(handle, (struct scheduler_thread*)handle); | 
|  | 64 | +    reownalloc(image, (struct scheduler_thread*)handle); | 
|  | 65 | +    handle->next = library_list_head; | 
|  | 66 | +    handle->lib = header; | 
|  | 67 | +    handle->alloc = image; | 
|  | 68 | +    mutex_unlock(&library_mutex); | 
|  | 69 | +    return handle; | 
|  | 70 | +} | 
|  | 71 | + | 
|  | 72 | +int library_unload(struct library_handle* lib) | 
|  | 73 | +{ | 
|  | 74 | +    mutex_lock(&library_mutex, TIMEOUT_BLOCK); | 
|  | 75 | +    int i; | 
|  | 76 | +    bool found = false; | 
|  | 77 | +    struct library_handle* h; | 
|  | 78 | +    for (h = library_list_head; h; h = h->next) | 
|  | 79 | +        if (h == lib) | 
|  | 80 | +        { | 
|  | 81 | +            found = true; | 
|  | 82 | +            break; | 
|  | 83 | +        } | 
|  | 84 | +    if (!found) | 
|  | 85 | +    { | 
|  | 86 | +        mutex_unlock(&library_mutex); | 
|  | 87 | +        return -1; | 
|  | 88 | +    } | 
|  | 89 | +    for (i = 0; i < ARRAYLEN(lib->users); i++) | 
|  | 90 | +        if (lib->users[i]) | 
|  | 91 | +        { | 
|  | 92 | +            mutex_unlock(&library_mutex); | 
|  | 93 | +            return -2; | 
|  | 94 | +        } | 
|  | 95 | +    if (lib->moreusers) | 
|  | 96 | +        for (i = 0; i < lib->moreusers_size / 4; i++) | 
|  | 97 | +            if (lib->moreusers[i]) | 
|  | 98 | +            { | 
|  | 99 | +                mutex_unlock(&library_mutex); | 
|  | 100 | +                return -2; | 
|  | 101 | +            } | 
|  | 102 | +    if (lib->lib->shutdownfunc && lib->lib->shutdownfunc() < 0) | 
|  | 103 | +    { | 
|  | 104 | +        mutex_unlock(&library_mutex); | 
|  | 105 | +        return -3; | 
|  | 106 | +    } | 
|  | 107 | +    if (library_list_head == lib) library_list_head = lib->next; | 
|  | 108 | +    else | 
|  | 109 | +        for (h = library_list_head; h; h = h->next) | 
|  | 110 | +            if (h == lib) | 
|  | 111 | +            { | 
|  | 112 | +                h->next = lib->next; | 
|  | 113 | +                break; | 
|  | 114 | +            } | 
|  | 115 | +    library_release_all_of_thread((struct scheduler_thread*)lib); | 
|  | 116 | +#ifdef HAVE_STORAGE | 
|  | 117 | +    close_all_of_process((struct scheduler_thread*)lib); | 
|  | 118 | +    closedir_all_of_process((struct scheduler_thread*)lib); | 
|  | 119 | +#endif | 
|  | 120 | +#ifdef HAVE_BUTTON | 
|  | 121 | +    button_unregister_all_of_thread((struct scheduler_thread*)lib); | 
|  | 122 | +#endif | 
|  | 123 | +    free_all_of_thread((struct scheduler_thread*)lib); | 
|  | 124 | +    mutex_unlock(&library_mutex); | 
|  | 125 | +    return 0; | 
|  | 126 | +} | 
|  | 127 | + | 
|  | 128 | +struct emcorelib_header* get_library_ext(uint32_t identifier, uint32_t minversion, | 
|  | 129 | +                                         uint32_t maxversion, enum library_sourcetype sourcetype, | 
|  | 130 | +                                         void* source, struct scheduler_thread* owner) | 
|  | 131 | +{ | 
|  | 132 | +    int i; | 
|  | 133 | +    int version = minversion - 1; | 
|  | 134 | +    struct library_handle* h; | 
|  | 135 | +    struct library_handle* best = NULL; | 
|  | 136 | +    mutex_lock(&library_mutex, TIMEOUT_BLOCK); | 
|  | 137 | +    for (h = library_list_head; h; h = h->next) | 
|  | 138 | +        if (h->lib->identifier == identifier && | 
|  | 139 | +            h->lib->version > version && h->lib->version <= maxversion) | 
|  | 140 | +        { | 
|  | 141 | +            best = h; | 
|  | 142 | +            version = h->lib->version; | 
|  | 143 | +            break; | 
|  | 144 | +        } | 
|  | 145 | +    if (!best) | 
|  | 146 | +    { | 
|  | 147 | +        mutex_unlock(&library_mutex); | 
|  | 148 | +        return NULL; | 
|  | 149 | +    } | 
|  | 150 | +    for (i = 0; i < ARRAYLEN(best->users); i++) | 
|  | 151 | +        if (best->users[i] == NULL) | 
|  | 152 | +        { | 
|  | 153 | +            best->users[i] = owner; | 
|  | 154 | +            mutex_unlock(&library_mutex); | 
|  | 155 | +            return best->lib; | 
|  | 156 | +        } | 
|  | 157 | +    if (best->moreusers) | 
|  | 158 | +        for (i = 0; i < best->moreusers_size / 4; i++) | 
|  | 159 | +            if (h->moreusers[i] == NULL) | 
|  | 160 | +                { | 
|  | 161 | +                    h->moreusers[i] = owner; | 
|  | 162 | +                    mutex_unlock(&library_mutex); | 
|  | 163 | +                    return best->lib; | 
|  | 164 | +                } | 
|  | 165 | +    void* newalloc = realloc(best->moreusers, best->moreusers_size + 64); | 
|  | 166 | +    if (!newalloc) | 
|  | 167 | +    { | 
|  | 168 | +        mutex_unlock(&library_mutex); | 
|  | 169 | +        return NULL; | 
|  | 170 | +    } | 
|  | 171 | +    best->moreusers = (void**)newalloc; | 
|  | 172 | +    best->moreusers[best->moreusers_size / 4] = owner; | 
|  | 173 | +    best->moreusers_size += 64; | 
|  | 174 | +    mutex_unlock(&library_mutex); | 
|  | 175 | +    return best->lib; | 
|  | 176 | +} | 
|  | 177 | + | 
|  | 178 | +struct emcorelib_header* get_library(uint32_t identifier, uint32_t minversion, uint32_t maxversion, | 
|  | 179 | +                                     enum library_sourcetype sourcetype, void* source) | 
|  | 180 | +{ | 
|  | 181 | +    return get_library_ext(identifier, minversion, maxversion, sourcetype, source, current_thread); | 
|  | 182 | +} | 
|  | 183 | + | 
|  | 184 | +int release_library_ext(struct emcorelib_header* lib, struct scheduler_thread* owner) | 
|  | 185 | +{ | 
|  | 186 | +    int i; | 
|  | 187 | +    int rc = -2; | 
|  | 188 | +    struct library_handle* h; | 
|  | 189 | +    mutex_lock(&library_mutex, TIMEOUT_BLOCK); | 
|  | 190 | +    for (h = library_list_head; h; h = h->next) | 
|  | 191 | +        if (h->lib == lib) | 
|  | 192 | +        { | 
|  | 193 | +            rc = -1; | 
|  | 194 | +            for (i = 0; i < ARRAYLEN(h->users); i++) | 
|  | 195 | +                if (h->users[i] == owner) | 
|  | 196 | +                { | 
|  | 197 | +                    h->users[i] = NULL; | 
|  | 198 | +                    rc = 0; | 
|  | 199 | +                    break; | 
|  | 200 | +                } | 
|  | 201 | +            if (rc && h->moreusers) | 
|  | 202 | +                for (i = 0; i < h->moreusers_size / 4; i++) | 
|  | 203 | +                    if (h->moreusers[i] == owner) | 
|  | 204 | +                        { | 
|  | 205 | +                            h->moreusers[i] = NULL; | 
|  | 206 | +                            rc = 0; | 
|  | 207 | +                            break; | 
|  | 208 | +                        } | 
|  | 209 | +            break; | 
|  | 210 | +        } | 
|  | 211 | +    mutex_unlock(&library_mutex); | 
|  | 212 | +    return rc; | 
|  | 213 | +} | 
|  | 214 | + | 
|  | 215 | +int release_library(struct emcorelib_header* lib) | 
|  | 216 | +{ | 
|  | 217 | +    return release_library_ext(lib, current_thread); | 
|  | 218 | +} | 
|  | 219 | + | 
|  | 220 | +int library_release_all_of_thread(struct scheduler_thread* thread) | 
|  | 221 | +{ | 
|  | 222 | +    mutex_lock(&library_mutex, TIMEOUT_BLOCK); | 
|  | 223 | +    int i; | 
|  | 224 | +    int released = 0; | 
|  | 225 | +    struct library_handle* h; | 
|  | 226 | +    for (h = library_list_head; h; h = h->next) | 
|  | 227 | +    { | 
|  | 228 | +        for (i = 0; i < ARRAYLEN(h->users); i++) | 
|  | 229 | +            if (h->users[i] == thread) | 
|  | 230 | +            { | 
|  | 231 | +                h->users[i] = NULL; | 
|  | 232 | +                released++; | 
|  | 233 | +            } | 
|  | 234 | +        if (h->moreusers) | 
|  | 235 | +            for (i = 0; i < h->moreusers_size / 4; i++) | 
|  | 236 | +                if (h->moreusers[i] == thread) | 
|  | 237 | +                    { | 
|  | 238 | +                        h->moreusers[i] = NULL; | 
|  | 239 | +                        released++; | 
|  | 240 | +                    } | 
|  | 241 | +    } | 
|  | 242 | +    mutex_unlock(&library_mutex); | 
|  | 243 | +    return released; | 
|  | 244 | +} | 
| Index: emcore/trunk/thread.c | 
| — | — | @@ -27,6 +27,7 @@ | 
| 28 | 28 | #include "panic.h" | 
| 29 | 29 | #include "util.h" | 
| 30 | 30 | #include "malloc.h" | 
|  | 31 | +#include "library.h" | 
| 31 | 32 | #ifdef HAVE_STORAGE | 
| 32 | 33 | #include "dir.h" | 
| 33 | 34 | #include "file.h" | 
| — | — | @@ -470,6 +471,7 @@ | 
| 471 | 472 |  | 
| 472 | 473 | leave_critical_section(mode); | 
| 473 | 474 |  | 
|  | 475 | +    library_release_all_of_thread(thread); | 
| 474 | 476 | #ifdef HAVE_STORAGE | 
| 475 | 477 | close_all_of_process(thread); | 
| 476 | 478 | closedir_all_of_process(thread); | 
| Index: emcore/trunk/library.h | 
| — | — | @@ -0,0 +1,80 @@ | 
|  | 2 | +// | 
|  | 3 | +// | 
|  | 4 | +//    Copyright 2011 TheSeven | 
|  | 5 | +// | 
|  | 6 | +// | 
|  | 7 | +//    This file is part of emCORE. | 
|  | 8 | +// | 
|  | 9 | +//    emCORE is free software: you can redistribute it and/or | 
|  | 10 | +//    modify it under the terms of the GNU General Public License as | 
|  | 11 | +//    published by the Free Software Foundation, either version 2 of the | 
|  | 12 | +//    License, or (at your option) any later version. | 
|  | 13 | +// | 
|  | 14 | +//    emCORE is distributed in the hope that it will be useful, | 
|  | 15 | +//    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | 16 | +//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | 
|  | 17 | +//    See the GNU General Public License for more details. | 
|  | 18 | +// | 
|  | 19 | +//    You should have received a copy of the GNU General Public License along | 
|  | 20 | +//    with emCORE.  If not, see <http://www.gnu.org/licenses/>. | 
|  | 21 | +// | 
|  | 22 | +// | 
|  | 23 | + | 
|  | 24 | + | 
|  | 25 | +#ifndef __LIBRARY_H__ | 
|  | 26 | +#define __LIBRARY_H__ | 
|  | 27 | + | 
|  | 28 | + | 
|  | 29 | +#ifdef _TOOL | 
|  | 30 | +#include <stdint.h> | 
|  | 31 | +#else | 
|  | 32 | +#include "global.h" | 
|  | 33 | +#include "thread.h" | 
|  | 34 | +#endif | 
|  | 35 | + | 
|  | 36 | + | 
|  | 37 | +#define EMCORELIB_HEADER_VERSION 1 | 
|  | 38 | +struct emcorelib_header | 
|  | 39 | +{ | 
|  | 40 | +    uint32_t headerversion; | 
|  | 41 | +    uint32_t identifier; | 
|  | 42 | +	uint32_t version; | 
|  | 43 | +    int (*initfunc)(); | 
|  | 44 | +    int (*shutdownfunc)(); | 
|  | 45 | +    void* api; | 
|  | 46 | +}; | 
|  | 47 | + | 
|  | 48 | +struct library_handle | 
|  | 49 | +{ | 
|  | 50 | +    struct library_handle* next; | 
|  | 51 | +    struct emcorelib_header* lib; | 
|  | 52 | +    void* alloc; | 
|  | 53 | +    void* users[16]; | 
|  | 54 | +    void** moreusers; | 
|  | 55 | +    size_t moreusers_size; | 
|  | 56 | +}; | 
|  | 57 | + | 
|  | 58 | +enum library_sourcetype | 
|  | 59 | +{ | 
|  | 60 | +    LIBSOURCE_RAM_ALLOCED = 1, | 
|  | 61 | +    LIBSOURCE_RAM_NEEDCOPY = 2, | 
|  | 62 | +    LIBSOURCE_BOOTFLASH = 3, | 
|  | 63 | +    LIBSOURCE_FILESYSTEM = 4 | 
|  | 64 | +}; | 
|  | 65 | + | 
|  | 66 | + | 
|  | 67 | +#ifndef _TOOL | 
|  | 68 | +struct library_handle* library_register(void* image, struct emcorelib_header* header); | 
|  | 69 | +int library_unload(struct library_handle* lib); | 
|  | 70 | +struct emcorelib_header* get_library(uint32_t identifier, uint32_t minversion, uint32_t maxversion, | 
|  | 71 | +                                     enum library_sourcetype sourcetype, void* source); | 
|  | 72 | +struct emcorelib_header* get_library_ext(uint32_t identifier, uint32_t minversion, | 
|  | 73 | +                                         uint32_t maxversion, enum library_sourcetype sourcetype, | 
|  | 74 | +                                         void* source, struct scheduler_thread* owner); | 
|  | 75 | +int release_library(struct emcorelib_header* lib); | 
|  | 76 | +int release_library_ext(struct emcorelib_header* lib, struct scheduler_thread* owner); | 
|  | 77 | +int library_release_all_of_thread(struct scheduler_thread* thread); | 
|  | 78 | +#endif | 
|  | 79 | + | 
|  | 80 | + | 
|  | 81 | +#endif |