I want to create a new work queue using create_workqueue()
The author of the book I'm reading about kernel development says "This function creates all the worker threads (one for each processor in the system) and prepares them to handle work."
My code shown at the end of this question, creates a kernel and schedules work on two queues. One is a default workqueue, and the other uses customized workqueue. They should by handled by different worker threads.
However, I see in the results (shown below) both are handled by same process (PID 42501), which is the thread kworker2 in my virtual machine.
Run result:
#include <linux/workqueue.h>
#include "kn_common.h"
#include <linux/sched.h>
MODULE_LICENSE("Dual BSD/GPL");
static void my_work_func(struct work_struct *work){
long ID;
printk(KERN_ALERT"=============\n");
print_current_time(0);
ID = current->pid;
printk(KERN_ALERT"my workqueue function is called!.... pid = %ld\n", ID);
printk(KERN_ALERT"=============\n");
}
static void my_work_custom_func(struct work_struct *work){
long ID;
printk(KERN_ALERT"=============\n");
print_current_time(0);
ID = current->pid;
printk(KERN_ALERT"my customize workqueue is called!... pid = %ld\n", ID);
printk(KERN_ALERT"=============\n");
}
DECLARE_WORK(mywork, my_work_func);
static int testworkqueue_init(void){
struct workqueue_struct *myworkqueue = create_workqueue("myworkqueue");
// init a work_struct dynamically use pointer
struct work_struct *mywork2;
mywork2 = kmalloc(sizeof(struct work_struct), GFP_KERNEL);
INIT_WORK(mywork2, my_work_custom_func);
flush_scheduled_work();
// schedule work
schedule_work(&mywork);
// flush customized workqueue
flush_workqueue(myworkqueue);
queue_work(myworkqueue, mywork2);
return 0;
}
static void testworkqueue_exit(void){
printk(KERN_ALERT"*************\n");
print_current_time(0);
printk(KERN_ALERT"testworkqueu exit\n");
printk(KERN_ALERT"*************\n");
}
module_init(testworkqueue_init);
module_exit(testworkqueue_exit);
And Makefile
obj-m += myworkqueue.o
myworkqueue-objs := testworkqueue.o kn_common.o
CURRENT_PATH := $(shell pwd)
LINUX_KERNEL := $(shell uname -r)
# you may change this to your own kernel src path
LINUX_KERNEL_PATH := /lib/modules/$(LINUX_KERNEL)/build
all:
make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules
rm -rf modules.order Module.symvers .*.cmd *.o *.mod.c .tmp_versions *.unsigned
clean:
rm -rf modules.order Module.symvers .*.cmd *.o *.mod.c *.ko .tmp_versions *.unsigned
Originally implemented Multi thread(MT) Workqueue wasted a lot of resource, the level of concurrency provided was unsatisfactory.
New design has introduced to get high level of concurrency. Functions "create_*workqueue()" are deprecated and scheduled for removal.
Please read this for latest implementation of workqueue.
Related
I'm trying to compile a kernel module for Linux. I have the following files: testuio.c and Makefile. When I type make all I get the following errors:
$ make all
make -C /lib/modules/`uname -r`/build M=/srv/dev-disk-by-label-tboWolfRaid/home/alex/ma/source/kernel_modules/memory modules
make[1]: Entering directory '/usr/src/linux-headers-5.4.0-0.bpo.2-amd64'
CC [M] /srv/dev-disk-by-label-tboWolfRaid/home/alex/ma/source/kernel_modules/memory/testuio.o
In file included from /usr/include/unistd.h:25,
from /srv/dev-disk-by-label-tboWolfRaid/home/alex/ma/source/kernel_modules/memory/testuio.c:13:
/usr/include/features.h:424:12: fatal error: sys/cdefs.h: No such file or directory
# include <sys/cdefs.h>
^~~~~~~~~~~~~
compilation terminated.
make[3]: *** [/usr/src/linux-headers-5.4.0-0.bpo.2-common/scripts/Makefile.build:271: /srv/dev-disk-by-label-tboWolfRaid/home/alex/ma/source/kernel_modules/memory/testuio.o] Error 1
make[2]: *** [/usr/src/linux-headers-5.4.0-0.bpo.2-common/Makefile:1665: /srv/dev-disk-by-label-tboWolfRaid/home/alex/ma/source/kernel_modules/memory] Error 2
make[1]: *** [/usr/src/linux-headers-5.4.0-0.bpo.2-common/Makefile:179: sub-make] Error 2
make[1]: Leaving directory '/usr/src/linux-headers-5.4.0-0.bpo.2-amd64'
make: *** [Makefile:19: all] Error 2
This is correct, there is no such file under /usr/include/sys/. What I don't understand is why it would not find it under /usr/include/x86_64-linux-gnu/sys where there is such a file.
The following is part of gcc -xc -E -v - output:
#include <...> search starts here:
.
/usr/lib/gcc/x86_64-linux-gnu/8/include
/usr/local/include
/usr/lib/gcc/x86_64-linux-gnu/8/include-fixed
/usr/include/x86_64-linux-gnu
/usr/include
My Makefile contains:
# (1) consult https://www.kernel.org/doc/Documentation/kbuild/modules.txt to build a kbuild-compatible Makefile
# sections of special interest: 3.1 (shared makefile)
# (2) specifics about the Makefile under https://www.kernel.org/doc/Documentation/kbuild/makefiles.txt
# sections of special interest 3.7 (compilation flags)
ifneq ($(KERNELRELEASE),)
# kbuild part of the makefile (could pull this out into a file named Kbuild, this variant is more robust though)
obj-m += testuio.o
CFLAGS_testuio.o = -I/usr/include/x86_64-linux-gnu
ccflags-m = -I/usr/include/x86_64-linux-gnu # see (2) section 3.7
ccflags-y += ${ccflags-m}
#ccflags-y = -I/usr/include/aarch64-linux-gnu -I/usr/include # see (2) section 3.7
else
# "normal" makefile
KDIR ?= /lib/modules/`uname -r`/build # ?= sets KDIR only if it has no value already
all:
make -C $(KDIR) M=$(PWD) modules
install:
make -C $(KDIR) M=$(PWD) modules_install
clean:
make -C $(KDIR) M=$(PWD) clean
endif
For reference my testuio.c contains:
// In order for a device to be compatible with this UIO platform device driver
// it needs to use "generic-uio" in its compatible property
// This is a kernel driver.
#include <linux/module.h> // included for module_* macros
#include <linux/device.h> // included for devm_kzalloc
#include <linux/mman.h> // included for mmap
// #include <linux/stat.h> // included for fstat (for being able to read out of files)
#include <linux/platform_device.h> // included for struct platform_device
#include <linux/uio_driver.h> // included for struct uio_info
#include <unistd.h> // included for read and write syscalls
#include <fcntl.h> // included for file creation flags
#include <stdio.h> // included for FILE* type, fscanf
#define EOPENUIOFD 1
#define EMEMMAP 2
#define UIO_SIZE_FILE "/sys/class/uio/uio0/maps/map0/size"
MODULE_LICENSE("");
MODULE_AUTHOR("Alexander Pastor");
MODULE_VERSION("0.0.1");
// MODULE_DEVICE_TABLE(???);
typedef struct testuio_dev {
struct uio_info* info;
} testuio_dev;
// TODO: change s.t. interupts can be handled correctly
// HINT: might not be necessary tho
static int testuio_irq_handler(int irq, struct uio_info* info)
{
// if (IRQ is not caused by my hardware)
if (true)
return IRQ_NONE;
/* Disable interrupt */
// Perform some register access to silence the IRQ line
return IRQ_HANDLED;
}
static int testuio_probe(struct platform_device* pdev)
{
struct testuio_dev* dev;
struct resource* res;
int irq;
// collect handles and information from platform device
// devm_kzalloc => managed (free upon detaching device from system) kernel zero-initialized memory allocation
// gfp flags => get free page flags
dev = devm_kzalloc(&pdev->dev, (sizeof(struct testuio_dev)), GFP_KERNEL);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq = platform_get_irq(pdev, 0);
// basic uio info struct initialization (required!)
dev->info->name = "testuio";
dev->info->version = "0.0.1";
// memory region initialization
dev->info->mem[0].name = "dummy_mem";
dev->info->mem[0].addr = res->start;
dev->info->mem[0].size = resource_size(res);
dev->info->mem[0].memtype = UIO_MEM_PHYS;
// other memory types include:
// - UIO_MEM_LOGICAL allocated by kmalloc
// - UIO_MEM_VIRTUAL allocated by vmalloc
// interrupt initialization
dev->info->irq = irq;
dev->info->irq_flags = 0;
dev->info->handler = &testuio_irq_handler;
if(uio_register_device(&pdev->dev, info))
{
iounmap(dev->info->mem[0].internal_addr);
return -ENODEV;
} else {
return 0;
}
}
int main(int argc, char** argv)
{
int uio_fd; // UIO file descriptor
unsigned int uio_size; // memory size of UIO
FILE* size_fp; // pointer to the file containing memory size
void* base_address; // start address of mapped memory
uio_fd = open(/dev/uio, O_RDWR);
if(uio_fd == -1)
return EOPENUIOFD;
size_fp = fopen(UIO_SIZE_FILE, O_RDONLY);
fscanf(size_fp, "0x%08x", &uio_size); // 0x%08x expects unsigned int; %p expects void*
// Whenever the user space program reads or writes in the virtual address range
// it is accessing the device w/o the need for a system call. This improves performance.
base_address = mmap(NULL, // NULL => kernel chooses page-aligned address at which to create mapping
uio_size, // length of memory mapping
PROT_READ | PROT_WRITE, // flags: grant read + write access
MAP_SHARED_VALIDATE, // updates to mapping are visible to other processes
// (+validates given flags, available since Linux 4.15)
uio_fd,
0);
if (uio_fd == MAP_FAILED)
return EMEMMAP;
// --- BEGIN APPLICATION CODE
// ??? Is this even the right spot for the application code
// see also
// https://docplayer.net/37414164-Linux-user-space-device-drivers-john-linn-based-on-3-14-linux-kernel.html
// helpful: https://stackoverflow.com/questions/26259421/use-mmap-in-c-to-write-into-memory
// TODO: read in content from file as done in link above using fstat
int testvals[8] = {0xDEADBEEF, 7, 12, 13, 31, 42, -63, -65535}
memcpy(base_address, testvals, sizeof(testvals));
for(int i=0; i<8; i++)
{
printk(KERN_INFO "The value at address %p is %d",
base_address+i*sizeof(int),
(int)*(base_address+i*sizeof(int)));
}
//! interrupt stuff
// read() returns the number of interrupt events.
// It allows blocking and non-blocking modes with this being blocking mode
int pending = 0;
int reennable = 1;
read(uio_fd, (void*)&pending, sizeof(int));
//! device specific processing
// acking the interrupt in the device
write(uio_fd, (void*)&reenable, sizeof(int));
// --- END APPLICATON CODE
//! undo virtual address mapping
munmap(base_address, uio_size);
return 0;
}
You seem to be mixing up kernel and userspace stuff in your code. However all this is wrong:
CFLAGS_testuio.o = -I/usr/include/x86_64-linux-gnu
ccflags-m = -I/usr/include/x86_64-linux-gnu # see (2) section 3.7
ccflags-y += ${ccflags-m}
As you're stitching some user-space include paths to your kernel flags.
And also all these:
#include <unistd.h> // included for read and write syscalls
#include <fcntl.h> // included for file creation flags
#include <stdio.h> // included for FILE* type, fscanf
don't belong in a kernel module.The main function also has to go away.
My assumption is you need a kernel module and a userspace application to test it. Don't mix the two of them together. Keep these things separate.
I have a strange segmentation fault that doesn't exist when everything is in 1 .c file, but does exist when I put part of the code in a dynamically linked library and link it to a test file. The complete code for the working 1 .c file code is at the bottom, the complete code for the error system with 2 .c and 1 .h file come first.
Here is the error system:
example.h:
#include <stdio.h>
#include <stdlib.h>
typedef struct MYARRAY {
int len;
void* items[];
} MYARRAY;
MYARRAY *collection;
void
mypush(void* p);
example.c:
#include "example.h"
void
mypush(void* p) {
printf("Here %lu\n", sizeof collection);
puts("FOO");
int len = collection->len++;
puts("BAR");
collection->items[len] = p;
}
example2.c:
This is essentially a test file:
#include "example.h"
void
test_print() {
puts("Here1");
mypush("foo");
puts("Here2");
}
int
main() {
collection = malloc(sizeof *collection + (sizeof collection->items[0] * 1000));
collection->len = 0;
puts("Start");
test_print();
puts("Done");
return 0;
}
Makefile:
I link example to example2 here, and run:
example:
#clang -I . -dynamiclib \
-undefined dynamic_lookup \
-o example.dylib example.c
#clang example2.c example.dylib -o example2.o
#./example2.o
.PHONY: example
The output is:
$ make example
Start
Here1
Here 8
FOO
make: *** [example] Segmentation fault: 11
But it should show the full output of:
$ make example
Start
Here1
Here 8
FOO
BAR
Here2
Done
The weird thing is everything works if it is this system:
example.c:
#include <stdio.h>
#include <stdlib.h>
typedef struct MYARRAY {
int len;
void* items[];
} MYARRAY;
MYARRAY *collection;
void
mypush(void* p) {
printf("Here %lu\n", sizeof collection);
puts("FOO");
int len = collection->len++;
puts("BAR");
collection->items[len] = p;
}
void
test_print() {
puts("Here1");
mypush("foo");
puts("Here");
}
int
main() {
collection = malloc(sizeof *collection + (sizeof collection->items[0] * 1000));
collection->len = 0;
puts("ASF");
test_print();
return 0;
}
Makefile:
example:
#clang -o example example.c
#./example
.PHONY: example
Wondering why it's creating a segmentation fault when it is linked like this, and what I am doing wrong.
I have checked otool and with DYLD_PRINT_LIBRARIES=YES and it shows it is importing the dynamically linked libraries, but for some reason it's segmentation faulting when linked but works fine when it isn't linked.
Your problem is this, in example.h:
MYARRAY *collection;
Since both main.c and example.c include this file, you end up defining collection twice, which results in undefined behavior. You need to make sure you define each object only once. The details are relatively unimportant since anything can happen with undefined behavior, but what's probably happening is that main.c is allocating memory for one object, but the one example.c is using is still NULL. As mentioned in the comments, since you define collection in main.c your linker is able to build the executable without needing to look for that symbol in the dynamic library, so you don't get a link time warning about it being defined there too, and obviously there'd be no cause for a warning at the time you compile the library.
It works for you when you put everything in one file because obviously then you're not defining anything twice, anymore. The error itself is nothing to do with the fact you're using a dynamic library, although that may have made it harder to detect.
It would be better to define this in example.c and provide a constructor function, there's no need for main() to be able to access it directly. But if you must do this, then define it in example.c and just declare an extern identifier in the header file to tell main.c that the object is defined somewhere else.
I am newbee to linux kernel. Currently I want to have 2 module they can interact with each other. I've tried to call function2 from module2 in module1 by EXPORT_SYMBOL_GPL. When I 'insmod' module1 it tells me function2 is "unknown symbol" to module1. I did export function2 and add -DEXPORT_SYMTAB in Makefile. What else I miss? Any advice great appreciate.
Here's my hello samples
/* *************************************************************************************
* hello-1.c - The simplest kernel module.
*/
#include <linux/module.h> /* Needed by all modules */
#include <linux/kernel.h> /* Needed for KERN_INFO */
#include "hello2.h"
static int __init init_module1(void)
{
printk(KERN_INFO "Hello world 1.\n");
function2();
/*
* A non 0 return means init_module failed; module can't be loaded.
*/
return 0;
}
static void __exit cleanup_module1(void)
{
printk(KERN_INFO "Goodbye world 1.\n");
}
module_init(init_module1);
module_exit(cleanup_module1);
MODULE_DESCRIPTION("Hello1");
MODULE_LICENSE("GPL");
/* *************************************************************************************
* hello-2.c - The simplest kernel module.
*/
#include <linux/module.h> /* Needed by all modules */
#include <linux/kernel.h> /* Needed for KERN_INFO */
static void function2 (void)
{
printk(KERN_INFO "Function called in hello2.\n");
}
EXPORT_SYMBOL_GPL(function2);
static int __init init_module2(void)
{
printk(KERN_INFO "Hello world 2.\n");
/*
* A non 0 return means init_module failed; module can't be loaded.
*/
return 0;
}
static void __exit cleanup_module2(void)
{
printk(KERN_INFO "Goodbye world 2.\n");
}
module_init(init_module2);
module_exit(cleanup_module2);
MODULE_DESCRIPTION("Hello2");
MODULE_LICENSE("GPL");
/* *************************************************************************************
* hello-2.h - The simplest kernel module header
*/
extern void function2 (void);
################################################
# Makefile for hello2
PWD := $(shell pwd)
KVERSION := $(shell uname -r)
KDIR := /lib/modules/$(shell uname -r)/build
KERNEL_DIR := /usr/src/linux-headers-$(KVERSION)/
INSTALL_PATH := /lib/modules/$(shell uname -r)/extra
EXTRA_CFLAGS = -DEXPORT_SYMTAB
MODULE_NAME = hello2
obj-m := hello2.o
#.PHONY: all clean insert
.PHONY: all clean
all:
$(MAKE) -C $(KDIR) M=$(PWD) modules
clean:
$(MAKE) -C $(KDIR) M=$(PWD) clean
rm -rf *.o *.ko *.mod.* .c* .t*
insert:
$(MAKE) INSTALL_MOD_DIR=$(INSTALL_PATH) -C $(KDIR) M=$(PWD) modules_install
In hello-2.c you have:
static void function2 (void)
{
...
}
Please consider making it non-static:
void function2(void)
{
...
}
I found the solution from an old post:
insmod fails with "Unknown symbol in module" for a symbol defined in another module
Turns out 2 modules need to be built at the same time. I built they separately with 2 different Makefile.
I use the following module code to hooks syscall, (code credited to someone else, e.g., Linux Kernel: System call hooking example).
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/unistd.h>
#include <asm/semaphore.h>
#include <asm/cacheflush.h>
void **sys_call_table;
asmlinkage int (*original_call) (const char*, int, int);
asmlinkage int our_sys_open(const char* file, int flags, int mode)
{
printk(KERN_ALERT "A file was opened\n");
return original_call(file, flags, mode);
}
int set_page_rw(long unsigned int _addr)
{
struct page *pg;
pgprot_t prot;
pg = virt_to_page(_addr);
prot.pgprot = VM_READ | VM_WRITE;
return change_page_attr(pg, 1, prot);
}
int init_module()
{
// sys_call_table address in System.map
sys_call_table = (void*)0xffffffff804a1ba0;
original_call = sys_call_table[1024];
set_page_rw(sys_call_table);
sys_call_table[1024] = our_sys_open;
return 0;
}
void cleanup_module()
{
// Restore the original call
sys_call_table[1024] = original_call;
}
When insmod the compiled .ko file, terminal throws "Killed". When looking into 'cat /proc/modules' file, I get the Loading status.
my_module 10512 1 - Loading 0xffffffff882e7000 (P)
As expected, I can not rmmod this module, as it complains its in use. The system is rebooted to get a clean-slate status.
Later on, after commenting two code lines in the above source sys_call_table[1024] = our_sys_open; and sys_call_table[1024] = original_call;, it can insmod successfully. More interestingly, when uncommenting these two lines (change back to the original code), the compiled module can be insmod successfully. I dont quite understand why this happens? And is there any way to successfully compile the code and insmod it directly?
I did all this on Redhat with linux kernel 2.6.24.6.
I think you should take a look to the kprobes API, which is well documented in Documentation/krpobes.txt. It gives you the ability to install handler on every address (e.g. syscall entry) so that you can do what you want. Added bonus is that your code would be more portable.
If you're only interested in tracing those syscalls you can use the audit subsystem, coding your own userland daemon which will be able to receive events on a NETLINK socket from the audit kthread. libaudit provides a simple API to register/read events.
If you do have a good reason with not using kprobes/audit, I would suggest that you check that the value you are trying to write to is not above the page that you set writable. A quick calculation shows that:
offset_in_sys_call_table * sizeof(*sys_call_table) = 1024 * 8 = 8192
which is two pages after the one you set writable if you are using 4K pages.
I have a mixed C++/Objective-C project that uses AudioObjectGetPropertyDataSize to get the number of audio devices (such as USB headsets) plugged in. This API doesn't seem to work under certain conditions. For example, on 10.5 it will work but on 10.6 it won't detect when a new USB headset is plugged in.
I've pared down the problem to a small bit of code that reproduces the problem (it calls AudioObjectGetPropertyDataSize in a loop). The code will work on 10.6 (ie, it will detect when devices are plugged/unplugged) when its only linked against CoreAudio, but once you link against Foundation it will stop working.
I don't understand how linking to a framework can break code that otherwise works.
Here is the code (coreaudio-test.cpp):
#include <stdio.h>
#include <CoreAudio/AudioHardware.h>
int main(int argc, char **argv) {
printf("Press <enter> to refresh device list> \n");
while (1) {
getchar();
// get device count
UInt32 dataSize = 0;
AudioObjectPropertyAddress propertyAddress;
propertyAddress.mSelector = kAudioHardwarePropertyDevices;
propertyAddress.mScope = kAudioObjectPropertyScopeGlobal;
propertyAddress.mElement = kAudioObjectPropertyElementMaster;
OSStatus result =
AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &dataSize);
int count = -1;
if (result == noErr) {
count = dataSize / sizeof(AudioDeviceID);
}
printf("num devices= %d \n", count);
}
return 0;
}
And here is the Makefile:
LFLAGS= -framework CoreAudio
all: coreaudio-test coreaudio-test.broken
# create a test that works
coreaudio-test: coreaudio-test.cpp
g++ -o $# $^ $(LFLAGS)
# linking to foundation will break the test
coreaudio-test.broken: coreaudio-test.cpp
g++ -o $# $^ $(LFLAGS) -framework Foundation
Any thoughts on this bizarre behavior? (btw, I've also posted this question on the CoreAudio list.)
The CoreAudio List answered my question. We need to tell CoreAudio to allocate its own event-dispatching thread:
CFRunLoopRef theRunLoop = NULL;
AudioObjectPropertyAddress theAddress = { kAudioHardwarePropertyRunLoop, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
AudioObjectSetPropertyData(kAudioObjectSystemObject, &theAddress, 0, NULL, sizeof(CFRunLoopRef), &theRunLoop);
I suspect what's happening is that when the program is linked to Foundation, CoreAudio assumes the main thread is acting as an event dispatcher loop (very common since Objective-C is usually used for GUI programs). When not linking against Foundation, I guess it figures that it needs to allocate its own event thread.
Related behavior, which is like 9 years ago someone reported:
http://lists.apple.com/archives/coreaudio-api/2001/May/msg00021.html