Getting current information
Get current task with:
#include <kern/task.h>
task_t cur_task = current_task();
Get current thread with:
#include <kern/thread.h>
thread_t cur_thread = current_thread();
Kernel memory allocation
Use #include <libkern/OSMalloc.h> in your source code before all other code below.
First you need to create a tag allocation:
OSMallocTag gMallocTag = OSMalloc_Tagalloc("allocation.tag.name", OSMT_DEFAULT);
When you finish you will have to release it via:
OSMalloc_Tagfree(gMallocTag);
Actual memory allocations:
void *kernel_new_ptr = OSMalloc((uint32_t)size, gMallocTag);
Actual memory freeing:
OSFree(kernel_new_ptr, (uint32_t)size, gMallocTag);
The annoying part here is that you must keep the size of your allocations somewhere
If you are using IOKit extension you can use this instead of allocating a malloc tag:
void *iokit_new_ptr = IOMalloc(size);
/* using iokit_new_ptr */
IOFree(iokit_new_ptr, size);
Or simply call malloc itself:
void * ptr = _MALLOC(size, 1, M_ZERO);
/* free the ptr */
_FREE(ptr, M_ZERO);
Semaphores
Use #include <mach/mach_types.h> in your source code before the code below.
Declare a sempahore:
semaphore_port_t sem;
Create a semaphore:
if (semaphore_create(current_task(), &sem, SYNC_POLICY_FIFO, 0) != KERN_SUCCESS)
{
/* handle error in creation */
}
- Note that the scheduling policy (of releases threads) can be changed from
SYNC_POLICY_FIFOtoSYNC_POLICY_FIXED_PRIORITY,SYNC_POLICY_LIFOandSYNC_POLICY_ORDERMASK
Wait on a sempahore:
semaphore_wait(sem);
Signal and release one waiting thread:
semaphore_signal(sem);
Signal and release all waiting threads:
semaphore_signal_all(sem);
Destroy the semaphore:
semaphore_destroy(current_task(), &sem);
- Note that all waiting threads are released
Spinlocks
Mutex
Declare the needed lock group attributes, lock group and lock attribute variables:
lck_grp_t *lock_grp;
Allocate the lock group:
lock_grp = lck_grp_alloc_init("lock_group_name", LCK_GRP_ATTR_NULL);
Declare the lock itself:
lck_mtx_t * lock = lck_mtx_alloc_init(lock_grp, LCK_ATTR_NULL);
Lock the mutex:
lck_mtx_lock(lock);
Unlock the mutex:
lck_mtx_unlock(lock);
Destroy the mutex:
lck_mtx_destroy(lock);
Free the mutex:
lck_mtx_free(lock, lock_grp);
Sleep on event:
lck_mtx_sleep(lock, LCK_SLEEP_DEFAULT, event, THREAD_INTERRUPTIBLE);
the sleep action can be either:
LCK_SLEEP_DEFAULTwhich release the lock while waiting for the event, then reclaimLCK_SLEEP_UNLOCKwhich release the lock and return unheldLCK_SLEEP_SHAREDwhich reclaim the lock in shared mode (RW only)LCK_SLEEP_EXCLUSIVEwhich reclaim the lock in exclusive mode (RW only)LCK_SLEEP_SPINwhich reclaim the lock in spin mode (mutex only)
the interrupt action can be either:
THREAD_UNINTwhich is not interruptableTHREAD_INTERRUPTIBLEwhich is interruptable but not restableTHREAD_ABORTSAFEwhich can be aborted safely
Sleeping with msleep():
{% highlight c++ %}
void some_data = / data you are waiting on */ dummyptr;
struct timespec ts = {0}; ts.tv_sec = 0; ts.tv_nsec = 10;
msleep(some_data, lock, 0, “sleep_on_some_data”, &ts); {% endhighlight %}
Obtain kernel version
include #include <libkern/version.h> and use the variables described there:
version_major, version_minor, version_variant, version_revision, version_stage, version_prerelease_level, ostype, osrelease, osbuilder
And as a complete string of everything: version
Read from file
{% highlight c++ %} #include <sys/vnode.h> vnode_t vnode = NULLVP;
if (vnode_lookup("/file/path", 0, &vnode, vfs_context_current()))
{
/* handle the error */
}
else
{
int err = KERN_SUCCESS;
offset_t offset = 0;
user_size_t size = 1024;
void *read_buffer = _MALLOC(size, 1, M_ZERO);
uio_t uio = uio_create(1, offset, UIO_SYSSPACE, UIO_READ);
if (uio == NULL)
{
/* handle the error */
}
err = uio_addiov(uio, CAST_USER_ADDR_T(read_buffer), size);
if (err)
{
/* handle the error */
}
err = VNOP_READ(vnode, uio, 0, vfs_context_current());
if (err)
{
/* handle the error */
}
else if (uio_resid(uio))
{
/* handle the error */
}
uio_free(uio);
vnode_put(vnode);
}
{% endhighlight %}