Changeset c621f4aa in mainline for kernel/generic/src/mm/frame.c


Ignore:
Timestamp:
2010-07-25T10:11:13Z (15 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
377cce8
Parents:
24a2517 (diff), a2da43c (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge with mainline.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • kernel/generic/src/mm/frame.c

    r24a2517 rc621f4aa  
    4343 */
    4444
    45 #include <arch/types.h>
     45#include <typedefs.h>
    4646#include <mm/frame.h>
    4747#include <mm/as.h>
     
    6666 * available.
    6767 */
    68 mutex_t mem_avail_mtx;
    69 condvar_t mem_avail_cv;
    70 size_t mem_avail_req = 0;  /**< Number of frames requested. */
    71 size_t mem_avail_gen = 0;  /**< Generation counter. */
     68static mutex_t mem_avail_mtx;
     69static condvar_t mem_avail_cv;
     70static size_t mem_avail_req = 0;  /**< Number of frames requested. */
     71static size_t mem_avail_gen = 0;  /**< Generation counter. */
    7272
    7373/********************/
     
    7575/********************/
    7676
    77 static inline size_t frame_index(zone_t *zone, frame_t *frame)
     77NO_TRACE static inline size_t frame_index(zone_t *zone, frame_t *frame)
    7878{
    7979        return (size_t) (frame - zone->frames);
    8080}
    8181
    82 static inline size_t frame_index_abs(zone_t *zone, frame_t *frame)
     82NO_TRACE static inline size_t frame_index_abs(zone_t *zone, frame_t *frame)
    8383{
    8484        return (size_t) (frame - zone->frames) + zone->base;
    8585}
    8686
    87 static inline bool frame_index_valid(zone_t *zone, size_t index)
     87NO_TRACE static inline bool frame_index_valid(zone_t *zone, size_t index)
    8888{
    8989        return (index < zone->count);
    9090}
    9191
    92 static inline size_t make_frame_index(zone_t *zone, frame_t *frame)
     92NO_TRACE static inline size_t make_frame_index(zone_t *zone, frame_t *frame)
    9393{
    9494        return (frame - zone->frames);
     
    100100 *
    101101 */
    102 static void frame_initialize(frame_t *frame)
     102NO_TRACE static void frame_initialize(frame_t *frame)
    103103{
    104104        frame->refcount = 1;
     
    121121 *
    122122 */
    123 static size_t zones_insert_zone(pfn_t base, size_t count)
     123NO_TRACE static size_t zones_insert_zone(pfn_t base, size_t count,
     124    zone_flags_t flags)
    124125{
    125126        if (zones.count + 1 == ZONES_MAX) {
     
    131132        for (i = 0; i < zones.count; i++) {
    132133                /* Check for overlap */
    133                 if (overlaps(base, count,
    134                     zones.info[i].base, zones.info[i].count)) {
    135                         printf("Zones overlap!\n");
     134                if (overlaps(zones.info[i].base, zones.info[i].count,
     135                    base, count)) {
     136                       
     137                        /*
     138                         * If the overlaping zones are of the same type
     139                         * and the new zone is completely within the previous
     140                         * one, then quietly ignore the new zone.
     141                         *
     142                         */
     143                       
     144                        if ((zones.info[i].flags != flags) ||
     145                            (!iswithin(zones.info[i].base, zones.info[i].count,
     146                            base, count))) {
     147                                printf("Zone (%p, %p) overlaps with previous zone (%p, %p)!\n",
     148                                    PFN2ADDR(base), PFN2ADDR(count),
     149                                    PFN2ADDR(zones.info[i].base),
     150                                    PFN2ADDR(zones.info[i].count));
     151                        }
     152                       
    136153                        return (size_t) -1;
    137154                }
     
    162179 */
    163180#ifdef CONFIG_DEBUG
    164 static size_t total_frames_free(void)
     181NO_TRACE static size_t total_frames_free(void)
    165182{
    166183        size_t total = 0;
     
    171188        return total;
    172189}
    173 #endif
     190#endif /* CONFIG_DEBUG */
    174191
    175192/** Find a zone with a given frames.
     
    185202 *
    186203 */
    187 size_t find_zone(pfn_t frame, size_t count, size_t hint)
     204NO_TRACE size_t find_zone(pfn_t frame, size_t count, size_t hint)
    188205{
    189206        if (hint >= zones.count)
     
    199216                if (i >= zones.count)
    200217                        i = 0;
     218               
    201219        } while (i != hint);
    202220       
     
    205223
    206224/** @return True if zone can allocate specified order */
    207 static bool zone_can_alloc(zone_t *zone, uint8_t order)
     225NO_TRACE static bool zone_can_alloc(zone_t *zone, uint8_t order)
    208226{
    209227        return (zone_flags_available(zone->flags)
     
    221239 *
    222240 */
    223 static size_t find_free_zone(uint8_t order, zone_flags_t flags, size_t hint)
     241NO_TRACE static size_t find_free_zone(uint8_t order, zone_flags_t flags,
     242    size_t hint)
    224243{
    225244        if (hint >= zones.count)
     
    242261                if (i >= zones.count)
    243262                        i = 0;
     263               
    244264        } while (i != hint);
    245265       
     
    260280 *
    261281 */
    262 static link_t *zone_buddy_find_block(buddy_system_t *buddy, link_t *child,
    263     uint8_t order)
     282NO_TRACE static link_t *zone_buddy_find_block(buddy_system_t *buddy,
     283    link_t *child, uint8_t order)
    264284{
    265285        frame_t *frame = list_get_instance(child, frame_t, buddy_link);
     
    283303 *
    284304 */
    285 static link_t *zone_buddy_find_buddy(buddy_system_t *buddy, link_t *block)
     305NO_TRACE static link_t *zone_buddy_find_buddy(buddy_system_t *buddy,
     306    link_t *block)
    286307{
    287308        frame_t *frame = list_get_instance(block, frame_t, buddy_link);
     
    296317                index = (frame_index(zone, frame)) +
    297318                    (1 << frame->buddy_order);
    298         } else {        /* is_right */
     319        } else {  /* is_right */
    299320                index = (frame_index(zone, frame)) -
    300321                    (1 << frame->buddy_order);
     
    319340 *
    320341 */
    321 static link_t *zone_buddy_bisect(buddy_system_t *buddy, link_t *block)
     342NO_TRACE static link_t *zone_buddy_bisect(buddy_system_t *buddy, link_t *block)
    322343{
    323344        frame_t *frame_l = list_get_instance(block, frame_t, buddy_link);
     
    337358 *
    338359 */
    339 static link_t *zone_buddy_coalesce(buddy_system_t *buddy, link_t *block_1,
    340     link_t *block_2)
     360NO_TRACE static link_t *zone_buddy_coalesce(buddy_system_t *buddy,
     361    link_t *block_1, link_t *block_2)
    341362{
    342363        frame_t *frame1 = list_get_instance(block_1, frame_t, buddy_link);
     
    353374 *
    354375 */
    355 static void zone_buddy_set_order(buddy_system_t *buddy, link_t *block,
     376NO_TRACE static void zone_buddy_set_order(buddy_system_t *buddy, link_t *block,
    356377    uint8_t order)
    357378{
     
    367388 *
    368389 */
    369 static uint8_t zone_buddy_get_order(buddy_system_t *buddy, link_t *block)
     390NO_TRACE static uint8_t zone_buddy_get_order(buddy_system_t *buddy,
     391    link_t *block)
    370392{
    371393        return list_get_instance(block, frame_t, buddy_link)->buddy_order;
     
    378400 *
    379401 */
    380 static void zone_buddy_mark_busy(buddy_system_t *buddy, link_t * block)
     402NO_TRACE static void zone_buddy_mark_busy(buddy_system_t *buddy, link_t *block)
    381403{
    382404        list_get_instance(block, frame_t, buddy_link)->refcount = 1;
     
    387409 * @param buddy Buddy system.
    388410 * @param block Buddy system block.
    389  */
    390 static void zone_buddy_mark_available(buddy_system_t *buddy, link_t *block)
     411 *
     412 */
     413NO_TRACE static void zone_buddy_mark_available(buddy_system_t *buddy,
     414    link_t *block)
    391415{
    392416        list_get_instance(block, frame_t, buddy_link)->refcount = 0;
     
    419443 *
    420444 */
    421 static pfn_t zone_frame_alloc(zone_t *zone, uint8_t order)
     445NO_TRACE static pfn_t zone_frame_alloc(zone_t *zone, uint8_t order)
    422446{
    423447        ASSERT(zone_flags_available(zone->flags));
     
    447471 *
    448472 */
    449 static void zone_frame_free(zone_t *zone, size_t frame_idx)
     473NO_TRACE static void zone_frame_free(zone_t *zone, size_t frame_idx)
    450474{
    451475        ASSERT(zone_flags_available(zone->flags));
     
    468492
    469493/** Return frame from zone. */
    470 static frame_t *zone_get_frame(zone_t *zone, size_t frame_idx)
     494NO_TRACE static frame_t *zone_get_frame(zone_t *zone, size_t frame_idx)
    471495{
    472496        ASSERT(frame_idx < zone->count);
     
    475499
    476500/** Mark frame in zone unavailable to allocation. */
    477 static void zone_mark_unavailable(zone_t *zone, size_t frame_idx)
     501NO_TRACE static void zone_mark_unavailable(zone_t *zone, size_t frame_idx)
    478502{
    479503        ASSERT(zone_flags_available(zone->flags));
     
    504528 *
    505529 */
    506 static void zone_merge_internal(size_t z1, size_t z2, zone_t *old_z1, buddy_system_t *buddy)
     530NO_TRACE static void zone_merge_internal(size_t z1, size_t z2, zone_t *old_z1,
     531    buddy_system_t *buddy)
    507532{
    508533        ASSERT(zone_flags_available(zones.info[z1].flags));
     
    600625 *
    601626 */
    602 static void return_config_frames(size_t znum, pfn_t pfn, size_t count)
     627NO_TRACE static void return_config_frames(size_t znum, pfn_t pfn, size_t count)
    603628{
    604629        ASSERT(zone_flags_available(zones.info[znum].flags));
     
    635660 *
    636661 */
    637 static void zone_reduce_region(size_t znum, pfn_t frame_idx, size_t count)
     662NO_TRACE static void zone_reduce_region(size_t znum, pfn_t frame_idx,
     663    size_t count)
    638664{
    639665        ASSERT(zone_flags_available(zones.info[znum].flags));
     
    673699bool zone_merge(size_t z1, size_t z2)
    674700{
    675         ipl_t ipl = interrupts_disable();
    676         spinlock_lock(&zones.lock);
     701        irq_spinlock_lock(&zones.lock, true);
    677702       
    678703        bool ret = true;
     
    744769       
    745770errout:
    746         spinlock_unlock(&zones.lock);
    747         interrupts_restore(ipl);
     771        irq_spinlock_unlock(&zones.lock, true);
    748772       
    749773        return ret;
     
    777801 *
    778802 */
    779 static void zone_construct(zone_t *zone, buddy_system_t *buddy, pfn_t start, size_t count, zone_flags_t flags)
     803NO_TRACE static void zone_construct(zone_t *zone, buddy_system_t *buddy,
     804    pfn_t start, size_t count, zone_flags_t flags)
    780805{
    781806        zone->base = start;
     
    820845 *
    821846 */
    822 uintptr_t zone_conf_size(size_t count)
     847size_t zone_conf_size(size_t count)
    823848{
    824849        return (count * sizeof(frame_t) + buddy_conf_size(fnzb(count)));
     
    841866 *
    842867 */
    843 size_t zone_create(pfn_t start, size_t count, pfn_t confframe, zone_flags_t flags)
    844 {
    845         ipl_t ipl = interrupts_disable();
    846         spinlock_lock(&zones.lock);
     868size_t zone_create(pfn_t start, size_t count, pfn_t confframe,
     869    zone_flags_t flags)
     870{
     871        irq_spinlock_lock(&zones.lock, true);
    847872       
    848873        if (zone_flags_available(flags)) {  /* Create available zone */
     
    887912                }
    888913               
    889                 size_t znum = zones_insert_zone(start, count);
     914                size_t znum = zones_insert_zone(start, count, flags);
    890915                if (znum == (size_t) -1) {
    891                         spinlock_unlock(&zones.lock);
    892                         interrupts_restore(ipl);
     916                        irq_spinlock_unlock(&zones.lock, true);
    893917                        return (size_t) -1;
    894918                }
     
    905929                }
    906930               
    907                 spinlock_unlock(&zones.lock);
    908                 interrupts_restore(ipl);
     931                irq_spinlock_unlock(&zones.lock, true);
    909932               
    910933                return znum;
     
    912935       
    913936        /* Non-available zone */
    914         size_t znum = zones_insert_zone(start, count);
     937        size_t znum = zones_insert_zone(start, count, flags);
    915938        if (znum == (size_t) -1) {
    916                 spinlock_unlock(&zones.lock);
    917                 interrupts_restore(ipl);
     939                irq_spinlock_unlock(&zones.lock, true);
    918940                return (size_t) -1;
    919941        }
    920942        zone_construct(&zones.info[znum], NULL, start, count, flags);
    921943       
    922         spinlock_unlock(&zones.lock);
    923         interrupts_restore(ipl);
     944        irq_spinlock_unlock(&zones.lock, true);
    924945       
    925946        return znum;
     
    933954void frame_set_parent(pfn_t pfn, void *data, size_t hint)
    934955{
    935         ipl_t ipl = interrupts_disable();
    936         spinlock_lock(&zones.lock);
     956        irq_spinlock_lock(&zones.lock, true);
    937957       
    938958        size_t znum = find_zone(pfn, 1, hint);
     
    943963            pfn - zones.info[znum].base)->parent = data;
    944964       
    945         spinlock_unlock(&zones.lock);
    946         interrupts_restore(ipl);
     965        irq_spinlock_unlock(&zones.lock, true);
    947966}
    948967
    949968void *frame_get_parent(pfn_t pfn, size_t hint)
    950969{
    951         ipl_t ipl = interrupts_disable();
    952         spinlock_lock(&zones.lock);
     970        irq_spinlock_lock(&zones.lock, true);
    953971       
    954972        size_t znum = find_zone(pfn, 1, hint);
     
    959977            pfn - zones.info[znum].base)->parent;
    960978       
    961         spinlock_unlock(&zones.lock);
    962         interrupts_restore(ipl);
     979        irq_spinlock_unlock(&zones.lock, true);
    963980       
    964981        return res;
     
    977994{
    978995        size_t size = ((size_t) 1) << order;
    979         ipl_t ipl;
    980996        size_t hint = pzone ? (*pzone) : 0;
    981997       
    982998loop:
    983         ipl = interrupts_disable();
    984         spinlock_lock(&zones.lock);
     999        irq_spinlock_lock(&zones.lock, true);
    9851000       
    9861001        /*
     
    9931008           if it does not help, reclaim all */
    9941009        if ((znum == (size_t) -1) && (!(flags & FRAME_NO_RECLAIM))) {
    995                 spinlock_unlock(&zones.lock);
    996                 interrupts_restore(ipl);
    997                
     1010                irq_spinlock_unlock(&zones.lock, true);
    9981011                size_t freed = slab_reclaim(0);
    999                
    1000                 ipl = interrupts_disable();
    1001                 spinlock_lock(&zones.lock);
     1012                irq_spinlock_lock(&zones.lock, true);
    10021013               
    10031014                if (freed > 0)
     
    10061017               
    10071018                if (znum == (size_t) -1) {
    1008                         spinlock_unlock(&zones.lock);
    1009                         interrupts_restore(ipl);
    1010                        
     1019                        irq_spinlock_unlock(&zones.lock, true);
    10111020                        freed = slab_reclaim(SLAB_RECLAIM_ALL);
    1012                        
    1013                         ipl = interrupts_disable();
    1014                         spinlock_lock(&zones.lock);
     1021                        irq_spinlock_lock(&zones.lock, true);
    10151022                       
    10161023                        if (freed > 0)
     
    10221029        if (znum == (size_t) -1) {
    10231030                if (flags & FRAME_ATOMIC) {
    1024                         spinlock_unlock(&zones.lock);
    1025                         interrupts_restore(ipl);
     1031                        irq_spinlock_unlock(&zones.lock, true);
    10261032                        return NULL;
    10271033                }
     
    10311037#endif
    10321038               
    1033                 spinlock_unlock(&zones.lock);
    1034                 interrupts_restore(ipl);
     1039                irq_spinlock_unlock(&zones.lock, true);
     1040               
     1041                if (!THREAD)
     1042                        panic("Cannot wait for memory to become available.");
    10351043               
    10361044                /*
     
    10661074            + zones.info[znum].base;
    10671075       
    1068         spinlock_unlock(&zones.lock);
    1069         interrupts_restore(ipl);
     1076        irq_spinlock_unlock(&zones.lock, true);
    10701077       
    10711078        if (pzone)
     
    10891096void frame_free(uintptr_t frame)
    10901097{
    1091         ipl_t ipl = interrupts_disable();
    1092         spinlock_lock(&zones.lock);
     1098        irq_spinlock_lock(&zones.lock, true);
    10931099       
    10941100        /*
     
    11021108        zone_frame_free(&zones.info[znum], pfn - zones.info[znum].base);
    11031109       
    1104         spinlock_unlock(&zones.lock);
    1105         interrupts_restore(ipl);
     1110        irq_spinlock_unlock(&zones.lock, true);
    11061111       
    11071112        /*
     
    11271132 *
    11281133 */
    1129 void frame_reference_add(pfn_t pfn)
    1130 {
    1131         ipl_t ipl = interrupts_disable();
    1132         spinlock_lock(&zones.lock);
     1134NO_TRACE void frame_reference_add(pfn_t pfn)
     1135{
     1136        irq_spinlock_lock(&zones.lock, true);
    11331137       
    11341138        /*
     
    11411145        zones.info[znum].frames[pfn - zones.info[znum].base].refcount++;
    11421146       
    1143         spinlock_unlock(&zones.lock);
    1144         interrupts_restore(ipl);
    1145 }
    1146 
    1147 /** Mark given range unavailable in frame zones. */
    1148 void frame_mark_unavailable(pfn_t start, size_t count)
    1149 {
    1150         ipl_t ipl = interrupts_disable();
    1151         spinlock_lock(&zones.lock);
     1147        irq_spinlock_unlock(&zones.lock, true);
     1148}
     1149
     1150/** Mark given range unavailable in frame zones.
     1151 *
     1152 */
     1153NO_TRACE void frame_mark_unavailable(pfn_t start, size_t count)
     1154{
     1155        irq_spinlock_lock(&zones.lock, true);
    11521156       
    11531157        size_t i;
     
    11611165        }
    11621166       
    1163         spinlock_unlock(&zones.lock);
    1164         interrupts_restore(ipl);
    1165 }
    1166 
    1167 /** Initialize physical memory management. */
     1167        irq_spinlock_unlock(&zones.lock, true);
     1168}
     1169
     1170/** Initialize physical memory management.
     1171 *
     1172 */
    11681173void frame_init(void)
    11691174{
    11701175        if (config.cpu_active == 1) {
    11711176                zones.count = 0;
    1172                 spinlock_initialize(&zones.lock, "zones.lock");
     1177                irq_spinlock_initialize(&zones.lock, "frame.zones.lock");
    11731178                mutex_initialize(&mem_avail_mtx, MUTEX_ACTIVE);
    11741179                condvar_initialize(&mem_avail_cv);
     
    12011206}
    12021207
    1203 /** Return total size of all zones. */
    1204 uint64_t zone_total_size(void)
    1205 {
    1206         ipl_t ipl = interrupts_disable();
    1207         spinlock_lock(&zones.lock);
     1208/** Return total size of all zones.
     1209 *
     1210 */
     1211uint64_t zones_total_size(void)
     1212{
     1213        irq_spinlock_lock(&zones.lock, true);
    12081214       
    12091215        uint64_t total = 0;
     
    12121218                total += (uint64_t) FRAMES2SIZE(zones.info[i].count);
    12131219       
    1214         spinlock_unlock(&zones.lock);
    1215         interrupts_restore(ipl);
     1220        irq_spinlock_unlock(&zones.lock, true);
    12161221       
    12171222        return total;
    12181223}
    12191224
    1220 /** Prints list of zones. */
    1221 void zone_print_list(void)
     1225void zones_stats(uint64_t *total, uint64_t *unavail, uint64_t *busy,
     1226    uint64_t *free)
     1227{
     1228        ASSERT(total != NULL);
     1229        ASSERT(unavail != NULL);
     1230        ASSERT(busy != NULL);
     1231        ASSERT(free != NULL);
     1232       
     1233        irq_spinlock_lock(&zones.lock, true);
     1234       
     1235        *total = 0;
     1236        *unavail = 0;
     1237        *busy = 0;
     1238        *free = 0;
     1239       
     1240        size_t i;
     1241        for (i = 0; i < zones.count; i++) {
     1242                *total += (uint64_t) FRAMES2SIZE(zones.info[i].count);
     1243               
     1244                if (zone_flags_available(zones.info[i].flags)) {
     1245                        *busy += (uint64_t) FRAMES2SIZE(zones.info[i].busy_count);
     1246                        *free += (uint64_t) FRAMES2SIZE(zones.info[i].free_count);
     1247                } else
     1248                        *unavail += (uint64_t) FRAMES2SIZE(zones.info[i].count);
     1249        }
     1250       
     1251        irq_spinlock_unlock(&zones.lock, true);
     1252}
     1253
     1254/** Prints list of zones.
     1255 *
     1256 */
     1257void zones_print_list(void)
    12221258{
    12231259#ifdef __32_BITS__
    1224         printf("#  base address frames       flags    free frames  busy frames\n");
    1225         printf("-- ------------ ------------ -------- ------------ ------------\n");
     1260        printf("[nr] [base addr] [frames    ] [flags ] [free frames ] [busy frames ]\n");
    12261261#endif
    12271262
    12281263#ifdef __64_BITS__
    1229         printf("#  base address          frames      flags    free frames  busy frames\n");
    1230         printf("-- -------------------- ------------ -------- ------------ ------------\n");
     1264        printf("[nr] [base address    ] [frames    ] [flags ] [free frames ] [busy frames ]\n");
    12311265#endif
    12321266       
     
    12441278        size_t i;
    12451279        for (i = 0;; i++) {
    1246                 ipl_t ipl = interrupts_disable();
    1247                 spinlock_lock(&zones.lock);
     1280                irq_spinlock_lock(&zones.lock, true);
    12481281               
    12491282                if (i >= zones.count) {
    1250                         spinlock_unlock(&zones.lock);
    1251                         interrupts_restore(ipl);
     1283                        irq_spinlock_unlock(&zones.lock, true);
    12521284                        break;
    12531285                }
     
    12591291                size_t busy_count = zones.info[i].busy_count;
    12601292               
    1261                 spinlock_unlock(&zones.lock);
    1262                 interrupts_restore(ipl);
     1293                irq_spinlock_unlock(&zones.lock, true);
    12631294               
    12641295                bool available = zone_flags_available(flags);
    12651296               
    1266                 printf("%-2" PRIs, i);
     1297                printf("%-4" PRIs, i);
    12671298               
    12681299#ifdef __32_BITS__
    1269                 printf("   %10p", base);
     1300                printf("  %10p", base);
    12701301#endif
    12711302               
    12721303#ifdef __64_BITS__
    1273                 printf("   %18p", base);
     1304                printf(" %18p", base);
    12741305#endif
    12751306               
     
    12801311               
    12811312                if (available)
    1282                         printf("%12" PRIs " %12" PRIs,
     1313                        printf("%14" PRIs " %14" PRIs,
    12831314                            free_count, busy_count);
    12841315               
     
    12941325void zone_print_one(size_t num)
    12951326{
    1296         ipl_t ipl = interrupts_disable();
    1297         spinlock_lock(&zones.lock);
     1327        irq_spinlock_lock(&zones.lock, true);
    12981328        size_t znum = (size_t) -1;
    12991329       
     
    13071337       
    13081338        if (znum == (size_t) -1) {
    1309                 spinlock_unlock(&zones.lock);
    1310                 interrupts_restore(ipl);
     1339                irq_spinlock_unlock(&zones.lock, true);
    13111340                printf("Zone not found.\n");
    13121341                return;
     
    13191348        size_t busy_count = zones.info[i].busy_count;
    13201349       
    1321         spinlock_unlock(&zones.lock);
    1322         interrupts_restore(ipl);
     1350        irq_spinlock_unlock(&zones.lock, true);
    13231351       
    13241352        bool available = zone_flags_available(flags);
Note: See TracChangeset for help on using the changeset viewer.