1/*
2 * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package sun.jvmstat.perfdata.monitor;
27
28import sun.jvmstat.monitor.*;
29import java.nio.ByteOrder;
30import java.nio.ByteBuffer;
31import java.nio.IntBuffer;
32
33/**
34 * Abstraction representing the HotSpot PerfData instrumentation buffer
35 * header. This class represents only the fixed portion of the header.
36 * Version specific classes represent the portion of the header that
37 * may change from release to release.
38 * <p>
39 * The PerfDataBufferProlog class supports parsing of the following
40 * C structure:
41 * <pre>
42 * typedef struct {
43 *   jint magic;             // magic number - 0xcafec0c0
44 *   jbyte byte_order;       // byte order of the buffer
45 *   jbyte major_version;    // major and minor version numbers
46 *   jbyte minor_version;
47 *   jbyte reserved_byte1;   // reserved - see concrete implementations for
48 *                           // possible definition.
49 *   ...                     // remainder is handled by the subclasses.
50 * } PerfDataPrologue
51 * </pre>
52 *
53 * @author Brian Doherty
54 * @since 1.5
55 */
56public abstract class AbstractPerfDataBufferPrologue {
57
58    protected ByteBuffer byteBuffer;
59
60    /*
61     * the following constants must match the field offsets and sizes
62     * in the PerfDataPrologue structure in perfMemory.hpp
63     */
64    final static int PERFDATA_PROLOG_OFFSET=0;
65    final static int PERFDATA_PROLOG_MAGIC_OFFSET=0;
66    final static int PERFDATA_PROLOG_BYTEORDER_OFFSET=4;
67    final static int PERFDATA_PROLOG_BYTEORDER_SIZE=1;         // sizeof(byte)
68    final static int PERFDATA_PROLOG_MAJOR_OFFSET=5;
69    final static int PERFDATA_PROLOG_MAJOR_SIZE=1;             // sizeof(byte)
70    final static int PERFDATA_PROLOG_MINOR_OFFSET=6;
71    final static int PERFDATA_PROLOG_MINOR_SIZE=1;             // sizeof(byte)
72    final static int PERFDATA_PROLOG_RESERVEDB1_OFFSET=7;
73    final static int PERFDATA_PROLOG_RESERVEDB1_SIZE=1;        // sizeof(byte)
74
75    final static int PERFDATA_PROLOG_SIZE=8;   // sizeof(struct PerfDataProlog)
76
77    // these constants should match their #define counterparts in perfMemory.hpp
78    final static byte PERFDATA_BIG_ENDIAN=0;
79    final static byte PERFDATA_LITTLE_ENDIAN=1;
80    final static int  PERFDATA_MAGIC = 0xcafec0c0;
81
82    // names for counters that expose the prolog fields
83    public final static String PERFDATA_MAJOR_NAME =
84            "sun.perfdata.majorVersion";
85    public final static String PERFDATA_MINOR_NAME =
86            "sun.perfdata.minorVersion";
87
88    /**
89     * Construct a PerfDataBufferPrologue instance.
90     *
91     * @param byteBuffer buffer containing the instrumentation data
92     */
93    public AbstractPerfDataBufferPrologue(ByteBuffer byteBuffer)
94           throws MonitorException  {
95        this.byteBuffer = byteBuffer.duplicate();
96
97        // the magic number is always stored in big-endian format
98        if (getMagic() != PERFDATA_MAGIC) {
99            throw new MonitorVersionException(
100                    "Bad Magic: " + Integer.toHexString(getMagic()));
101        }
102
103        // set the byte order
104        this.byteBuffer.order(getByteOrder());
105    }
106
107    /**
108     * Get the magic number.
109     *
110     * @return int - the magic number
111     */
112    public int getMagic() {
113        // the magic number is always stored in big-endian format
114        ByteOrder order = byteBuffer.order();
115        byteBuffer.order(ByteOrder.BIG_ENDIAN);
116
117        // get the magic number
118        byteBuffer.position(PERFDATA_PROLOG_MAGIC_OFFSET);
119        int magic = byteBuffer.getInt();
120
121        // restore the byte order
122        byteBuffer.order(order);
123        return magic;
124    }
125
126    /**
127     * Get the byte order.
128     *
129     * @return int - the byte order of the instrumentation buffer
130     */
131    public ByteOrder getByteOrder() {
132        // byte order field is byte order independent
133        byteBuffer.position(PERFDATA_PROLOG_BYTEORDER_OFFSET);
134
135        byte byte_order = byteBuffer.get();
136
137        if (byte_order == PERFDATA_BIG_ENDIAN) {
138            return ByteOrder.BIG_ENDIAN;
139        } else {
140            return ByteOrder.LITTLE_ENDIAN;
141        }
142    }
143
144    /**
145     * Get the major version.
146     *
147     * @return int - the major version
148     */
149    public int getMajorVersion() {
150        // major version field is byte order independent
151        byteBuffer.position(PERFDATA_PROLOG_MAJOR_OFFSET);
152        return (int)byteBuffer.get();
153    }
154
155    /**
156     * Get the minor version.
157     *
158     * @return int - the minor version
159     */
160    public int getMinorVersion() {
161        // minor version field is byte order independent
162        byteBuffer.position(PERFDATA_PROLOG_MINOR_OFFSET);
163        return (int)byteBuffer.get();
164    }
165
166    /**
167     * Get the accessible flag. If supported, it indicates that the shared
168     * memory region is sufficiently initialized for client acccess.
169     *
170     * @return boolean - the initialized status
171     * @see #supportsAccessible()
172     */
173    public abstract boolean isAccessible();
174
175    /**
176     * Test if the accessible flag is supported by this version of
177     * the PerfDataBufferPrologue. Although not an abstract method, this
178     * method should be overridden by version specific subclasses.
179     *
180     * @return boolean - the initialized flag support status.
181     * @see #isAccessible()
182     */
183    public abstract boolean supportsAccessible();
184
185    /**
186     * Get the size of the header portion of the instrumentation buffer.
187     *
188     * @return int - the size of the header
189     */
190    public int getSize() {
191        return PERFDATA_PROLOG_SIZE;  // sizeof(struct PerfDataProlog)
192    }
193
194    /**
195     * Return an IntBuffer that accesses the major version number.
196     * This is used to create a Monitor object for this value.
197     *
198     * @return IntBuffer - a ByteBuffer that accesses the major version number
199     *                     in the instrumentation buffer header.
200     */
201    public IntBuffer majorVersionBuffer() {
202        int[] holder = new int[1];
203        holder[0] = getMajorVersion();
204        IntBuffer ib = IntBuffer.wrap(holder);
205        ib.limit(1);
206        return ib;
207      }
208
209    /**
210     * Return an IntBuffer that accesses the minor version number.
211     * This is used to create a Monitor object for this value.
212     *
213     * @return IntBuffer - a ByteBuffer that accesses the minor version number
214     *                     in the instrumentation buffer header.
215     */
216    public IntBuffer minorVersionBuffer() {
217        int[] holder = new int[1];
218        holder[0] = getMinorVersion();
219        IntBuffer ib = IntBuffer.wrap(holder);
220        ib.limit(1);
221        return ib;
222    }
223
224    /**
225     * Get the magic number from the given byteBuffer.
226     *
227     * @return int - the magic number
228     */
229    public static int getMagic(ByteBuffer bb) {
230        // save buffer state
231        int position = bb.position();
232        ByteOrder order = bb.order();
233
234        // the magic number is always stored in big-endian format
235        bb.order(ByteOrder.BIG_ENDIAN);
236        bb.position(PERFDATA_PROLOG_MAGIC_OFFSET);
237        int magic = bb.getInt();
238
239        // restore buffer state.
240        bb.order(order);
241        bb.position(position);
242
243        return magic;
244    }
245
246    /**
247     * Get the major version number from the given ByteBuffer.
248     *
249     * @return int - the major version
250     */
251    public static int getMajorVersion(ByteBuffer bb) {
252        // save buffer state
253        int position = bb.position();
254
255        bb.position(PERFDATA_PROLOG_MAJOR_OFFSET);
256        int major = (int) bb.get();
257
258        // restore buffer state.
259        bb.position(position);
260
261        return major;
262    }
263
264    /**
265     * Get the minor version number from the given ByteBuffer.
266     *
267     * @return int - the minor version
268     */
269    public static int getMinorVersion(ByteBuffer bb) {
270        // save buffer state
271        int position = bb.position();
272
273        bb.position(PERFDATA_PROLOG_MINOR_OFFSET);
274        int minor = (int)bb.get();
275
276        // restore buffer state.
277        bb.position(position);
278
279        return minor;
280    }
281
282    /**
283     * Get the byte order for the given ByteBuffer.
284     *
285     * @return int - the byte order of the instrumentation buffer
286     */
287    public static ByteOrder getByteOrder(ByteBuffer bb) {
288        // save buffer state
289        int position = bb.position();
290
291        bb.position(PERFDATA_PROLOG_BYTEORDER_OFFSET);
292        ByteOrder order = (bb.get() == PERFDATA_BIG_ENDIAN)
293                          ? ByteOrder.BIG_ENDIAN
294                          : ByteOrder.LITTLE_ENDIAN;
295
296        // restore buffer state.
297        bb.position(position);
298        return order;
299    }
300}
301