1178476Sjb/*
2178476Sjb * CDDL HEADER START
3178476Sjb *
4178476Sjb * The contents of this file are subject to the terms of the
5178476Sjb * Common Development and Distribution License (the "License").
6178476Sjb * You may not use this file except in compliance with the License.
7178476Sjb *
8178476Sjb * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9178476Sjb * or http://www.opensolaris.org/os/licensing.
10178476Sjb * See the License for the specific language governing permissions
11178476Sjb * and limitations under the License.
12178476Sjb *
13178476Sjb * When distributing Covered Code, include this CDDL HEADER in each
14178476Sjb * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15178476Sjb * If applicable, add the following below this CDDL HEADER, with the
16178476Sjb * fields enclosed by brackets "[]" replaced with your own identifying
17178476Sjb * information: Portions Copyright [yyyy] [name of copyright owner]
18178476Sjb *
19178476Sjb * CDDL HEADER END
20178476Sjb */
21178476Sjb
22178476Sjb/*
23178476Sjb * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24178476Sjb * Use is subject to license terms.
25178476Sjb *
26178476Sjb * ident	"%Z%%M%	%I%	%E% SMI"
27178476Sjb */
28178476Sjbimport java.util.*;
29178476Sjbimport java.util.concurrent.atomic.*;
30178476Sjbimport org.opensolaris.os.dtrace.*;
31178476Sjb
32178476Sjb/**
33178476Sjb * Regression test for 6521523 aggregation drops can hang the Java
34178476Sjb * DTrace API.
35178476Sjb */
36178476Sjbpublic class TestDrop {
37178476Sjb    static final String PROGRAM =
38178476Sjb	    "fbt:genunix::entry { @[execname, pid] = count(); }";
39178476Sjb
40178476Sjb    static AtomicLong consumerThreadID = new AtomicLong();
41178476Sjb    static AtomicLong getAggregateThreadID = new AtomicLong();
42178476Sjb    static AtomicBoolean done = new AtomicBoolean();
43178476Sjb    static int seconds;
44178476Sjb
45178476Sjb    private static void
46178476Sjb    startTimer()
47178476Sjb    {
48178476Sjb	if (seconds <= 0) {
49178476Sjb	    return;
50178476Sjb	}
51178476Sjb
52178476Sjb	final Timer timer = new Timer();
53178476Sjb	timer.schedule(new TimerTask() {
54178476Sjb	    public void run() {
55178476Sjb		done.set(true);
56178476Sjb		timer.cancel();
57178476Sjb	    }
58178476Sjb	}, seconds * 1000L);
59178476Sjb    }
60178476Sjb
61178476Sjb    private static void
62178476Sjb    sampleAggregate(Consumer consumer) throws DTraceException
63178476Sjb    {
64178476Sjb	while (consumer.isRunning() && !done.get()) {
65178476Sjb	    try {
66178476Sjb		Thread.currentThread().sleep(50);
67178476Sjb	    } catch (InterruptedException e) {
68178476Sjb	    }
69178476Sjb
70178476Sjb	    consumer.getAggregate(Collections. <String> emptySet());
71178476Sjb	}
72178476Sjb    }
73178476Sjb
74178476Sjb    private static void
75178476Sjb    startAggregateThread(final Consumer consumer)
76178476Sjb    {
77178476Sjb	Runnable aggregateSampler = new Runnable() {
78178476Sjb	    public void run() {
79178476Sjb		Thread t = Thread.currentThread();
80178476Sjb		getAggregateThreadID.set(t.getId());
81178476Sjb		Throwable x = null;
82178476Sjb		try {
83178476Sjb		    sampleAggregate(consumer);
84178476Sjb		} catch (Throwable e) {
85178476Sjb		    x = e;
86178476Sjb		}
87178476Sjb
88178476Sjb		if (Thread.holdsLock(LocalConsumer.class)) {
89178476Sjb		    if (x != null) {
90178476Sjb			x.printStackTrace();
91178476Sjb		    }
92178476Sjb		    System.out.println("Lock held");
93178476Sjb		    System.exit(1);
94178476Sjb		} else {
95178476Sjb		    System.out.println("Lock released");
96178476Sjb		    consumer.close(); // blocks if lock held
97178476Sjb		}
98178476Sjb	    }
99178476Sjb	};
100178476Sjb
101178476Sjb	Thread t = new Thread(aggregateSampler, "Aggregate Sampler");
102178476Sjb	t.start();
103178476Sjb    }
104178476Sjb
105178476Sjb    static void
106178476Sjb    usage()
107178476Sjb    {
108178476Sjb	System.err.println("usage: java TestDrop [ seconds ]");
109178476Sjb	System.exit(2);
110178476Sjb    }
111178476Sjb
112178476Sjb    public static void
113178476Sjb    main(String[] args)
114178476Sjb    {
115178476Sjb	if (args.length == 1) {
116178476Sjb	    try {
117178476Sjb		seconds = Integer.parseInt(args[0]);
118178476Sjb	    } catch (NumberFormatException e) {
119178476Sjb		usage();
120178476Sjb	    }
121178476Sjb	} else if (args.length > 1) {
122178476Sjb	    usage();
123178476Sjb	}
124178476Sjb
125178476Sjb	final Consumer consumer = new LocalConsumer() {
126178476Sjb	    protected Thread createThread() {
127178476Sjb		Runnable worker = new Runnable() {
128178476Sjb		    public void run() {
129178476Sjb			Thread t = Thread.currentThread();
130178476Sjb			consumerThreadID.set(t.getId());
131178476Sjb			work();
132178476Sjb		    }
133178476Sjb		};
134178476Sjb		Thread t = new Thread(worker);
135178476Sjb		return t;
136178476Sjb	    }
137178476Sjb	};
138178476Sjb
139178476Sjb	consumer.addConsumerListener(new ConsumerAdapter() {
140178476Sjb	    public void consumerStarted(ConsumerEvent e) {
141178476Sjb		startAggregateThread(consumer);
142178476Sjb		startTimer();
143178476Sjb	    }
144178476Sjb	    public void dataDropped(DropEvent e) throws ConsumerException {
145178476Sjb		Thread t = Thread.currentThread();
146178476Sjb		if (t.getId() == getAggregateThreadID.get()) {
147178476Sjb		    Drop drop = e.getDrop();
148178476Sjb		    throw new ConsumerException(drop.getDefaultMessage(),
149178476Sjb			    drop);
150178476Sjb		}
151178476Sjb	    }
152178476Sjb	});
153178476Sjb
154178476Sjb	try {
155178476Sjb	    consumer.open();
156178476Sjb	    consumer.setOption(Option.aggsize, Option.kb(1));
157178476Sjb	    consumer.setOption(Option.aggrate, Option.millis(101));
158178476Sjb	    consumer.compile(PROGRAM);
159178476Sjb	    consumer.enable();
160178476Sjb	    consumer.go(new ExceptionHandler() {
161178476Sjb		public void handleException(Throwable e) {
162178476Sjb		    e.printStackTrace();
163178476Sjb		}
164178476Sjb	    });
165178476Sjb	} catch (DTraceException e) {
166178476Sjb	    e.printStackTrace();
167178476Sjb	}
168178476Sjb    }
169178476Sjb}
170