1146773Ssam/*
2146773Ssam * CDDL HEADER START
3146773Ssam *
4146773Ssam * The contents of this file are subject to the terms of the
5146773Ssam * Common Development and Distribution License (the "License").
6146773Ssam * You may not use this file except in compliance with the License.
7146773Ssam *
8146773Ssam * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9146773Ssam * or http://www.opensolaris.org/os/licensing.
10146773Ssam * See the License for the specific language governing permissions
11146773Ssam * and limitations under the License.
12146773Ssam *
13146773Ssam * When distributing Covered Code, include this CDDL HEADER in each
14146773Ssam * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15146773Ssam * If applicable, add the following below this CDDL HEADER, with the
16146773Ssam * fields enclosed by brackets "[]" replaced with your own identifying
17146773Ssam * information: Portions Copyright [yyyy] [name of copyright owner]
18146773Ssam *
19146773Ssam * CDDL HEADER END
20146773Ssam */
21146773Ssam
22146773Ssam/*
23190207Srpaulo * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24146773Ssam * Use is subject to license terms.
25146773Ssam *
26146773Ssam * ident	"%Z%%M%	%I%	%E% SMI"
27146773Ssam */
28146773Ssamimport java.util.*;
29146773Ssamimport java.util.concurrent.atomic.*;
30146773Ssamimport org.opensolaris.os.dtrace.*;
31146773Ssam
32146773Ssam/**
33146773Ssam * Regression test for 6521523 aggregation drops can hang the Java
34146773Ssam * DTrace API.
35146773Ssam */
36214478Srpaulopublic class TestDrop {
37146773Ssam    static final String PROGRAM =
38146773Ssam	    "fbt:genunix::entry { @[execname, pid] = count(); }";
39146773Ssam
40146773Ssam    static AtomicLong consumerThreadID = new AtomicLong();
41146773Ssam    static AtomicLong getAggregateThreadID = new AtomicLong();
42146773Ssam    static AtomicBoolean done = new AtomicBoolean();
43146773Ssam    static int seconds;
44146773Ssam
45146773Ssam    private static void
46146773Ssam    startTimer()
47146773Ssam    {
48146773Ssam	if (seconds <= 0) {
49146773Ssam	    return;
50146773Ssam	}
51146773Ssam
52146773Ssam	final Timer timer = new Timer();
53146773Ssam	timer.schedule(new TimerTask() {
54146773Ssam	    public void run() {
55146773Ssam		done.set(true);
56214478Srpaulo		timer.cancel();
57146773Ssam	    }
58146773Ssam	}, seconds * 1000L);
59146773Ssam    }
60146773Ssam
61146773Ssam    private static void
62146773Ssam    sampleAggregate(Consumer consumer) throws DTraceException
63146773Ssam    {
64146773Ssam	while (consumer.isRunning() && !done.get()) {
65146773Ssam	    try {
66146773Ssam		Thread.currentThread().sleep(50);
67146773Ssam	    } catch (InterruptedException e) {
68146773Ssam	    }
69146773Ssam
70146773Ssam	    consumer.getAggregate(Collections. <String> emptySet());
71146773Ssam	}
72146773Ssam    }
73146773Ssam
74146773Ssam    private static void
75146773Ssam    startAggregateThread(final Consumer consumer)
76146773Ssam    {
77146773Ssam	Runnable aggregateSampler = new Runnable() {
78146773Ssam	    public void run() {
79146773Ssam		Thread t = Thread.currentThread();
80146773Ssam		getAggregateThreadID.set(t.getId());
81146773Ssam		Throwable x = null;
82146773Ssam		try {
83146773Ssam		    sampleAggregate(consumer);
84146773Ssam		} catch (Throwable e) {
85146773Ssam		    x = e;
86146773Ssam		}
87146773Ssam
88146773Ssam		if (Thread.holdsLock(LocalConsumer.class)) {
89146773Ssam		    if (x != null) {
90146773Ssam			x.printStackTrace();
91146773Ssam		    }
92146773Ssam		    System.out.println("Lock held");
93146773Ssam		    System.exit(1);
94146773Ssam		} else {
95146773Ssam		    System.out.println("Lock released");
96146773Ssam		    consumer.close(); // blocks if lock held
97146773Ssam		}
98146773Ssam	    }
99146773Ssam	};
100146773Ssam
101214478Srpaulo	Thread t = new Thread(aggregateSampler, "Aggregate Sampler");
102146773Ssam	t.start();
103146773Ssam    }
104146773Ssam
105146773Ssam    static void
106146773Ssam    usage()
107146773Ssam    {
108162017Ssam	System.err.println("usage: java TestDrop [ seconds ]");
109146773Ssam	System.exit(2);
110235530Sdelphij    }
111146773Ssam
112146773Ssam    public static void
113146773Ssam    main(String[] args)
114146773Ssam    {
115162017Ssam	if (args.length == 1) {
116146773Ssam	    try {
117146773Ssam		seconds = Integer.parseInt(args[0]);
118146773Ssam	    } catch (NumberFormatException e) {
119146773Ssam		usage();
120146773Ssam	    }
121	} else if (args.length > 1) {
122	    usage();
123	}
124
125	final Consumer consumer = new LocalConsumer() {
126	    protected Thread createThread() {
127		Runnable worker = new Runnable() {
128		    public void run() {
129			Thread t = Thread.currentThread();
130			consumerThreadID.set(t.getId());
131			work();
132		    }
133		};
134		Thread t = new Thread(worker);
135		return t;
136	    }
137	};
138
139	consumer.addConsumerListener(new ConsumerAdapter() {
140	    public void consumerStarted(ConsumerEvent e) {
141		startAggregateThread(consumer);
142		startTimer();
143	    }
144	    public void dataDropped(DropEvent e) throws ConsumerException {
145		Thread t = Thread.currentThread();
146		if (t.getId() == getAggregateThreadID.get()) {
147		    Drop drop = e.getDrop();
148		    throw new ConsumerException(drop.getDefaultMessage(),
149			    drop);
150		}
151	    }
152	});
153
154	try {
155	    consumer.open();
156	    consumer.setOption(Option.aggsize, Option.kb(1));
157	    consumer.setOption(Option.aggrate, Option.millis(101));
158	    consumer.compile(PROGRAM);
159	    consumer.enable();
160	    consumer.go(new ExceptionHandler() {
161		public void handleException(Throwable e) {
162		    e.printStackTrace();
163		}
164	    });
165	} catch (DTraceException e) {
166	    e.printStackTrace();
167	}
168    }
169}
170