Merge emailed fixes from Andrew Morton: "Bunch of fixes: - delayed IPC updates. I held back on this because of some possible outstanding bug reports, but they appear to have been addressed in later versions - A bunch of MAINTAINERS updates - Yet Another RTC driver. I'd held this back while a couple of little issues were being worked out. I'm expecting an intrusive-but-simple patchset from Joe Perches which splits up printk.c into kernel/printk/*. That will be a pig to maintain for two months so if it passes testing I'd like to get it upstream after a week or so." * emailed patches from Andrew Morton <akpm@linux-foundation.org>: (35 commits) printk: fix incorrect length from print_time() when seconds > 99999 drivers/rtc/rtc-vt8500.c: fix handling of data passed in struct rtc_time drivers/rtc/rtc-vt8500.c: correct handling of CR_24H bitfield rtc: add RTC driver for TPS6586x MAINTAINERS: fix drivers/staging/sm7xx/ MAINTAINERS: remove include/linux/of_pwm.h MAINTAINERS: remove arch/*/lib/perf_event*.c MAINTAINERS: remove drivers/mmc/host/imxmmc.* MAINTAINERS: fix Documentation/mei/ MAINTAINERS: remove arch/x86/platform/mrst/pmu.* MAINTAINERS: remove firmware/isci/ MAINTAINERS: fix drivers/ieee802154/ MAINTAINERS: fix .../plat-mxc/include/mach/imxfb.h MAINTAINERS: remove drivers/video/epson1355fb.c MAINTAINERS: fix drivers/media/usb/dvb-usb/cxusb* MAINTAINERS: adjust for UAPI MAINTAINERS: fix drivers/media/platform/atmel-isi.c MAINTAINERS: fix arch/arm/mach-at91/include/mach/at_hdmac.h MAINTAINERS: fix drivers/rtc/rtc-vt8500.c MAINTAINERS: remove arch/arm/plat-s5p/ ...tirimbino
commit
d0631c6e09
@ -0,0 +1,356 @@ |
||||
/*
|
||||
* rtc-tps6586x.c: RTC driver for TI PMIC TPS6586X |
||||
* |
||||
* Copyright (c) 2012, NVIDIA Corporation. |
||||
* |
||||
* Author: Laxman Dewangan <ldewangan@nvidia.com> |
||||
* |
||||
* This program is free software; you can redistribute it and/or |
||||
* modify it under the terms of the GNU General Public License as |
||||
* published by the Free Software Foundation version 2. |
||||
* |
||||
* This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, |
||||
* whether express or implied; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||||
* General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
||||
* 02111-1307, USA |
||||
*/ |
||||
|
||||
#include <linux/device.h> |
||||
#include <linux/err.h> |
||||
#include <linux/init.h> |
||||
#include <linux/kernel.h> |
||||
#include <linux/mfd/tps6586x.h> |
||||
#include <linux/module.h> |
||||
#include <linux/platform_device.h> |
||||
#include <linux/pm_runtime.h> |
||||
#include <linux/rtc.h> |
||||
#include <linux/slab.h> |
||||
|
||||
#define RTC_CTRL 0xc0 |
||||
#define POR_RESET_N BIT(7) |
||||
#define OSC_SRC_SEL BIT(6) |
||||
#define RTC_ENABLE BIT(5) /* enables alarm */ |
||||
#define RTC_BUF_ENABLE BIT(4) /* 32 KHz buffer enable */ |
||||
#define PRE_BYPASS BIT(3) /* 0=1KHz or 1=32KHz updates */ |
||||
#define CL_SEL_MASK (BIT(2)|BIT(1)) |
||||
#define CL_SEL_POS 1 |
||||
#define RTC_ALARM1_HI 0xc1 |
||||
#define RTC_COUNT4 0xc6 |
||||
|
||||
/* start a PMU RTC access by reading the register prior to the RTC_COUNT4 */ |
||||
#define RTC_COUNT4_DUMMYREAD 0xc5 |
||||
|
||||
/*only 14-bits width in second*/ |
||||
#define ALM1_VALID_RANGE_IN_SEC 0x3FFF |
||||
|
||||
#define TPS6586X_RTC_CL_SEL_1_5PF 0x0 |
||||
#define TPS6586X_RTC_CL_SEL_6_5PF 0x1 |
||||
#define TPS6586X_RTC_CL_SEL_7_5PF 0x2 |
||||
#define TPS6586X_RTC_CL_SEL_12_5PF 0x3 |
||||
|
||||
struct tps6586x_rtc { |
||||
struct device *dev; |
||||
struct rtc_device *rtc; |
||||
int irq; |
||||
bool irq_en; |
||||
unsigned long long epoch_start; |
||||
}; |
||||
|
||||
static inline struct device *to_tps6586x_dev(struct device *dev) |
||||
{ |
||||
return dev->parent; |
||||
} |
||||
|
||||
static int tps6586x_rtc_read_time(struct device *dev, struct rtc_time *tm) |
||||
{ |
||||
struct tps6586x_rtc *rtc = dev_get_drvdata(dev); |
||||
struct device *tps_dev = to_tps6586x_dev(dev); |
||||
unsigned long long ticks = 0; |
||||
unsigned long seconds; |
||||
u8 buff[6]; |
||||
int ret; |
||||
int i; |
||||
|
||||
ret = tps6586x_reads(tps_dev, RTC_COUNT4_DUMMYREAD, sizeof(buff), buff); |
||||
if (ret < 0) { |
||||
dev_err(dev, "read counter failed with err %d\n", ret); |
||||
return ret; |
||||
} |
||||
|
||||
for (i = 1; i < sizeof(buff); i++) { |
||||
ticks <<= 8; |
||||
ticks |= buff[i]; |
||||
} |
||||
|
||||
seconds = ticks >> 10; |
||||
seconds += rtc->epoch_start; |
||||
rtc_time_to_tm(seconds, tm); |
||||
return rtc_valid_tm(tm); |
||||
} |
||||
|
||||
static int tps6586x_rtc_set_time(struct device *dev, struct rtc_time *tm) |
||||
{ |
||||
struct tps6586x_rtc *rtc = dev_get_drvdata(dev); |
||||
struct device *tps_dev = to_tps6586x_dev(dev); |
||||
unsigned long long ticks; |
||||
unsigned long seconds; |
||||
u8 buff[5]; |
||||
int ret; |
||||
|
||||
rtc_tm_to_time(tm, &seconds); |
||||
if (seconds < rtc->epoch_start) { |
||||
dev_err(dev, "requested time unsupported\n"); |
||||
return -EINVAL; |
||||
} |
||||
seconds -= rtc->epoch_start; |
||||
|
||||
ticks = (unsigned long long)seconds << 10; |
||||
buff[0] = (ticks >> 32) & 0xff; |
||||
buff[1] = (ticks >> 24) & 0xff; |
||||
buff[2] = (ticks >> 16) & 0xff; |
||||
buff[3] = (ticks >> 8) & 0xff; |
||||
buff[4] = ticks & 0xff; |
||||
|
||||
/* Disable RTC before changing time */ |
||||
ret = tps6586x_clr_bits(tps_dev, RTC_CTRL, RTC_ENABLE); |
||||
if (ret < 0) { |
||||
dev_err(dev, "failed to clear RTC_ENABLE\n"); |
||||
return ret; |
||||
} |
||||
|
||||
ret = tps6586x_writes(tps_dev, RTC_COUNT4, sizeof(buff), buff); |
||||
if (ret < 0) { |
||||
dev_err(dev, "failed to program new time\n"); |
||||
return ret; |
||||
} |
||||
|
||||
/* Enable RTC */ |
||||
ret = tps6586x_set_bits(tps_dev, RTC_CTRL, RTC_ENABLE); |
||||
if (ret < 0) { |
||||
dev_err(dev, "failed to set RTC_ENABLE\n"); |
||||
return ret; |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
static int tps6586x_rtc_alarm_irq_enable(struct device *dev, |
||||
unsigned int enabled) |
||||
{ |
||||
struct tps6586x_rtc *rtc = dev_get_drvdata(dev); |
||||
|
||||
if (enabled && !rtc->irq_en) { |
||||
enable_irq(rtc->irq); |
||||
rtc->irq_en = true; |
||||
} else if (!enabled && rtc->irq_en) { |
||||
disable_irq(rtc->irq); |
||||
rtc->irq_en = false; |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
static int tps6586x_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) |
||||
{ |
||||
struct tps6586x_rtc *rtc = dev_get_drvdata(dev); |
||||
struct device *tps_dev = to_tps6586x_dev(dev); |
||||
unsigned long seconds; |
||||
unsigned long ticks; |
||||
unsigned long rtc_current_time; |
||||
unsigned long long rticks = 0; |
||||
u8 buff[3]; |
||||
u8 rbuff[6]; |
||||
int ret; |
||||
int i; |
||||
|
||||
rtc_tm_to_time(&alrm->time, &seconds); |
||||
|
||||
if (alrm->enabled && (seconds < rtc->epoch_start)) { |
||||
dev_err(dev, "can't set alarm to requested time\n"); |
||||
return -EINVAL; |
||||
} |
||||
|
||||
ret = tps6586x_rtc_alarm_irq_enable(dev, alrm->enabled); |
||||
if (ret < 0) { |
||||
dev_err(dev, "can't set alarm irq, err %d\n", ret); |
||||
return ret; |
||||
} |
||||
|
||||
seconds -= rtc->epoch_start; |
||||
ret = tps6586x_reads(tps_dev, RTC_COUNT4_DUMMYREAD, |
||||
sizeof(rbuff), rbuff); |
||||
if (ret < 0) { |
||||
dev_err(dev, "read counter failed with err %d\n", ret); |
||||
return ret; |
||||
} |
||||
|
||||
for (i = 1; i < sizeof(rbuff); i++) { |
||||
rticks <<= 8; |
||||
rticks |= rbuff[i]; |
||||
} |
||||
|
||||
rtc_current_time = rticks >> 10; |
||||
if ((seconds - rtc_current_time) > ALM1_VALID_RANGE_IN_SEC) |
||||
seconds = rtc_current_time - 1; |
||||
|
||||
ticks = (unsigned long long)seconds << 10; |
||||
buff[0] = (ticks >> 16) & 0xff; |
||||
buff[1] = (ticks >> 8) & 0xff; |
||||
buff[2] = ticks & 0xff; |
||||
|
||||
ret = tps6586x_writes(tps_dev, RTC_ALARM1_HI, sizeof(buff), buff); |
||||
if (ret) |
||||
dev_err(dev, "programming alarm failed with err %d\n", ret); |
||||
|
||||
return ret; |
||||
} |
||||
|
||||
static int tps6586x_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) |
||||
{ |
||||
struct tps6586x_rtc *rtc = dev_get_drvdata(dev); |
||||
struct device *tps_dev = to_tps6586x_dev(dev); |
||||
unsigned long ticks; |
||||
unsigned long seconds; |
||||
u8 buff[3]; |
||||
int ret; |
||||
|
||||
ret = tps6586x_reads(tps_dev, RTC_ALARM1_HI, sizeof(buff), buff); |
||||
if (ret) { |
||||
dev_err(dev, "read RTC_ALARM1_HI failed with err %d\n", ret); |
||||
return ret; |
||||
} |
||||
|
||||
ticks = (buff[0] << 16) | (buff[1] << 8) | buff[2]; |
||||
seconds = ticks >> 10; |
||||
seconds += rtc->epoch_start; |
||||
|
||||
rtc_time_to_tm(seconds, &alrm->time); |
||||
return 0; |
||||
} |
||||
|
||||
static const struct rtc_class_ops tps6586x_rtc_ops = { |
||||
.read_time = tps6586x_rtc_read_time, |
||||
.set_time = tps6586x_rtc_set_time, |
||||
.set_alarm = tps6586x_rtc_set_alarm, |
||||
.read_alarm = tps6586x_rtc_read_alarm, |
||||
.alarm_irq_enable = tps6586x_rtc_alarm_irq_enable, |
||||
}; |
||||
|
||||
static irqreturn_t tps6586x_rtc_irq(int irq, void *data) |
||||
{ |
||||
struct tps6586x_rtc *rtc = data; |
||||
|
||||
rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_AF); |
||||
return IRQ_HANDLED; |
||||
} |
||||
|
||||
static int tps6586x_rtc_probe(struct platform_device *pdev) |
||||
{ |
||||
struct device *tps_dev = to_tps6586x_dev(&pdev->dev); |
||||
struct tps6586x_rtc *rtc; |
||||
int ret; |
||||
|
||||
rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL); |
||||
if (!rtc) |
||||
return -ENOMEM; |
||||
|
||||
rtc->dev = &pdev->dev; |
||||
rtc->irq = platform_get_irq(pdev, 0); |
||||
|
||||
/* Set epoch start as 00:00:00:01:01:2009 */ |
||||
rtc->epoch_start = mktime(2009, 1, 1, 0, 0, 0); |
||||
|
||||
/* 1 kHz tick mode, enable tick counting */ |
||||
ret = tps6586x_update(tps_dev, RTC_CTRL, |
||||
RTC_ENABLE | OSC_SRC_SEL | |
||||
((TPS6586X_RTC_CL_SEL_1_5PF << CL_SEL_POS) & CL_SEL_MASK), |
||||
RTC_ENABLE | OSC_SRC_SEL | PRE_BYPASS | CL_SEL_MASK); |
||||
if (ret < 0) { |
||||
dev_err(&pdev->dev, "unable to start counter\n"); |
||||
return ret; |
||||
} |
||||
|
||||
platform_set_drvdata(pdev, rtc); |
||||
rtc->rtc = rtc_device_register(dev_name(&pdev->dev), &pdev->dev, |
||||
&tps6586x_rtc_ops, THIS_MODULE); |
||||
if (IS_ERR(rtc->rtc)) { |
||||
ret = PTR_ERR(rtc->rtc); |
||||
dev_err(&pdev->dev, "RTC device register: ret %d\n", ret); |
||||
goto fail_rtc_register; |
||||
} |
||||
|
||||
ret = request_threaded_irq(rtc->irq, NULL, tps6586x_rtc_irq, |
||||
IRQF_ONESHOT | IRQF_EARLY_RESUME, |
||||
dev_name(&pdev->dev), rtc); |
||||
if (ret < 0) { |
||||
dev_err(&pdev->dev, "request IRQ(%d) failed with ret %d\n", |
||||
rtc->irq, ret); |
||||
goto fail_req_irq; |
||||
} |
||||
disable_irq(rtc->irq); |
||||
device_set_wakeup_capable(&pdev->dev, 1); |
||||
return 0; |
||||
|
||||
fail_req_irq: |
||||
rtc_device_unregister(rtc->rtc); |
||||
|
||||
fail_rtc_register: |
||||
tps6586x_update(tps_dev, RTC_CTRL, 0, |
||||
RTC_ENABLE | OSC_SRC_SEL | PRE_BYPASS | CL_SEL_MASK); |
||||
return ret; |
||||
}; |
||||
|
||||
static int tps6586x_rtc_remove(struct platform_device *pdev) |
||||
{ |
||||
struct tps6586x_rtc *rtc = platform_get_drvdata(pdev); |
||||
struct device *tps_dev = to_tps6586x_dev(&pdev->dev); |
||||
|
||||
tps6586x_update(tps_dev, RTC_CTRL, 0, |
||||
RTC_ENABLE | OSC_SRC_SEL | PRE_BYPASS | CL_SEL_MASK); |
||||
rtc_device_unregister(rtc->rtc); |
||||
free_irq(rtc->irq, rtc); |
||||
return 0; |
||||
} |
||||
|
||||
#ifdef CONFIG_PM_SLEEP |
||||
static int tps6586x_rtc_suspend(struct device *dev) |
||||
{ |
||||
struct tps6586x_rtc *rtc = dev_get_drvdata(dev); |
||||
|
||||
if (device_may_wakeup(dev)) |
||||
enable_irq_wake(rtc->irq); |
||||
return 0; |
||||
} |
||||
|
||||
static int tps6586x_rtc_resume(struct device *dev) |
||||
{ |
||||
struct tps6586x_rtc *rtc = dev_get_drvdata(dev); |
||||
|
||||
if (device_may_wakeup(dev)) |
||||
disable_irq_wake(rtc->irq); |
||||
return 0; |
||||
} |
||||
#endif |
||||
|
||||
static const struct dev_pm_ops tps6586x_pm_ops = { |
||||
SET_SYSTEM_SLEEP_PM_OPS(tps6586x_rtc_suspend, tps6586x_rtc_resume) |
||||
}; |
||||
|
||||
static struct platform_driver tps6586x_rtc_driver = { |
||||
.driver = { |
||||
.name = "tps6586x-rtc", |
||||
.owner = THIS_MODULE, |
||||
.pm = &tps6586x_pm_ops, |
||||
}, |
||||
.probe = tps6586x_rtc_probe, |
||||
.remove = tps6586x_rtc_remove, |
||||
}; |
||||
module_platform_driver(tps6586x_rtc_driver); |
||||
|
||||
MODULE_ALIAS("platform:rtc-tps6586x"); |
||||
MODULE_DESCRIPTION("TI TPS6586x RTC driver"); |
||||
MODULE_AUTHOR("Laxman dewangan <ldewangan@nvidia.com>"); |
||||
MODULE_LICENSE("GPL v2"); |
@ -0,0 +1,25 @@ |
||||
uname_M := $(shell uname -m 2>/dev/null || echo not)
|
||||
ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/)
|
||||
ifeq ($(ARCH),i386) |
||||
ARCH := X86
|
||||
CFLAGS := -DCONFIG_X86_32 -D__i386__
|
||||
endif |
||||
ifeq ($(ARCH),x86_64) |
||||
ARCH := X86
|
||||
CFLAGS := -DCONFIG_X86_64 -D__x86_64__
|
||||
endif |
||||
|
||||
CFLAGS += -I../../../../usr/include/
|
||||
|
||||
all: |
||||
ifeq ($(ARCH),X86) |
||||
gcc $(CFLAGS) msgque.c -o msgque_test
|
||||
else |
||||
echo "Not an x86 target, can't build msgque selftest"
|
||||
endif |
||||
|
||||
run_tests: all |
||||
./msgque_test
|
||||
|
||||
clean: |
||||
rm -fr ./msgque_test
|
@ -0,0 +1,246 @@ |
||||
#include <stdlib.h> |
||||
#include <stdio.h> |
||||
#include <string.h> |
||||
#include <errno.h> |
||||
#include <linux/msg.h> |
||||
#include <fcntl.h> |
||||
|
||||
#define MAX_MSG_SIZE 32 |
||||
|
||||
struct msg1 { |
||||
int msize; |
||||
long mtype; |
||||
char mtext[MAX_MSG_SIZE]; |
||||
}; |
||||
|
||||
#define TEST_STRING "Test sysv5 msg" |
||||
#define MSG_TYPE 1 |
||||
|
||||
#define ANOTHER_TEST_STRING "Yet another test sysv5 msg" |
||||
#define ANOTHER_MSG_TYPE 26538 |
||||
|
||||
struct msgque_data { |
||||
key_t key; |
||||
int msq_id; |
||||
int qbytes; |
||||
int qnum; |
||||
int mode; |
||||
struct msg1 *messages; |
||||
}; |
||||
|
||||
int restore_queue(struct msgque_data *msgque) |
||||
{ |
||||
int fd, ret, id, i; |
||||
char buf[32]; |
||||
|
||||
fd = open("/proc/sys/kernel/msg_next_id", O_WRONLY); |
||||
if (fd == -1) { |
||||
printf("Failed to open /proc/sys/kernel/msg_next_id\n"); |
||||
return -errno; |
||||
} |
||||
sprintf(buf, "%d", msgque->msq_id); |
||||
|
||||
ret = write(fd, buf, strlen(buf)); |
||||
if (ret != strlen(buf)) { |
||||
printf("Failed to write to /proc/sys/kernel/msg_next_id\n"); |
||||
return -errno; |
||||
} |
||||
|
||||
id = msgget(msgque->key, msgque->mode | IPC_CREAT | IPC_EXCL); |
||||
if (id == -1) { |
||||
printf("Failed to create queue\n"); |
||||
return -errno; |
||||
} |
||||
|
||||
if (id != msgque->msq_id) { |
||||
printf("Restored queue has wrong id (%d instead of %d)\n", |
||||
id, msgque->msq_id); |
||||
ret = -EFAULT; |
||||
goto destroy; |
||||
} |
||||
|
||||
for (i = 0; i < msgque->qnum; i++) { |
||||
if (msgsnd(msgque->msq_id, &msgque->messages[i].mtype, |
||||
msgque->messages[i].msize, IPC_NOWAIT) != 0) { |
||||
printf("msgsnd failed (%m)\n"); |
||||
ret = -errno; |
||||
goto destroy; |
||||
}; |
||||
} |
||||
return 0; |
||||
|
||||
destroy: |
||||
if (msgctl(id, IPC_RMID, 0)) |
||||
printf("Failed to destroy queue: %d\n", -errno); |
||||
return ret; |
||||
} |
||||
|
||||
int check_and_destroy_queue(struct msgque_data *msgque) |
||||
{ |
||||
struct msg1 message; |
||||
int cnt = 0, ret; |
||||
|
||||
while (1) { |
||||
ret = msgrcv(msgque->msq_id, &message.mtype, MAX_MSG_SIZE, |
||||
0, IPC_NOWAIT); |
||||
if (ret < 0) { |
||||
if (errno == ENOMSG) |
||||
break; |
||||
printf("Failed to read IPC message: %m\n"); |
||||
ret = -errno; |
||||
goto err; |
||||
} |
||||
if (ret != msgque->messages[cnt].msize) { |
||||
printf("Wrong message size: %d (expected %d)\n", ret, |
||||
msgque->messages[cnt].msize); |
||||
ret = -EINVAL; |
||||
goto err; |
||||
} |
||||
if (message.mtype != msgque->messages[cnt].mtype) { |
||||
printf("Wrong message type\n"); |
||||
ret = -EINVAL; |
||||
goto err; |
||||
} |
||||
if (memcmp(message.mtext, msgque->messages[cnt].mtext, ret)) { |
||||
printf("Wrong message content\n"); |
||||
ret = -EINVAL; |
||||
goto err; |
||||
} |
||||
cnt++; |
||||
} |
||||
|
||||
if (cnt != msgque->qnum) { |
||||
printf("Wrong message number\n"); |
||||
ret = -EINVAL; |
||||
goto err; |
||||
} |
||||
|
||||
ret = 0; |
||||
err: |
||||
if (msgctl(msgque->msq_id, IPC_RMID, 0)) { |
||||
printf("Failed to destroy queue: %d\n", -errno); |
||||
return -errno; |
||||
} |
||||
return ret; |
||||
} |
||||
|
||||
int dump_queue(struct msgque_data *msgque) |
||||
{ |
||||
struct msqid64_ds ds; |
||||
int kern_id; |
||||
int i, ret; |
||||
|
||||
for (kern_id = 0; kern_id < 256; kern_id++) { |
||||
ret = msgctl(kern_id, MSG_STAT, &ds); |
||||
if (ret < 0) { |
||||
if (errno == -EINVAL) |
||||
continue; |
||||
printf("Failed to get stats for IPC queue with id %d\n", |
||||
kern_id); |
||||
return -errno; |
||||
} |
||||
|
||||
if (ret == msgque->msq_id) |
||||
break; |
||||
} |
||||
|
||||
msgque->messages = malloc(sizeof(struct msg1) * ds.msg_qnum); |
||||
if (msgque->messages == NULL) { |
||||
printf("Failed to get stats for IPC queue\n"); |
||||
return -ENOMEM; |
||||
} |
||||
|
||||
msgque->qnum = ds.msg_qnum; |
||||
msgque->mode = ds.msg_perm.mode; |
||||
msgque->qbytes = ds.msg_qbytes; |
||||
|
||||
for (i = 0; i < msgque->qnum; i++) { |
||||
ret = msgrcv(msgque->msq_id, &msgque->messages[i].mtype, |
||||
MAX_MSG_SIZE, i, IPC_NOWAIT | MSG_COPY); |
||||
if (ret < 0) { |
||||
printf("Failed to copy IPC message: %m (%d)\n", errno); |
||||
return -errno; |
||||
} |
||||
msgque->messages[i].msize = ret; |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
int fill_msgque(struct msgque_data *msgque) |
||||
{ |
||||
struct msg1 msgbuf; |
||||
|
||||
msgbuf.mtype = MSG_TYPE; |
||||
memcpy(msgbuf.mtext, TEST_STRING, sizeof(TEST_STRING)); |
||||
if (msgsnd(msgque->msq_id, &msgbuf.mtype, sizeof(TEST_STRING), |
||||
IPC_NOWAIT) != 0) { |
||||
printf("First message send failed (%m)\n"); |
||||
return -errno; |
||||
}; |
||||
|
||||
msgbuf.mtype = ANOTHER_MSG_TYPE; |
||||
memcpy(msgbuf.mtext, ANOTHER_TEST_STRING, sizeof(ANOTHER_TEST_STRING)); |
||||
if (msgsnd(msgque->msq_id, &msgbuf.mtype, sizeof(ANOTHER_TEST_STRING), |
||||
IPC_NOWAIT) != 0) { |
||||
printf("Second message send failed (%m)\n"); |
||||
return -errno; |
||||
}; |
||||
return 0; |
||||
} |
||||
|
||||
int main(int argc, char **argv) |
||||
{ |
||||
int msg, pid, err; |
||||
struct msgque_data msgque; |
||||
|
||||
msgque.key = ftok(argv[0], 822155650); |
||||
if (msgque.key == -1) { |
||||
printf("Can't make key\n"); |
||||
return -errno; |
||||
} |
||||
|
||||
msgque.msq_id = msgget(msgque.key, IPC_CREAT | IPC_EXCL | 0666); |
||||
if (msgque.msq_id == -1) { |
||||
printf("Can't create queue\n"); |
||||
goto err_out; |
||||
} |
||||
|
||||
err = fill_msgque(&msgque); |
||||
if (err) { |
||||
printf("Failed to fill queue\n"); |
||||
goto err_destroy; |
||||
} |
||||
|
||||
err = dump_queue(&msgque); |
||||
if (err) { |
||||
printf("Failed to dump queue\n"); |
||||
goto err_destroy; |
||||
} |
||||
|
||||
err = check_and_destroy_queue(&msgque); |
||||
if (err) { |
||||
printf("Failed to check and destroy queue\n"); |
||||
goto err_out; |
||||
} |
||||
|
||||
err = restore_queue(&msgque); |
||||
if (err) { |
||||
printf("Failed to restore queue\n"); |
||||
goto err_destroy; |
||||
} |
||||
|
||||
err = check_and_destroy_queue(&msgque); |
||||
if (err) { |
||||
printf("Failed to test queue\n"); |
||||
goto err_out; |
||||
} |
||||
return 0; |
||||
|
||||
err_destroy: |
||||
if (msgctl(msgque.msq_id, IPC_RMID, 0)) { |
||||
printf("Failed to destroy queue: %d\n", -errno); |
||||
return -errno; |
||||
} |
||||
err_out: |
||||
return err; |
||||
} |
Loading…
Reference in new issue