1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  *
  26  * ident        "%Z%%M% %I%     %E% SMI"
  27  */
  28 import java.util.*;
  29 import java.util.concurrent.atomic.*;
  30 import org.opensolaris.os.dtrace.*;
  31 
  32 /**
  33  * Regression test for 6521523 aggregation drops can hang the Java
  34  * DTrace API.
  35  */
  36 public class TestDrop {
  37     static final String PROGRAM =
  38             "fbt:genunix::entry { @[execname, pid] = count(); }";
  39 
  40     static AtomicLong consumerThreadID = new AtomicLong();
  41     static AtomicLong getAggregateThreadID = new AtomicLong();
  42     static AtomicBoolean done = new AtomicBoolean();
  43     static int seconds;
  44 
  45     private static void
  46     startTimer()
  47     {
  48         if (seconds <= 0) {
  49             return;
  50         }
  51 
  52         final Timer timer = new Timer();
  53         timer.schedule(new TimerTask() {
  54             public void run() {
  55                 done.set(true);
  56                 timer.cancel();
  57             }
  58         }, seconds * 1000L);
  59     }
  60 
  61     private static void
  62     sampleAggregate(Consumer consumer) throws DTraceException
  63     {
  64         while (consumer.isRunning() && !done.get()) {
  65             try {
  66                 Thread.currentThread().sleep(50);
  67             } catch (InterruptedException e) {
  68             }
  69 
  70             consumer.getAggregate(Collections. <String> emptySet());
  71         }
  72     }
  73 
  74     private static void
  75     startAggregateThread(final Consumer consumer)
  76     {
  77         Runnable aggregateSampler = new Runnable() {
  78             public void run() {
  79                 Thread t = Thread.currentThread();
  80                 getAggregateThreadID.set(t.getId());
  81                 Throwable x = null;
  82                 try {
  83                     sampleAggregate(consumer);
  84                 } catch (Throwable e) {
  85                     x = e;
  86                 }
  87 
  88                 if (Thread.holdsLock(LocalConsumer.class)) {
  89                     if (x != null) {
  90                         x.printStackTrace();
  91                     }
  92                     System.out.println("Lock held");
  93                     System.exit(1);
  94                 } else {
  95                     System.out.println("Lock released");
  96                     consumer.close(); // blocks if lock held
  97                 }
  98             }
  99         };
 100 
 101         Thread t = new Thread(aggregateSampler, "Aggregate Sampler");
 102         t.start();
 103     }
 104 
 105     static void
 106     usage()
 107     {
 108         System.err.println("usage: java TestDrop [ seconds ]");
 109         System.exit(2);
 110     }
 111 
 112     public static void
 113     main(String[] args)
 114     {
 115         if (args.length == 1) {
 116             try {
 117                 seconds = Integer.parseInt(args[0]);
 118             } catch (NumberFormatException e) {
 119                 usage();
 120             }
 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 }