<commit_before>/*
 *
 * general timer device for using in ISDN stacks
 *
 * Author	<NAME> <<EMAIL>>
 *
 * Copyright 2008  by <NAME> <<EMAIL>>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 */

#include <linux/poll.h>
#include <linux/vmalloc.h>
#include <linux/slab.h>
#include <linux/timer.h>
#include <linux/miscdevice.h>
#include <linux/module.h>
#include <linux/mISDNif.h>
#include <linux/mutex.h>
#include "core.h"

static DEFINE_MUTEX(mISDN_mutex);
static u_int	*debug;


struct mISDNtimerdev {
	int			next_id;
	struct list_head	pending;
	struct list_head	expired;
	wait_queue_head_t	wait;
	u_int			work;
	spinlock_t		lock; /* protect lists */
};

struct mISDNtimer {
	struct list_head	list;
	struct  mISDNtimerdev	*dev;
	struct timer_list	tl;
	int			id;
};

static int
mISDN_open(struct inode *ino, struct file *filep)
{
	struct mISDNtimerdev	*dev;

	if (*debug & DEBUG_TIMER)
		printk(KERN_DEBUG "%s(%p,%p)\n", __func__, ino, filep);
	dev = kmalloc(sizeof(struct mISDNtimerdev) , GFP_KERNEL);
	if (!dev)
		return -ENOMEM;
	dev->next_id = 1;
	INIT_LIST_HEAD(&dev->pending);
	INIT_LIST_HEAD(&dev->expired);
	spin_lock_init(&dev->lock);
	dev->work = 0;
	init_waitqueue_head(&dev->wait);
	filep->private_data = dev;
	__module_get(THIS_MODULE);
	return nonseekable_open(ino, filep);
}

static int
mISDN_close(struct inode *ino, struct file *filep)
{
	struct mISDNtimerdev	*dev = filep->private_data;
	struct mISDNtimer	*timer, *next;

	if (*debug & DEBUG_TIMER)
		printk(KERN_DEBUG "%s(%p,%p)\n", __func__, ino, filep);
	list_for_each_entry_safe(timer, next, &dev->pending, list) {
		del_timer(&timer->tl);
		kfree(timer);
	}
	list_for_each_entry_safe(timer, next, &dev->expired, list) {
		kfree(timer);
	}
	kfree(dev);
	module_put(THIS_MODULE);
	return 0;
}

static ssize_t
mISDN_read(struct file *filep, char __user *buf, size_t count, loff_t *off)
{
	struct mISDNtimerdev	*dev = filep->private_data;
	struct mISDNtimer	*timer;<commit_msg>mISDN: fix the races with timers going off just as they are deleted<commit_after>/*
 *
 * general timer device for using in ISDN stacks
 *
 * Author	<NAME> <<EMAIL>>
 *
 * Copyright 2008  by <NAME> <<EMAIL>>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 */

#include <linux/poll.h>
#include <linux/vmalloc.h>
#include <linux/slab.h>
#include <linux/timer.h>
#include <linux/miscdevice.h>
#include <linux/module.h>
#include <linux/mISDNif.h>
#include <linux/mutex.h>
#include "core.h"

static DEFINE_MUTEX(mISDN_mutex);
static u_int	*debug;


struct mISDNtimerdev {
	int			next_id;
	struct list_head	pending;
	struct list_head	expired;
	wait_queue_head_t	wait;
	u_int			work;
	spinlock_t		lock; /* protect lists */
};

struct mISDNtimer {
	struct list_head	list;
	struct  mISDNtimerdev	*dev;
	struct timer_list	tl;
	int			id;
};

static int
mISDN_open(struct inode *ino, struct file *filep)
{
	struct mISDNtimerdev	*dev;

	if (*debug & DEBUG_TIMER)
		printk(KERN_DEBUG "%s(%p,%p)\n", __func__, ino, filep);
	dev = kmalloc(sizeof(struct mISDNtimerdev) , GFP_KERNEL);
	if (!dev)
		return -ENOMEM;
	dev->next_id = 1;
	INIT_LIST_HEAD(&dev->pending);
	INIT_LIST_HEAD(&dev->expired);
	spin_lock_init(&dev->lock);
	dev->work = 0;
	init_waitqueue_head(&dev->wait);
	filep->private_data = dev;
	__module_get(THIS_MODULE);
	return nonseekable_open(ino, filep);
}

static int
mISDN_close(struct inode *ino, struct file *filep)
{
	struct mISDNtimerdev	*dev = filep->private_data;
	struct list_head	*list = &dev->pending;
	struct mISDNtimer	*timer, *next;

	if (*debug & DEBUG_TIMER)
		printk(KERN_DEBUG "%s(%p,%p)\n", __func__, ino, filep);

	spin_lock_irq(&dev->lock);
	while (!list_empty(list)) {
		timer = list_first_entry(list, struct mISDNtimer, list);
		spin_unlock_irq(&dev->lock);
		del_timer_sync(&timer->tl);
		spin_lock_irq(&dev->lock);
		/* it might have been moved to ->expired */
		list_del(&timer->list);
		kfree(timer);
	}
	spin_unlock_irq(&dev->lock);

	list_for_each_entry_safe(timer, next, &dev->expired, list) {
		kfree(timer);
	}
	kfree(dev);
	module_put(THIS_MODULE);
	return 0;
}

static ssize_t
mISDN_read(struct file *filep, char __user *buf, size_t count, loff_t *off)
{
	struct mISDNtimerdev	*dev = filep->private_data;
	struct mISDNtimer	*timer;
{'fraction_non_alphanumeric': 0.1232986389111289, 'fraction_numerical': 0.0032025620496397116, 'mean_word_length': 4.79026651216686, 'pattern_counts': {'":': 0, '<': 31, '<?xml version=': 0, '>': 61, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6248310', 'n_tokens_mistral': 1901, 'n_tokens_neox': 1850, 'n_words': 506}