1/*
2 * Copyright (c) 2011 Apple Inc. All rights reserved.
3 *
4 * @APPLE_APACHE_LICENSE_HEADER_START@
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 *     http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 * @APPLE_APACHE_LICENSE_HEADER_END@
19 */
20/*
21    SubzonePartition.h
22    Subzone partitioning scheme.
23    Copyright (c) 2009-2011 Apple Inc. All rights reserved.
24 */
25
26#ifndef __AUTO_SUBZONE_PARTITION__
27#define __AUTO_SUBZONE_PARTITION__
28
29#include "Admin.h"
30#include "Locks.h"
31
32namespace Auto {
33
34    // Forward declarations
35
36    //----- SubzonePartition -----//
37
38    class SubzonePartition {
39        enum {
40            kPartitionUnscanned  = 1,
41            kPartitionRetained   = 2,
42            kPartitionCount      = 4
43        };
44
45        Admin _small[kPartitionCount];
46        Admin _medium[kPartitionCount];
47
48    public:
49        void initialize(Zone *zone);
50
51        Admin &admin(const size_t size, const usword_t layout, bool refcount_is_one) {
52            usword_t partion = ((layout & AUTO_UNSCANNED) ? kPartitionUnscanned : 0) | (refcount_is_one ? kPartitionRetained : 0);
53            return (size < allocate_quantum_medium ? _small[partion] : _medium[partion]);
54        }
55
56        void lock() {
57            for (usword_t i = 0; i < kPartitionCount; ++i) {
58                spin_lock(_small[i].lock());
59                spin_lock(_medium[i].lock());
60            }
61        }
62
63        void unlock() {
64            for (usword_t i = kPartitionCount; i > 0; --i) {
65                spin_unlock(_medium[i - 1].lock());
66                spin_unlock(_small[i - 1].lock());
67            }
68        }
69
70        bool locked() {
71            for (usword_t i = 0; i < kPartitionCount; ++i) {
72                TrySpinLock smallAttempt(_small[i].lock());
73                if (!smallAttempt) return true;
74                TrySpinLock mediumAttempt(_medium[i].lock());
75                if (!mediumAttempt) return true;
76            }
77            return false;
78        }
79
80        //
81        // for_each
82        //
83        // Applies block to all partitioned admins.
84        //
85        void for_each(void (^block) (Admin &admin)) {
86            for (usword_t i = 0; i < kPartitionCount; ++i) {
87                block(_small[i]);
88                block(_medium[i]);
89            }
90        }
91
92        usword_t purge_free_space() {
93            usword_t bytes_purged = 0;
94            for (usword_t i = 0; i < kPartitionCount; ++i) {
95                bytes_purged += _small[i].purge_free_space();
96                bytes_purged += _medium[i].purge_free_space();
97            }
98            return bytes_purged;
99        }
100
101        usword_t purge_free_space_no_lock() {
102            usword_t bytes_purged = 0;
103            for (usword_t i = 0; i < kPartitionCount; ++i) {
104                bytes_purged += _small[i].purge_free_space_no_lock();
105                bytes_purged += _medium[i].purge_free_space_no_lock();
106            }
107            return bytes_purged;
108        }
109
110        class Lock {
111            SubzonePartition &_partition;
112        public:
113            Lock(SubzonePartition &partition) : _partition(partition) { _partition.lock(); }
114            ~Lock() { _partition.unlock(); }
115        };
116    };
117
118};
119
120#endif /* __AUTO_SUBZONE_PARTITION__ */
121